← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/AI-fixes into lp:widelands

 

hessenfarmer has proposed merging lp:~widelands-dev/widelands/AI-fixes into lp:widelands.

Commit message:
!!Important!!
!!fri03 scenario needs to be removed from this branch before merging!!
!!it was only added for testing!!

This fixes improves some behavior in AI performance 
Ai is now able to adopt to scenarios to certain extend


Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1827209 in widelands: "barbarian barracks in basic economy"
  https://bugs.launchpad.net/widelands/+bug/1827209
  Bug #1827223 in widelands: "AI does not expand to unguarded enemy land"
  https://bugs.launchpad.net/widelands/+bug/1827223
  Bug #1827279 in widelands: "AI stocklevel not taken into account for building neededness"
  https://bugs.launchpad.net/widelands/+bug/1827279

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/AI-fixes/+merge/367309

Following things changed:
1. barbarian barracks no longer part of basic economy
2. AI expands to low guarded enemy territory 
3. AI builds more economy buildings based on neededness and preciousness od wares
4. AI is less agressive in dismantling
5. added more decisions to genetics either in build and dismantle loops
6. forced second carrier for frisians, barbarians, empire (can be reverted as soon as AI is building them properly)

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/AI-fixes into lp:widelands.
=== modified file 'data/ai/ai_input_1.wai'
--- data/ai/ai_input_1.wai	2018-11-09 07:50:37 +0000
+++ data/ai/ai_input_1.wai	2019-05-11 21:13:40 +0000
@@ -166,7 +166,7 @@
 161="79"
 162="-56"
 163="-41"
-164="0"
+164="55"
 165="-63"
 166="8"
 167="-72"

=== modified file 'data/ai/ai_input_2.wai'
--- data/ai/ai_input_2.wai	2018-11-09 07:50:37 +0000
+++ data/ai/ai_input_2.wai	2019-05-11 21:13:40 +0000
@@ -166,7 +166,7 @@
 161="79"
 162="-56"
 163="-41"
-164="0"
+164="55"
 165="-63"
 166="8"
 167="-72"

=== modified file 'data/ai/ai_input_3.wai'
--- data/ai/ai_input_3.wai	2018-11-09 07:50:37 +0000
+++ data/ai/ai_input_3.wai	2019-05-11 21:13:40 +0000
@@ -166,7 +166,7 @@
 161="79"
 162="-56"
 163="-41"
-164="0"
+164="55"
 165="-63"
 166="8"
 167="-72"

=== modified file 'data/ai/ai_input_4.wai'
--- data/ai/ai_input_4.wai	2018-11-09 07:50:37 +0000
+++ data/ai/ai_input_4.wai	2019-05-11 21:13:40 +0000
@@ -166,7 +166,7 @@
 161="79"
 162="-56"
 163="-41"
-164="0"
+164="55"
 165="-63"
 166="8"
 167="-72"

=== modified file 'data/campaigns/campaigns.lua'
--- data/campaigns/campaigns.lua	2018-12-13 23:32:55 +0000
+++ data/campaigns/campaigns.lua	2019-05-11 21:13:40 +0000
@@ -120,6 +120,7 @@
          scenarios = {
             "fri01.wmf",
             "fri02.wmf",
+            "fri03.wmf",
             "dummy.wmf"
          }
       }

=== added directory 'data/campaigns/fri03.wmf'
=== added directory 'data/campaigns/fri03.wmf/binary'
=== added file 'data/campaigns/fri03.wmf/binary/heights'
Binary files data/campaigns/fri03.wmf/binary/heights	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/binary/heights	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/binary/mapobjects'
Binary files data/campaigns/fri03.wmf/binary/mapobjects	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/binary/mapobjects	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/binary/resource'
Binary files data/campaigns/fri03.wmf/binary/resource	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/binary/resource	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/binary/terrain'
Binary files data/campaigns/fri03.wmf/binary/terrain	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/binary/terrain	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/elemental'
--- data/campaigns/fri03.wmf/elemental	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/elemental	2019-05-11 21:13:40 +0000
@@ -0,0 +1,13 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+packet_version="1"
+map_w="400"
+map_h="272"
+nr_players="4"
+name=_"Frisian Carribbean"
+author="Nordfriese"
+descr=_"Reebaud and his tribe are living happily in the North. Meanwhile, the countries they have left behind are all but peaceful…"
+hint=_"The setting of this scenario is partly grounded in history, partly in literature, and partly fictional."
+background="campaigns/fri03.wmf/pics/background.jpg"
+tags="unbalanced"

=== added file 'data/campaigns/fri03.wmf/objective'
--- data/campaigns/fri03.wmf/objective	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/objective	2019-05-11 21:13:40 +0000
@@ -0,0 +1,4 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+packet_version="2"

=== added directory 'data/campaigns/fri03.wmf/pics'
=== added file 'data/campaigns/fri03.wmf/pics/atterdag.png'
Binary files data/campaigns/fri03.wmf/pics/atterdag.png	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/pics/atterdag.png	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/pics/background.jpg'
Binary files data/campaigns/fri03.wmf/pics/background.jpg	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/pics/background.jpg	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/pics/claus.png'
Binary files data/campaigns/fri03.wmf/pics/claus.png	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/pics/claus.png	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/pics/henneke.png'
Binary files data/campaigns/fri03.wmf/pics/henneke.png	1970-01-01 00:00:00 +0000 and data/campaigns/fri03.wmf/pics/henneke.png	2019-05-11 21:13:40 +0000 differ
=== added file 'data/campaigns/fri03.wmf/player_names'
--- data/campaigns/fri03.wmf/player_names	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/player_names	2019-05-11 21:13:40 +0000
@@ -0,0 +1,28 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+packet_version="2"
+
+[player_1]
+name="Claus Lembeck"
+tribe="frisians"
+ai=
+closeable="false"
+
+[player_2]
+name="Waldemar Atterdag"
+tribe="empire"
+ai="normal"
+closeable="false"
+
+[player_3]
+name="Henneke Lembeck"
+tribe="frisians"
+ai="normal"
+closeable="false"
+
+[player_4]
+name="Hans Ravenstrupp"
+tribe="barbarians"
+ai="normal"
+closeable="false"

=== added file 'data/campaigns/fri03.wmf/player_position'
--- data/campaigns/fri03.wmf/player_position	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/player_position	2019-05-11 21:13:40 +0000
@@ -0,0 +1,8 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+packet_version="2"
+player_1="130 180"
+player_2="115 35"
+player_3="346 211"
+player_4="384 135"

=== added file 'data/campaigns/fri03.wmf/port_spaces'
--- data/campaigns/fri03.wmf/port_spaces	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/port_spaces	2019-05-11 21:13:40 +0000
@@ -0,0 +1,7 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+packet_version="1"
+number_of_port_spaces="0"
+
+[port_spaces]

=== added directory 'data/campaigns/fri03.wmf/scripting'
=== added file 'data/campaigns/fri03.wmf/scripting/init.lua'
--- data/campaigns/fri03.wmf/scripting/init.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/init.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,40 @@
+-- =======================================================================
+--                         Frisian Campaign Mission 3
+-- =======================================================================
+set_textdomain("scenario_fri03.wmf")
+
+include "scripting/coroutine.lua"
+include "scripting/objective_utils.lua"
+include "scripting/infrastructure.lua"
+include "scripting/table.lua"
+include "scripting/ui.lua"
+
+game = wl.Game()
+map = game.map
+p1 = game.players[1] -- Claus Lembeck     – Player's tribe
+p2 = game.players[2] -- Waldemar Atterdag – Enemy, King of Denmark
+p3 = game.players[3] -- Henneke Lembeck   – Claus's son
+p4 = game.players[4] -- Hans Ravenstrupp  – Enemy to Claus's other son
+
+ai_speed_1 = 500
+ai_speed_2 = 10
+
+p3_start = {
+   map:get_field(346, 210),
+   map:get_field(347, 210),
+   map:get_field(344, 211),
+   map:get_field(345, 211),
+   map:get_field(346, 211),
+   map:get_field(347, 211),
+   map:get_field(343, 212),
+   map:get_field(344, 212),
+   map:get_field(345, 212),
+   map:get_field(346, 212),
+   map:get_field(343, 213),
+   map:get_field(344, 213),
+   map:get_field(345, 213),
+   map:get_field(344, 214),
+}
+
+include "map:scripting/texts.lua"
+include "map:scripting/mission_thread.lua"

=== added file 'data/campaigns/fri03.wmf/scripting/mission_thread.lua'
--- data/campaigns/fri03.wmf/scripting/mission_thread.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/mission_thread.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,509 @@
+include "scripting/messages.lua"
+include "scripting/field_animations.lua"
+
+farm_connect_done = false
+
+function steady_supply(player, wares)
+   while not player.defeated do
+      sleep(60000)
+      local whs = array_combine(
+         player:get_buildings("HQ_atterdag"),
+         player:get_buildings("HQ_ravenstrupp"),
+         player:get_buildings(player.tribe_name .. "_headquarters"),
+         player:get_buildings(player.tribe_name .. "_warehouse"))
+      -- If the player is low on a ware, he'll certainly get it replaced;
+      -- otherwise, there's a random chance that he'll get it anyway.
+      for ware,n in pairs(wares) do
+         local wh = whs[math.random(#whs)]
+         if wh:get_wares(ware) < n then
+            wh:set_wares(ware, n)
+         end
+      end
+   end
+end
+
+function farms()
+   campaign_message_box(farms_1)
+   local o = add_campaign_objective(obj_connect_farms)
+   local nr_farms = #p1:get_buildings("frisians_farm")
+   local hq = p1:get_buildings("frisians_headquarters")[1].flag
+   sleep(300000)
+   while true do
+      sleep(90000)
+      local ok = true
+      for i,farm in pairs(array_combine(
+         p1:get_buildings("frisians_farm"),
+         p1:get_buildings("frisians_farm_new")
+      )) do
+         if not hq:get_distance(farm.flag) then
+            ok = false
+            p1:send_message(unconnected_farm.title, unconnected_farm.body, {
+               heading = unconnected_farm.heading,
+               field = farm.fields[1],
+               icon = farm.descr.representative_image,
+            })
+            break
+         end
+         sleep(5)
+      end
+      if ok then
+         set_objective_done(o)
+         farm_connect_done = true
+         p1:allow_buildings("all")
+         p1:forbid_buildings {
+            "frisians_hunters_house",
+            "frisians_quarry",
+            "frisians_foresters_house",
+            "frisians_woodcutters_house",
+            "frisians_farm",
+            "frisians_fortress",
+            "frisians_warehouse",
+            "frisians_port",
+            "frisians_shipyard",
+         }
+         return
+      end
+   end
+end
+
+function save_atterdag()
+   -- Waldemar Atterdag must not be defeated, therefore rescue him when it’s going badly for him
+   local hq = p2:get_buildings("empire_headquarters")[1]
+   while true do
+      sleep(5000)
+      local danger = 0
+      for i,f in pairs(map.player_slots[2].starting_field:region(21)) do
+         if f.immovable and f.immovable.descr.type_name == "militarysite" and (f.owner == p1 or f.owner == p3) then
+            danger = danger + f.immovable.descr.max_number_of_soldiers
+         end
+      end
+      if danger > 0 then
+         -- Fill his milsites with soldiers
+         local ok = false
+         for i,f in pairs(map.player_slots[2].starting_field:region(21)) do
+            if f.immovable and f.immovable.descr.type_name == "militarysite" then
+               if f.immovable:get_soldiers({4, 4, 0, 2}) < f.immovable.descr.max_number_of_soldiers then
+                  f.immovable:set_soldiers({4, 4, 0, 2}, f.immovable.descr.max_number_of_soldiers)
+                  ok = true
+               end
+            end
+         end
+         if not ok then
+            -- No milsites to fill? Straight into the HQ then
+            local soldiers = 0
+            for descr,n in pairs(hq:get_soldiers("all")) do
+               soldiers = soldiers + n
+            end
+            hq:set_soldiers({4, 4, 0, 2}, soldiers + danger)
+         end
+         sleep(90000)
+      end
+   end
+end
+
+function run_witch(witch)
+   while witch do
+      for i,f in pairs(witch.field:region(1)) do
+         if f.owner.team == 2 and f.immovable and f.immovable.descr.type_name == "productionsite" then
+            f.immovable:destroy()
+            break
+         end
+      end
+      sleep(math.random(900, 24000))
+   end
+end
+
+function mission_thread()
+
+   p1.team = 1
+   p2.team = 2
+   p3.team = 1
+   p4.team = 2
+
+   for i,f in pairs(p3_start) do
+      map:place_immovable("debris00", f, "world")
+   end
+
+   local land = {}
+   for x=0, map.width - 1 do
+      for y=0, map.height - 1 do
+         local f = map:get_field(x, y)
+         if f.terr ~= "winter_water" or f.terd ~= "winter_water" then
+            table.insert(land, f)
+            table.insert(land, f.brn)
+            table.insert(land, f.bln)
+            table.insert(land, f.trn)
+            table.insert(land, f.tln)
+            table.insert(land, f.rn)
+            table.insert(land, f.ln)
+         end
+      end
+   end
+   p1:reveal_fields(land)
+   p1:conquer(map.player_slots [1].starting_field, map.width)
+   include "map:scripting/starting_conditions.lua"
+
+   run(steady_supply, p1, {
+      log = 40,
+      granite = 20,
+      iron_ore = 20,
+      gold_ore = 10,
+   })
+   run(steady_supply, p2, {
+      log = 60,
+      granite = 30,
+      marble = 80,
+      iron_ore = 30,
+      gold_ore = 20,
+   })
+   run(steady_supply, p4, {
+      log = 70,
+      granite = 40,
+      iron_ore = 30,
+      gold_ore = 20,
+   })
+   scroll_to_field(map.player_slots[1].starting_field)
+
+
+-- NOCOM
+p1.see_all = true
+sleep(9999999)
+
+   -- Introduction
+   sleep(3000)
+   campaign_message_box(intro_1)
+   sleep(3000)
+   campaign_message_box(intro_2)
+   scroll_to_field(map.player_slots[2].starting_field)
+   sleep(3000)
+   campaign_message_box(intro_3)
+   scroll_to_field(map.player_slots[4].starting_field)
+   sleep(3000)
+   campaign_message_box(intro_4)
+   scroll_to_field(map.player_slots[1].starting_field)
+   sleep(3000)
+   campaign_message_box(intro_5)
+   local o = add_campaign_objective(obj_wait_for_reinforcements)
+
+   sleep(5000)
+   campaign_message_box(intro_6)
+
+   sleep(5000)
+   run(save_atterdag)
+   run(farms)
+
+   -- Give the player some extra work to keep him busy
+   while not farm_connect_done do sleep(1000) end
+   -- Now we wait until the enemy is nearly at the Castle
+   local fields = map.player_slots[1].starting_field:region(21, 16)
+   while true do
+      sleep(10000)
+      local enemy = false
+      for i,f in pairs(fields) do
+         if f.owner and f.owner.team == 2 then
+            enemy = true
+            break
+         end
+      end
+      if #p1:get_buildings("frisians_headquarters") == 0 then
+         scroll_to_field(map.player_slots[1].starting_field)
+         sleep(2000)
+         campaign_message_box(defeated_1)
+         wl.ui.MapView():close()
+         return
+      end
+      if enemy then break end
+   end
+
+   for i,f in pairs(p3_start) do
+      f.immovable:remove()
+   end
+   p3:place_ship(map:get_field(344, 208))
+   scroll_to_field(map.player_slots[3].starting_field)
+   sleep(3000)
+   campaign_message_box(help_arrives_1)
+
+   local port = p3:place_building("frisians_port", map.player_slots[3].starting_field, false, true)
+   port:set_wares {
+      log = 40,
+      granite = 50,
+      thatch_reed = 50,
+      brick = 80,
+      clay = 30,
+      water = 10,
+      fish = 10,
+      meat = 10,
+      fruit = 10,
+      barley = 5,
+      ration = 20,
+      honey = 10,
+      smoked_meat = 5,
+      smoked_fish = 5,
+      mead = 5,
+      meal = 2,
+      coal = 20,
+      iron = 5,
+      gold = 4,
+      iron_ore = 10,
+      bread_frisians = 15,
+      honey_bread = 5,
+      beer = 5,
+      cloth = 5,
+      fur = 10,
+      fur_garment = 5,
+      sword_short = 5,
+      hammer = 5,
+      fire_tongs = 2,
+      bread_paddle = 2,
+      kitchen_tools = 2,
+      felling_ax = 3,
+      needles = 2,
+      basket = 2,
+      pick = 5,
+      shovel = 5,
+      scythe = 3,
+      hunting_spear = 2,
+      fishing_net = 3,
+   }
+   port:set_workers {
+      frisians_blacksmith = 3,
+      frisians_baker = 1,
+      frisians_brewer = 1,
+      frisians_builder = 10,
+      frisians_charcoal_burner = 1,
+      frisians_claydigger = 2,
+      frisians_brickmaker = 2,
+      frisians_carrier = 40,
+      frisians_reed_farmer = 2,
+      frisians_berry_farmer = 2,
+      frisians_fruit_collector = 2,
+      frisians_farmer = 1,
+      frisians_landlady = 1,
+      frisians_smoker = 1,
+      frisians_geologist = 4,
+      frisians_woodcutter = 3,
+      frisians_beekeeper = 1,
+      frisians_miner = 4,
+      frisians_miner_master = 2,
+      frisians_forester = 2,
+      frisians_stonemason = 2,
+      frisians_reindeer = 5,
+      frisians_trainer = 3,
+   }
+   port:set_soldiers {
+      [{0,0,0,0}] = 40,
+      [{2,3,2,0}] = 10,
+   }
+   p3:allow_buildings("all")
+   p3:forbid_buildings {
+      "frisians_hunters_house",
+      "frisians_quarry",
+      "frisians_foresters_house",
+      "frisians_woodcutters_house",
+      "frisians_fortress",
+      "frisians_port",
+      "frisians_shipyard",
+   }
+   run(steady_supply, p3, {
+      log = 30,
+      granite = 20,
+      iron_ore = 10,
+      gold_ore = 5,
+   })
+   set_objective_done(o)
+
+   sleep(1000)
+   campaign_message_box(help_arrives_2)
+   p1:switchplayer(3)
+   campaign_message_box(help_arrives_3)
+   o = add_campaign_objective(obj_rescue)
+
+   -- Wait until the enemy is pushed well back
+   fields = map.player_slots[1].starting_field:region(60)
+   while true do
+      local enemy = false
+      for i,f in pairs(fields) do
+         if f.owner and f.owner.team == 2 then
+            enemy = true
+            break
+         end
+         sleep(10)
+      end
+      if p3.defeated or #p1:get_buildings("frisians_headquarters") == 0 then
+         scroll_to_field(map.player_slots[1].starting_field)
+         sleep(2000)
+         campaign_message_box(defeated_1)
+         wl.ui.MapView():close()
+         return
+      end
+      if enemy then break end
+   end
+   set_objective_done(o)
+
+   local critters = {
+      "bunny",
+      "sheep",
+      "wisent",
+      "wildboar",
+      "chamois",
+      "deer",
+      "reindeer",
+      "stag",
+      "elk",
+      "marten",
+      "badger",
+      "lynx",
+      "fox",
+      "wolf",
+      "brownbear"
+   }
+   local witch = {}
+   for i=1,64 do
+      local f = fields[math.random(#fields)]
+      table.insert(witch, map:place_critter(f, critters[math.random(#critters)]))
+   end
+   witch = witch[math.random(#witch)]
+
+   -- Now we have placed an evil witch in disguise on the map.
+   -- She'll walk around and cause buildings to spontaneously burst into flames.
+
+   local destroyed = 0
+   local created_flames = {}
+   while true do
+      local did_destroy = false
+
+      local fires_removed = {}
+      for i,f in pairs(created_flames) do
+         if (not f.immovable) or f.immovable.descr.name ~= "destroyed_building" then
+            table.insert(fires_removed, i)
+         end
+      end
+      for i,index in pairs(fires_removed) do
+         table.remove(index)
+      end
+
+      for i,f in pairs(witch.field:region(1)) do
+         if f.owner.team == 1 and f.immovable and f.immovable.descr.type_name == "productionsite" then
+            f.immovable:destroy()
+            table.insert(created_flames, f)
+            did_destroy = true
+            if destroyed ~= nil then
+               destroyed = destroyed + 1
+               scroll_to_field(f)
+               if destroyed > 3 then
+                  destroyed = nil
+                  campaign_message_box(witchhunt_1)
+                  campaign_message_box(witchhunt_2)
+                  campaign_message_box(witchhunt_3)
+                  o = add_campaign_objective(obj_witchhunt)
+               end
+            end
+            break
+         end
+      end
+
+      if did_destroy then
+         -- Give the witch some time to get away from the flames
+         sleep(3600)
+      else
+         -- Check if the player killed or conjured the witch
+         local next_to_fire = false
+         for i,f in pairs(witch.field:region(1)) do
+            if f.tln.immovable and f.tln.immovable.descr.name == "destroyed_building" then
+               -- Check if this flame was created by the witch or not
+               local w = false
+               for j,field in pairs(f:region(1)) do
+                  for k,flame in pairs(created_flames) do
+                     if field == flame then
+                        w = true
+                        break
+                     end
+                  end
+                  if w then break end
+               end
+               if w then
+                  -- At least one adjacent fire was created by the witch, so she's safe for now
+                  next_to_fire = false
+                  break
+               else
+                  next_to_fire = true
+               end
+            end
+         end
+
+         if next_to_fire then
+            -- The witch is killed
+            scroll_to_field(witch.field)
+            witch:destroy()
+            witch = nil
+            sleep(1000)
+            campaign_message_box(witchhunt_kill)
+            set_objective_done(o)
+            break
+         -- else
+            -- check if she's conjured
+
+            -- TODO(NOCOM)(Nordfriese): Conjure the witch
+
+         end
+      end
+
+      sleep(math.random(600, 18000))
+   end
+   if witch then run(run_witch, witch) end
+
+   campaign_message_box(next_attack_1)
+   o = add_campaign_objective(obj_defeat_ravenstrupp)
+   while not p4.defeated do sleep(4321) end
+   set_objective_done(o)
+
+   sleep(5000)
+   -- TODO(NOCOM)(Nordfriese): place ships for Atterdag and give him lots and lots of soldiers
+   scroll_to_field(map.player_slots[2].starting_field)
+   campaign_message_box(next_attack_2)
+   sleep(1000)
+   campaign_message_box(next_attack_3)
+   campaign_message_box(next_attack_4)
+   o = add_campaign_objective(obj_flee)
+
+   p3:allow_buildings{
+      "frisians_port",
+      "frisians_shipyard",
+   }
+
+   -- Wait until an expedition ship is ready
+   local expedition = nil
+   while not expedition do
+      if p3.defeated or #p1:get_buildings("frisians_headquarters") == 0 then
+         scroll_to_field(map.player_slots[1].starting_field)
+         sleep(2000)
+         campaign_message_box(defeated_1)
+         wl.ui.MapView():close()
+         return
+      end
+      for i,port in pairs(p3:get_buildings("frisians_port")) do
+         if port.expedition_in_progress then
+            expedition = port
+            break
+         end
+      end
+      sleep(1149)
+   end
+
+   -- We escaped!
+   scroll_to_field(expedition.fields[1])
+   local persist = {}
+   for descr,n in pairs(expedition:get_soldiers("all")) do
+      persist[descr[1] .. descr[2] .. descr[3]] = n
+   end
+   -- We save a table of all soldiers we can take with us.
+   -- The syntax is the same as in fri01.
+   game:save_campaign_data("frisians", "fri03", persist)
+   sleep(1000)
+   campaign_message_box(victory_1)
+   p3:reveal_scenario("frisians03")
+   -- END OF MISSION 3
+
+end
+
+run(mission_thread)

=== added file 'data/campaigns/fri03.wmf/scripting/starting_conditions.lua'
--- data/campaigns/fri03.wmf/scripting/starting_conditions.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/starting_conditions.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,408 @@
+-- =======================================================================
+--                                 Player 1
+-- =======================================================================
+p1.see_all = true
+p1:forbid_buildings("all")
+p1:allow_buildings {
+   "frisians_farm",
+   "frisians_warehouse",
+}
+hq = p1:place_building("frisians_headquarters", map.player_slots [1].starting_field, false, true)
+hq:set_wares {
+   log = 40,
+   granite = 50,
+   thatch_reed = 50,
+   brick = 80,
+   clay = 30,
+   water = 10,
+   fish = 10,
+   meat = 10,
+   barley = 5,
+   honey = 10,
+   smoked_meat = 5,
+   smoked_fish = 5,
+   mead = 5,
+   coal = 20,
+   iron = 5,
+   gold = 4,
+   iron_ore = 10,
+   bread_frisians = 15,
+   honey_bread = 5,
+   beer = 5,
+   cloth = 5,
+   fur = 10,
+   fur_garment = 5,
+   sword_short = 5,
+   hammer = 5,
+   fire_tongs = 2,
+   bread_paddle = 2,
+   kitchen_tools = 2,
+   felling_ax = 3,
+   needles = 2,
+   basket = 2,
+   pick = 5,
+   shovel = 5,
+   scythe = 3,
+   hunting_spear = 2,
+   fishing_net = 3,
+}
+hq:set_workers {
+   frisians_blacksmith = 3,
+   frisians_baker = 1,
+   frisians_brewer = 1,
+   frisians_builder = 5,
+   frisians_charcoal_burner = 1,
+   frisians_claydigger = 2,
+   frisians_brickmaker = 2,
+   frisians_carrier = 40,
+   frisians_reed_farmer = 2,
+   frisians_berry_farmer = 2,
+   frisians_fruit_collector = 2,
+   frisians_farmer = 1,
+   frisians_landlady = 1,
+   frisians_smoker = 1,
+   frisians_geologist = 4,
+   frisians_woodcutter = 3,
+   frisians_beekeeper = 1,
+   frisians_miner = 4,
+   frisians_miner_master = 2,
+   frisians_forester = 2,
+   frisians_stonemason = 2,
+   frisians_reindeer = 500,
+   frisians_trainer = 3,
+}
+hq:set_soldiers {
+   [{0,0,0,0}] = 40,
+   [{1,3,1,0}] = 20,
+   [{2,6,2,0}] = 10,
+}
+
+field = map.player_slots[1].starting_field.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn.brn
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+connected_road(p1, field.brn.immovable, "w,w,w|w,w,w|w,w,w|w,w,w|w,w,w")
+for i=1,4 do
+   field = field.ln.ln.ln
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne")
+end
+
+field = field.ln.ln.ln
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+for i=1,4 do
+   field = field.tln.tln.tln
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "e,e,e|e,e,e|e,e,e|e,e,e|e,e,e")
+   connected_road(p1, field.brn.immovable, "ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne")
+end
+
+field = field.tln.tln.tln
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+connected_road(p1, field.brn.immovable, "ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne")
+for i=1,4 do
+   field = field.trn.trn.trn
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "e,e,e|e,e,e|e,e,e|e,e,e|e,e,e")
+end
+
+field = field.trn.trn.trn
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+connected_road(p1, field.brn.immovable, "e,e,e|e,e,e|e,e,e|e,e,e|e,e,e")
+for i=1,4 do
+   field = field.rn.rn.rn
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw")
+end
+
+field = field.rn.rn.rn
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+for i=1,4 do
+   field = field.brn.brn.brn
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "w,w,w|w,w,w|w,w,w|w,w,w|w,w,w")
+   connected_road(p1, field.brn.immovable, "sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw")
+end
+
+field = field.brn.brn.brn
+p1:place_building("frisians_tower", field, false, true):set_soldiers({2, 6, 2, 0}, 7)
+connected_road(p1, field.brn.immovable, "sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw")
+for i=1,4 do
+   field = field.bln.bln.bln
+   p1:place_building("frisians_sentinel", field, false, true):set_soldiers({0, 0, 0, 0}, 2)
+   connected_road(p1, field.brn.immovable, "w,w,w|w,w,w|w,w,w|w,w,w|w,w,w")
+end
+
+connected_road(p1, map.player_slots[1].starting_field.brn.immovable, "w,w,w|w,w,w|w,w,w|w,w,w|w,w,w")
+connected_road(p1, map.player_slots[1].starting_field.brn.immovable, "e,e,e|e,e,e|e,e,e|e,e,e|e,e,e")
+connected_road(p1, map.player_slots[1].starting_field.brn.immovable, "ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne|ne,ne,ne")
+connected_road(p1, map.player_slots[1].starting_field.brn.immovable, "sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw|sw,sw,sw")
+
+houses = {
+   reed_farm = 2,
+   well = 3,
+   clay_pit = 2,
+   brick_kiln = 2,
+   furnace = 2,
+   blacksmithy = 1,
+   armor_smithy_small = 2,
+   armor_smithy_large = 2,
+   recycling_center = 1,
+   sewing_room = 1,
+   tailors_shop = 1,
+   charcoal_kiln = 3,
+   smokery = 3,
+   bakery = 1,
+   brewery = 1,
+   honey_bread_bakery = 2,
+   mead_brewery = 2,
+   reindeer_farm = 2,
+   barracks = 1,
+   training_camp = 1,
+   training_arena = 1,
+}
+fields = {}
+field = map.player_slots[1].starting_field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.brn.brn.brn
+table.insert(fields, field)
+field = field.brn.brn.brn
+table.insert(fields, field)
+field = field.brn.brn.brn
+table.insert(fields, field)
+field = field.bln.bln.bln
+table.insert(fields, field)
+field = field.bln.bln.bln
+table.insert(fields, field)
+field = field.bln.bln.bln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.tln.tln.tln
+table.insert(fields, field)
+field = field.tln.tln.tln
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.ln.ln.ln
+table.insert(fields, field)
+field = field.trn.trn.trn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = map.player_slots[1].starting_field.bln.bln.bln.bln.bln.bln
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+field = field.rn.rn.rn
+table.insert(fields, field)
+for bld,n in pairs(houses) do
+   for i=1,n do
+      field = math.random(#fields)
+      local b = p1:place_building("frisians_" .. bld, fields[field], false, true)
+      if b.valid_inputs then b:set_inputs(b.valid_inputs) end
+      if b.valid_workers then b:set_workers(b.valid_workers) end
+      table.remove(fields, field)
+   end
+end
+
+for i=1,384 do
+   field = nil
+   while not field do
+      field = map:get_field(math.random(5, map.width - 5), math.random(5, map.height - 5))
+      if not p1:get_suitability("frisians_farm", field) then
+         field = nil
+      end
+   end
+   -- Using custom building here to prevent the player from destroying or
+   -- dismantling some farms to make the connect_farms objective easier
+   p1:place_building("frisians_farm_new", field, false, true):set_workers("frisians_farmer", 1)
+end
+
+-- =======================================================================
+--                                 Player 2
+-- =======================================================================
+p2.see_all = true
+p2:allow_buildings("all")
+p2:forbid_buildings {
+   "empire_hunters_house",
+   "empire_quarry",
+   "empire_foresters_house",
+   "empire_lumberjacks_house",
+   "empire_port",
+   "empire_shipyard",
+   "empire_marblemine",
+}
+
+hq = p2:place_building("HQ_atterdag", map.player_slots [2].starting_field, false, true)
+hq:set_wares {
+   armor_helmet = 4,
+   spear_wooden = 5,
+   felling_ax = 6,
+   bread_paddle = 2,
+   basket = 2,
+   empire_bread = 8,
+   cloth = 5,
+   coal = 12,
+   fire_tongs = 2,
+   fish = 6,
+   fishing_rod = 2,
+   flour = 4,
+   gold = 4,
+   grape = 4,
+   hammer = 14,
+   hunting_spear = 2,
+   iron = 12,
+   iron_ore = 5,
+   kitchen_tools = 4,
+   marble = 25,
+   marble_column = 6,
+   meat = 6,
+   pick = 8,
+   saw = 2,
+   scythe = 5,
+   shovel = 6,
+   granite = 40,
+   log = 30,
+   water = 12,
+   wheat = 4,
+   wine = 8,
+   planks = 45,
+   wool = 2,
+}
+hq:set_workers {
+   empire_armorsmith = 1,
+   empire_brewer = 1,
+   empire_builder = 10,
+   empire_carrier = 40,
+   empire_charcoal_burner = 1,
+   empire_geologist = 4,
+   empire_lumberjack = 3,
+   empire_miner = 4,
+   empire_stonemason = 2,
+   empire_toolsmith = 2,
+   empire_trainer = 3,
+   empire_weaponsmith = 1,
+   empire_donkey = 5,
+}
+hq:set_soldiers {
+   [{0,0,0,0}] = 160,
+   [{0,0,0,2}] = 80,
+   [{2,2,0,0}] = 80,
+   [{4,4,0,2}] = 40,
+}
+
+
+
+-- =======================================================================
+--                                 Player 3
+-- =======================================================================
+
+-- He'll join the game later
+p3.see_all = true
+p3:forbid_buildings("all")
+
+-- =======================================================================
+--                                 Player 4
+-- =======================================================================
+p4.see_all = true
+p4:allow_buildings("all")
+p4:forbid_buildings {
+   "barbarians_hunters_hut",
+   "barbarians_gamekeepers_hut",
+   "barbarians_quarry",
+   "barbarians_rangers_hut",
+   "barbarians_lumberjacks_hut",
+   "barbarians_inn",
+   "barbarians_port",
+   "barbarians_shipyard",
+}
+
+hq = p4:place_building("barbarians_headquarters", map.player_slots [4].starting_field, false, true)
+hq:set_wares {
+   ax = 5,
+   bread_paddle = 2,
+   blackwood = 32,
+   cloth = 5,
+   coal = 12,
+   felling_ax = 4,
+   fire_tongs = 2,
+   fish = 6,
+   fishing_rod = 2,
+   gold = 4,
+   grout = 12,
+   hammer = 12,
+   hunting_spear = 2,
+   iron = 12,
+   iron_ore = 5,
+   kitchen_tools = 4,
+   meat = 6,
+   pick = 8,
+   barbarians_bread = 8,
+   granite = 40,
+   scythe = 6,
+   shovel = 4,
+   thatch_reed = 24,
+   log = 80,
+}
+hq:set_workers {
+   barbarians_blacksmith = 2,
+   barbarians_brewer = 1,
+   barbarians_builder = 10,
+   barbarians_charcoal_burner = 1,
+   barbarians_carrier = 40,
+   barbarians_gardener = 1,
+   barbarians_geologist = 4,
+   barbarians_lime_burner = 1,
+   barbarians_lumberjack = 3,
+   barbarians_miner = 4,
+   barbarians_miner_master = 4,
+   barbarians_ranger = 1,
+   barbarians_stonemason = 2,
+   barbarians_trainer = 3,
+   barbarians_ox = 5,
+}
+hq:set_soldiers {
+   [{0,0,0,0}] = 160,
+   [{0,0,0,2}] = 80,
+   [{3,5,0,0}] = 80,
+   [{3,5,0,2}] = 40,
+}
+
+

=== added file 'data/campaigns/fri03.wmf/scripting/texts.lua'
--- data/campaigns/fri03.wmf/scripting/texts.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/texts.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,245 @@
+-- =========================
+-- Some formating functions
+-- =========================
+
+include "scripting/richtext_scenarios.lua"
+
+function claus(title, text)
+   return speech ("map:claus.png", "1CC200", title, text)
+end
+function henneke(title, text)
+   return speech ("map:henneke.png", "F7FF00", title, text)
+end
+function atterdag(title, text)
+   return speech ("map:atterdag.png", "CC1000", title, text)
+end
+
+-- =======================================================================
+--                           Texts - No logic here
+-- =======================================================================
+
+-- ===========
+-- objectives
+-- ===========
+
+obj_wait_for_reinforcements = {
+   name = "wait_for_reinforcements",
+   title=_"Survive until help arrives",
+   number = 1,
+   body = objective_text(_"Wait For Help",
+      li(_[[Survive the attacks until Henneke Lembeck arrives with reinforcements.]]) ..
+      li_arrow(_[[The enemies must not destroy your headquarters.]])
+   ),
+}
+
+obj_connect_farms = {
+   name = "connect_farms",
+   title=_"Connect the farms",
+   number = 1,
+   body = objective_text(_"Build Roads to All Farms",
+      li(_[[Build roads to ensure all farms can be reached from your headquarters.]]) ..
+      li(_[[You may not attempt to make this task easier by destroying or dismantling some farms.]]) ..
+      li(_[[Until you have completed this objective, you may build only farms and warehouses. Afterwards, these buildings can not be built anymore.]])
+   ),
+}
+
+obj_rescue = {
+   name = "rescue",
+   title=_"Rescue the Castle",
+   number = 1,
+   body = objective_text(_"Prevent the Enemies from Destroying the Castle",
+      li(_[[Push back the enemies. They must not conquer Claus Lembeck’s headquarters.]])
+   ),
+}
+
+obj_witchhunt = {
+   name = "witchhunt",
+   title=_"Chase the witch",
+   number = 1,
+   body = objective_text(_"Kill or Capture the Evil Witch",
+      li(_[[A witch in animal shape is destroying your buildings. Either kill her or capture her.]]) ..
+      li_arrow(_[[To kill the witch, burn down a building when the witch is close to its flag.]]) ..
+      li_arrow(_[[To capture the witch, conjure the spirits residing within her. Hint: You need to make a circle.]])
+   ),
+}
+
+obj_defeat_ravenstrupp = {
+   name = "defeat_ravenstrupp",
+   title=_"Defeat Hans Ravenstrupp",
+   number = 1,
+   body = objective_text(_"Defeat the King’s Ally",
+      li(_[[Defeat Atterdag’s accomplice Ravenstrupp!]])
+   ),
+}
+
+obj_flee = {
+   name = "flee",
+   title=_"Flee",
+   number = 1,
+   body = objective_text(_"Flee the Island",
+      li(_[[Build a ship and start an expedition from a port to flee.]]) ..
+      li(_[[The enemies are too powerful and numerous for you to defeat them. Don’t even try.]]) ..
+      li(_[[Take some soldiers with you when your ship sets sail. You will need them.]])
+   ),
+}
+
+-- ==================
+-- Texts to the user
+-- ==================
+
+intro_1 = {
+   title = _"Introduction",
+   body=claus(_"Welcome back!",
+      -- TRANSLATORS: Claus Lembeck – Introduction 1
+      _([[I wish I could greet you, but the circumstances deny me that luxury.]])),
+}
+intro_2 = {
+   title = _"Introduction",
+   body=claus(_"Welcome back!",
+      -- TRANSLATORS: Claus Lembeck – Introduction 2. The "Thing" (DO NOT TRANSLATE) is the gathering of the frisian aldermen
+      _([[In other times, I would welcome you with a banquet, introduce you to the Thing, and show you around Föhr, this beautiful island, which we also call the Green Island due to its shining meadows, or the Frisian Carribbean, in comparison with a faraway land which the captains and sailors talk so highly about.]])),
+}
+intro_3 = {
+   title = _"Introduction",
+   body=claus(_"Welcome back!",
+      -- TRANSLATORS: Claus Lembeck – Introduction 3
+      _([[But I am none other than Claus Lembeck, and my troubles are too great; for danger has risen from a partly unexpected source, and it has arrived ere I was ready for it.]])
+      .. paragraphdivider() ..
+      -- TRANSLATORS: Claus Lembeck – Introduction 3
+      _([[My old enemy Waldemar Atterdag, King of the Danes, is leveling at my life yet again. I have lost count of the number of times I have fought him and prevailed. But then, I was always in my fortress at Dorning, which is impenetrable even to the strongest foe. But recently, I have left Dorning to my oldest son Rolf to build a castle here on Föhr.]])),
+}
+intro_4 = {
+   title = _"Introduction",
+   body=claus(_"Welcome back!",
+      -- TRANSLATORS: Claus Lembeck – Introduction 4
+      _([[Added to this worry is the fact that Rolf made an enemy of Atterdag’s kinsman Hans Ravenstrupp, who owns the castle of Haderslevhuus. If the news hold true, he has dishonourably murdered my son and is now seeking to be revenged on me as well for God knows what.]])
+      .. paragraphdivider() ..
+      -- TRANSLATORS: Claus Lembeck – Introduction 4
+      _([[Atterdag and Ravenstrupp have joined in complot and have both landed on this island before my watchmen discovered their approach.]])),
+}
+intro_5 = {
+   title = _"Introduction",
+   body=claus(_"Welcome back!",
+      -- TRANSLATORS: Claus Lembeck – Introduction 5
+      _([[I have sent word to my other son Henneke, and he is coming to my aid. Until then, we must hold out against the enemies’ attacks. They are still far away and may appear weak, but my scouts assure me that they are much too strong for our modest army.]]))
+      .. new_objectives(obj_wait_for_reinforcements),
+}
+intro_6 = {
+   title = _"Note",
+   -- TRANSLATORS: Narrator – Introduction 6
+   body=p(_([[No mines can be built on this island. There are no rocks to cut granite from. And it is not possible to grow trees on this map. All players will be supplied frequently with wood, stones, and ores.]])),
+   w = 450,
+   h = 150,
+}
+
+farms_1 = {
+   title = _"Barley Supply",
+   body=claus(_"Connect our farms",
+      -- TRANSLATORS: Claus Lembeck – Farms
+      _([[We used to get the barley we need for bread, beer, and to feed the reindeer by trading with the farmers. In this time of war, we have to make this trade more efficient. The farmers have agreed to deliver their entire harvest to our headquarters at a fixed price. Build roads to all farms to ensure our carriers can take care of that.]]))
+      .. new_objectives(obj_connect_farms),
+}
+
+unconnected_farm = {
+   title = _"Unconnected Farm",
+   heading = _"A Farm is not connected yet",
+   body = p(_[[At least one of your farms is not connected to your headquarters yet.]])
+}
+
+help_arrives_1 = {
+   title = _"Aid is Arriving",
+   body=claus(_"Henneke is coming!",
+      -- TRANSLATORS: Claus Lembeck – Henneke arrives 1
+      _([[Finally! A ship has landed on the eastern cost of the island. I know these colors – my son Henneke has come to our aid at last!]])),
+}
+help_arrives_2 = {
+   title = _"Aid is Arriving",
+   body=henneke(_"Unwelcome news",
+      -- TRANSLATORS: Henneke Lembeck – Henneke arrives 2
+      _([[Peace, Father! I have come to help you, but I fear I bring cold news. When I was lately at Kiel, the citizens mistook my soldiers for bandits and killed most of them, and I lost more when destroying the town in revenge. To cut the tale short – I have brought but few soldiers to aid you.]])),
+}
+help_arrives_3 = {
+   title = _"Aid is Arriving",
+   body=claus(_"Unwelcome news",
+      -- TRANSLATORS: Claus Lembeck – Henneke arrives 3
+      _([[These news are terrible indeed! The enemies are strong, and a mighty army would be hard-pressed to drive them off! But it is useless to complain, since there is nothing that can be done about it. Let us pray for strength, and fight the foes together!]]))
+      .. new_objectives(obj_rescue),
+}
+
+witchhunt_1 = {
+   title = _"Inexplicable Fires",
+   body=claus(_"Buildings are burning",
+      -- TRANSLATORS: Claus Lembeck – Witchhunt 1
+      _([[The enemies have been pushed back, but something strange is going on. Several buildings have burst into flame for no apparent reason! How can this be?]])),
+}
+witchhunt_2 = {
+   title = _"Inexplicable Fires",
+   body=henneke(_"Buildings are burning",
+      -- TRANSLATORS: Henneke Lembeck – Witchhunt 2
+      _([[It is rumoured among our people that there is a witch or wizard inside our fortifications. This evildoer, they say, is responsible for the fires. Sightings of ferocious animals that strolled through our town have been reported. I suspect the evil witch is disguised as one of these, and working havoc in our Castle!]])),
+}
+witchhunt_3 = {
+   title = _"Inexplicable Fires",
+   body=claus(_"Buildings are burning",
+      -- TRANSLATORS: Claus Lembeck – Witchhunt 3
+      _([[You think so? You know I am sceptical whether witches even exist, but the clerics seem to share your suspicions. Very well, let’s see if we can identify and kill the witch. Or perhaps, it might even be possible to capture her alive and make her fight our enemies for us! I have no idea how that could be done though…]]))
+      .. new_objectives(obj_witchhunt),
+}
+witchhunt_kill = {
+   title = _"Witch Killed",
+   body=claus(_"The witch was killed",
+      -- TRANSLATORS: Claus Lembeck – Witchhunt: Witch was killed
+      _([[Finally! The witch was killed, and we can now focus on driving out our enemies again.]])),
+}
+witchhunt_conjure = {
+   title = _"Witch Conjured",
+   body=henneke(_"The witch was conjured",
+      -- TRANSLATORS: Henneke Lembeck – Witchhunt: Witch was conjured
+      _([[We succeeded in conjuring the witch! She is now heading to our enemies and will harrass them instead of us. We can now focus on driving out our enemies again.]])),
+}
+next_attack_1 = {
+   title = _"Defeat Hans Ravenstrupp",
+   body=claus(_"Defeat Ravenstrupp",
+      -- TRANSLATORS: Claus Lembeck – Next Attack 1
+      _([[I am confident we only need to defeat Hans Ravenstrupp – I know his master the King for a coward that pretends to be invincible while he is protected by his minions but who will run for life as soon as his helpers are defeated.]]))
+      .. new_objectives(obj_defeat_ravenstrupp),
+}
+next_attack_2 = {
+   title = _"Reinforcements",
+   body=atterdag(_"I am not defeated yet!",
+      -- TRANSLATORS: Waldemar Atterdag – Next Attack 2
+      _([[You may have defeated my loyal ally, but do not think you have gotten the better of me! Fools, I have sent to Denmark for aid, and here it arrives! Today, I will defeat you at last, Lembeck!]])),
+}
+next_attack_3 = {
+   title = _"Reinforcements",
+   body=henneke(_"No hope",
+      -- TRANSLATORS: Henneke Lembeck – Next Attack 3
+      _([[Oh no! Just look at the sheer number of ships! There is no way we can defeat such a mighty army. How can we possibly hope to see another dawn?]])),
+}
+next_attack_4 = {
+   title = _"Reinforcements",
+   body=claus(_"Escape",
+      -- TRANSLATORS: Claus Lembeck – Next Attack 4
+      _([[If we attempt to fight, we will all be slaughtered. We have to escape while we still can, and come back later with a large fighting force to give the cur what he deserves!]])
+      .. paragraphdivider() ..
+      -- TRANSLATORS: Claus Lembeck – Next Attack 4
+      _([[I have but few friends on the mainland and the surrounding islands – they will not be able or willing to aid us. Our only hope is my old friend Reebaud. I heard he sailed North after the Great Stormflood. Our only hope to reclaim my island lies in seeking him out and asking for his aid.!]]))
+      .. new_objectives(obj_flee),
+}
+
+defeated_1 = {
+   title = _"You are Defeated",
+   -- TRANSLATORS: Narrator – Player was defeated
+   body=p(_([[You were defeated and may not continue playing. May you have better luck when you retry this scenario. Click OK to return to the main menu.]])),
+   w = 450,
+   h = 150,
+}
+victory_1 = {
+   title = _"Victory",
+   body=claus(_"We escaped!",
+      -- TRANSLATORS: Claus Lembeck – victory
+      _([[We have escaped]]))
+      .. objective_text(_"Congratulations",
+      -- TRANSLATORS: Claus Lembeck – victory
+      _[[You have completed this mission. You may move on to the next scenario now to help us in our quest to seek out Reebaud and obtain his aid…]]),
+}

=== added directory 'data/campaigns/fri03.wmf/scripting/tribes'
=== added file 'data/campaigns/fri03.wmf/scripting/tribes/HQ_atterdag.lua'
--- data/campaigns/fri03.wmf/scripting/tribes/HQ_atterdag.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/tribes/HQ_atterdag.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,32 @@
+dirname = "tribes/buildings/warehouses/empire/headquarters/"
+
+tribes:new_warehouse_type {
+   msgctxt = "empire_building",
+   name = "HQ_atterdag",
+   -- TRANSLATORS: This is a building name used in lists of buildings
+   descname = pgettext("empire_building", "Headquarters"),
+   helptext_script = dirname .. "helptexts.lua",
+   icon = dirname .. "menu.png",
+   size = "big",
+   destructible = false,
+
+   animations = {
+      idle = {
+         pictures = path.list_files(dirname .. "idle_??.png"),
+         hotspot = { 95, 109 },
+      },
+   },
+
+   outputs = {
+      "granite",
+      "marble",
+      "iron_ore",
+      "gold_ore",
+      "log"
+   },
+
+   aihints = {},
+
+   heal_per_second = 220,
+   conquers = 9,
+}

=== added file 'data/campaigns/fri03.wmf/scripting/tribes/HQ_ravenstrupp.lua'
--- data/campaigns/fri03.wmf/scripting/tribes/HQ_ravenstrupp.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/tribes/HQ_ravenstrupp.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,35 @@
+dirname = "tribes/buildings/warehouses/barbarians/headquarters/"
+
+tribes:new_warehouse_type {
+   msgctxt = "barbarians_building",
+   name = "HQ_ravenstrupp",
+   -- TRANSLATORS: This is a building name used in lists of buildings
+   descname = pgettext("barbarians_building", "Headquarters"),
+   helptext_script = dirname .. "helptexts.lua",
+   icon = dirname .. "menu.png",
+   size = "big",
+   destructible = false,
+
+   -- The Headquarters of the barbarians is from the apperance a stable military
+   -- Building, fortified base and some towers made of blackwood. Some flags
+   -- in the player colors may be present
+   animations = {
+      idle = {
+         pictures = path.list_files(dirname .. "idle_??.png"),
+         hotspot = { 90, 96 },
+         fps = 10
+      },
+   },
+
+   outputs = {
+      "granite",
+      "iron_ore",
+      "gold_ore",
+      "log"
+   },
+
+   aihints = {},
+
+   heal_per_second = 220,
+   conquers = 9,
+}

=== added file 'data/campaigns/fri03.wmf/scripting/tribes/farm_new.lua'
--- data/campaigns/fri03.wmf/scripting/tribes/farm_new.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/tribes/farm_new.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,76 @@
+dirname = "tribes/buildings/productionsites/frisians/farm/"
+
+tribes:new_productionsite_type {
+   msgctxt = "frisians_building",
+   name = "frisians_farm_new",
+   -- TRANSLATORS: This is a building name used in lists of buildings
+   descname = pgettext ("frisians_building", "Farm"),
+   helptext_script = dirname .. "helptexts.lua",
+   icon = dirname .. "menu.png",
+   size = "big",
+   destructible = false,
+
+   animations = {
+      idle = {
+         pictures = path.list_files (dirname .. "idle_??.png"),
+         hotspot = {105, 138},
+         fps = 10,
+      },
+      working = {
+         pictures = path.list_files (dirname .. "working_??.png"),
+         hotspot = {105, 138},
+         fps = 10,
+      },
+      unoccupied = {
+         pictures = path.list_files (dirname .. "unoccupied_?.png"),
+         hotspot = {105, 111},
+      },
+   },
+
+   aihints = {},
+
+   working_positions = {
+      frisians_farmer = 1
+   },
+
+   outputs = {
+      "barley"
+   },
+
+   programs = {
+      work = {
+         -- TRANSLATORS: Completed/Skipped/Did not start working because ...
+         descname = _"working",
+         actions = {
+            "call=plant_barley",
+            "call=harvest_barley",
+            "return=no_stats"
+         }
+      },
+      plant_barley = {
+         -- TRANSLATORS: Completed/Skipped/Did not start planting barley because ...
+         descname = _"planting barley",
+         actions = {
+            "sleep=18000",
+            "callworker=plant"
+         }
+      },
+      harvest_barley = {
+         -- TRANSLATORS: Completed/Skipped/Did not start harvesting barley because ...
+         descname = _"harvesting barley",
+         actions = {
+            "sleep=8000",
+            "callworker=harvest",
+            "animate=working 40000",
+            "produce=barley" --produces 2 barley per field
+         }
+      },
+   },
+   out_of_resource_notification = {
+      -- Translators: Short for "Out of ..." for a resource
+      title = _"No Fields",
+      heading = _"Out of Fields",
+      message = pgettext ("frisians_building", "The farmer working at this farm has no cleared soil to plant his seeds."),
+      productivity_threshold = 30
+   },
+}

=== added file 'data/campaigns/fri03.wmf/scripting/tribes/init.lua'
--- data/campaigns/fri03.wmf/scripting/tribes/init.lua	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/scripting/tribes/init.lua	2019-05-11 21:13:40 +0000
@@ -0,0 +1,21 @@
+tribes = wl.Tribes()
+include "scripting/mapobjects.lua"
+
+print_loading_message("Loading campaign-specific tribe units", function()
+   include "map:scripting/tribes/farm_new.lua"
+   include "map:scripting/tribes/HQ_atterdag.lua"
+   include "map:scripting/tribes/HQ_ravenstrupp.lua"
+end)
+
+tribes:add_custom_building {
+   tribename = "frisians",
+   buildingname = "frisians_farm_new",
+}
+tribes:add_custom_building {
+   tribename = "empire",
+   buildingname = "HQ_atterdag",
+}
+tribes:add_custom_building {
+   tribename = "barbarians",
+   buildingname = "HQ_ravenstrupp",
+}

=== added file 'data/campaigns/fri03.wmf/version'
--- data/campaigns/fri03.wmf/version	1970-01-01 00:00:00 +0000
+++ data/campaigns/fri03.wmf/version	2019-05-11 21:13:40 +0000
@@ -0,0 +1,11 @@
+# Automatically created by Widelands bzr9036[editor-resize-map] (Debug)
+
+[global]
+map_source_url=
+map_release=
+map_creator_version="bzr9036[editor-resize-map]"
+map_version_major="0"
+map_version_minor="1"
+map_version_timestamp="1554470707"
+packet_version="1"
+packet_compatibility="1"

=== modified file 'data/tribes/buildings/productionsites/atlanteans/horsefarm/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/horsefarm/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/buildings/productionsites/atlanteans/horsefarm/init.lua	2019-05-11 21:13:40 +0000
@@ -32,7 +32,8 @@
 
    aihints = {
       recruitment = true,
-      prohibited_till = 610
+      prohibited_till = 610,
+      forced_after = 2000
    },
 
    working_positions = {

=== modified file 'data/tribes/buildings/productionsites/barbarians/barracks/init.lua'
--- data/tribes/buildings/productionsites/barbarians/barracks/init.lua	2019-03-13 20:21:20 +0000
+++ data/tribes/buildings/productionsites/barbarians/barracks/init.lua	2019-05-11 21:13:40 +0000
@@ -37,7 +37,6 @@
    },
 
    aihints = {
-      basic_amount = 1,
       very_weak_ai_limit = 1,
       weak_ai_limit = 2,
       prohibited_till = 920

=== modified file 'data/tribes/buildings/productionsites/barbarians/cattlefarm/init.lua'
--- data/tribes/buildings/productionsites/barbarians/cattlefarm/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/buildings/productionsites/barbarians/cattlefarm/init.lua	2019-05-11 21:13:40 +0000
@@ -32,7 +32,8 @@
 
    aihints = {
       recruitment = true,
-      prohibited_till = 610
+      prohibited_till = 610,
+      forced_after = 2000
    },
 
    working_positions = {

=== modified file 'data/tribes/buildings/productionsites/empire/donkeyfarm/init.lua'
--- data/tribes/buildings/productionsites/empire/donkeyfarm/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/buildings/productionsites/empire/donkeyfarm/init.lua	2019-05-11 21:13:40 +0000
@@ -32,7 +32,8 @@
 
    aihints = {
       recruitment = true,
-      prohibited_till = 610
+      prohibited_till = 610,
+      forced_after = 2000
    },
 
    working_positions = {

=== modified file 'data/tribes/wares/coal/init.lua'
--- data/tribes/wares/coal/init.lua	2017-06-30 15:31:17 +0000
+++ data/tribes/wares/coal/init.lua	2019-05-11 21:13:40 +0000
@@ -14,10 +14,10 @@
       empire = 20
    },
    preciousness = {
-      atlanteans = 1,
-      barbarians = 1,
-      frisians = 6,
-      empire = 1
+      atlanteans = 10,
+      barbarians = 20,
+      frisians = 40,
+      empire = 10
    },
 
    animations = {

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2019-04-20 05:44:37 +0000
+++ src/ai/defaultai.cc	2019-05-11 21:13:40 +0000
@@ -1326,13 +1326,17 @@
 	field.nearest_buildable_spot_nearby = std::numeric_limits<uint16_t>::max();
 	field.unowned_buildable_spots_nearby = 0;
 	field.unowned_portspace_vicinity_nearby = 0;
-	if (field.unowned_land_nearby > 0) {
+	if (field.unowned_land_nearby > 0 || (field.enemy_owned_land_nearby > 0 &&
+	       field.enemy_military_presence < std::abs(management_data.get_military_number_at(174)) / 10)) {
 		std::vector<Coords> found_buildable_fields;
 
 		// first looking for unowned buildable spots
 		field.unowned_buildable_spots_nearby =
 		   map.find_fields(Area<FCoords>(field.coords, kBuildableSpotsCheckArea),
 		                   &found_buildable_fields, find_unowned_buildable);
+		field.unowned_buildable_spots_nearby +=
+		   map.find_fields(Area<FCoords>(field.coords, kBuildableSpotsCheckArea),
+		                   &found_buildable_fields, find_enemy_owned_walkable);
 		// Now iterate over fields to collect statistics
 		for (auto& coords : found_buildable_fields) {
 			// We are not interested in blocked fields
@@ -2454,6 +2458,12 @@
 
 		if (!bo.buildable(*player_)) {
 			bo.new_building = BuildingNecessity::kNotNeeded;
+			// TODO Hessenfarmer: Add the buildings if they are allowed again
+			// This line removes buildings from basic econmy if they are not allowed for the player
+			// this should only happen by scripting. 
+			if (bo.basic_amount) {
+				persistent_data->remaining_basic_buildings.erase(bo.id);
+			}
 		} else if (bo.type == BuildingObserver::Type::kProductionsite ||
 		           bo.type == BuildingObserver::Type::kMine) {
 
@@ -3752,6 +3762,8 @@
 		// if we are within grace time, it is OK, just go on
 		if (eco->dismantle_grace_time > gametime &&
 		    eco->dismantle_grace_time != std::numeric_limits<uint32_t>::max()) {
+			;
+
 			// if grace time is not set, this is probably first time without a warehouse and we must
 			// set it
 		} else if (eco->dismantle_grace_time == std::numeric_limits<uint32_t>::max()) {
@@ -4104,7 +4116,8 @@
 
 	// do not dismantle or upgrade the same type of building too soon - to give some time to update
 	// statistics
-	if (site.bo->last_dismantle_time > game().get_gametime() - 30 * 1000) {
+	if (site.bo->last_dismantle_time > game().get_gametime() -
+		    (std::abs(management_data.get_military_number_at(164)) / 25 + 1) * 60 * 1000) {
 		return false;
 	}
 
@@ -4210,11 +4223,11 @@
 		    (en_bo.cnt_under_construction + en_bo.unoccupied_count) == 0) {
 
 			// forcing first upgrade
-			if (en_bo.total_count() == 0) {
+			if (en_bo.total_count() == 0 && (site.bo->cnt_built > 1 || site.bo->is(BuildingAttribute::kUpgradeSubstitutes))) {
 				doing_upgrade = true;
 			}
 
-			if (en_bo.total_count() == 1) {
+			if (en_bo.total_count() == 1 && (site.bo->cnt_built > 1 || site.bo->is(BuildingAttribute::kUpgradeSubstitutes))) {
 				if (en_bo.current_stats > 55) {
 					doing_upgrade = true;
 				}
@@ -4441,7 +4454,8 @@
 
 		// if we have more buildings then target
 		if ((site.bo->cnt_built - site.bo->unconnected_count) > site.bo->cnt_target &&
-		    site.unoccupied_till + 10 * 60 * 1000 < gametime && site.site->can_start_working()) {
+		    site.unoccupied_till + (std::abs(management_data.get_military_number_at(166)) / 5 + 1) * 60 *
+		    1000 < gametime && site.site->can_start_working()) {
 
 			if (site.site->get_statistics_percent() < 30 && get_stocklevel(*site.bo, gametime) > 100) {
 				site.bo->last_dismantle_time = game().get_gametime();
@@ -4456,7 +4470,9 @@
 
 		// a building can be dismanteld if it performs too bad, if it is not the last one
 		if (site.site->get_statistics_percent() <= 10 && site.bo->cnt_built > 1 &&
-		    site.unoccupied_till + 10 * 60 * 1000 < gametime && site.site->can_start_working()) {
+		    site.unoccupied_till + (std::abs(management_data.get_military_number_at(167)) / 5 + 1) * 60 *
+		    1000 < gametime && site.site->can_start_working() && get_stocklevel(*site.bo, gametime) >
+		    (std::abs(management_data.get_military_number_at(168)) / 5)) {
 
 			if (connected_to_wh) {
 				game().send_player_dismantle(*site.site);
@@ -4483,7 +4499,8 @@
 	    site.site->can_start_working() &&
 	    check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime) ==
 	       BuildingNecessity::kNotNeeded &&
-	    gametime - site.bo->last_dismantle_time > 5 * 60 * 1000 &&
+	    gametime - site.bo->last_dismantle_time >
+	        (std::abs(management_data.get_military_number_at(169)) / 10 + 1) * 60 * 1000 &&
 
 	    site.bo->current_stats > site.site->get_statistics_percent() &&  // underperformer
 	    (game().get_gametime() - site.unoccupied_till) > 10 * 60 * 1000) {
@@ -4821,7 +4838,6 @@
 BuildingNecessity DefaultAI::check_building_necessity(BuildingObserver& bo,
                                                       const PerfEvaluation purpose,
                                                       const uint32_t gametime) {
-
 	bo.primary_priority = 0;
 
 	static BasicEconomyBuildingStatus site_needed_for_economy = BasicEconomyBuildingStatus::kNone;
@@ -4935,7 +4951,7 @@
 		if (!basic_economy_established) {
 			return BuildingNecessity::kForbidden;
 		}
-		const uint16_t min_roads_count = 50 + std::abs(management_data.get_military_number_at(33));
+		const uint16_t min_roads_count = 20 + std::abs(management_data.get_military_number_at(33))/2;
 		if (roads.size() < min_roads_count) {
 			return BuildingNecessity::kForbidden;
 		}
@@ -4971,8 +4987,8 @@
 
 			if (calculate_stocklevel(wt) < target ||
 			    site_needed_for_economy == BasicEconomyBuildingStatus::kEncouraged) {
-				if (bo.max_needed_preciousness < preciousness) {
-					bo.max_needed_preciousness = preciousness;
+				if (bo.max_needed_preciousness < 2 * preciousness) {
+					bo.max_needed_preciousness = 2 * preciousness;
 				}
 				if (site_needed_for_economy == BasicEconomyBuildingStatus::kEncouraged) {
 					bo.max_needed_preciousness +=
@@ -5054,7 +5070,7 @@
 		   get_building_observer(tribe_->get_building_descr(enhancement)->name().c_str());
 		if ((gametime > 30 * 60 * 1000 && en_bo.total_count() == 0) || gametime > 90 * 60 * 1000) {
 			// We fake this
-			bo.max_needed_preciousness = bo.max_preciousness;
+			bo.max_needed_preciousness = bo.max_preciousness * 2;
 			needs_second_for_upgrade = true;
 		}
 	}
@@ -5103,9 +5119,9 @@
 			inputs[8] = (expansion_type.get_expansion_type() == ExpansionMode::kEconomy) ? +3 : 0;
 			inputs[9] = (expansion_type.get_expansion_type() == ExpansionMode::kBoth) ? +1 : 0;
 			inputs[10] = (expansion_type.get_expansion_type() == ExpansionMode::kBoth) ? +1 : 0;
-			inputs[11] = (bo.last_building_built + 5 * 60 * 100 > gametime) ? +1 : 0;
-			inputs[12] = (bo.last_building_built + 10 * 60 * 100 > gametime) ? +1 : 0;
-			inputs[13] = (bo.last_building_built + 20 * 60 * 100 > gametime) ? +1 : 0;
+			inputs[11] = (bo.last_building_built + 5 * 60 * 100 < gametime) ? +1 : 0;
+			inputs[12] = (bo.last_building_built + 10 * 60 * 100 < gametime) ? +1 : 0;
+			inputs[13] = (bo.last_building_built + 20 * 60 * 100 < gametime) ? +1 : 0;
 			inputs[14] = (bo.total_count() >= bo.cnt_target) ? -1 : 0;
 			inputs[15] = (bo.total_count() >= bo.cnt_target) ? -2 : 0;
 			inputs[16] = (bo.total_count() < bo.cnt_target) ? -1 : 0;
@@ -5150,7 +5166,7 @@
 			if (bo.total_count() > 1 && (bo.cnt_under_construction + bo.unoccupied_count > 0)) {
 				return BuildingNecessity::kForbidden;
 			}
-			bo.cnt_target = 3;
+			bo.cnt_target = 2;
 			// adjusting/decreasing based on cnt_limit_by_aimode
 			bo.cnt_target = std::min(bo.cnt_target, bo.cnt_limit_by_aimode);
 
@@ -5173,8 +5189,7 @@
 		} else if (bo.is(BuildingAttribute::kRanger)) {
 
 			// making sure we have one completed lumberjack
-			if (bo.total_count() > 0 &&
-			    get_building_observer(BuildingAttribute::kLumberjack).cnt_built < 1) {
+			if (get_building_observer(BuildingAttribute::kLumberjack).cnt_built < 1) {
 				return BuildingNecessity::kForbidden;
 			}
 
@@ -5455,11 +5470,10 @@
 			inputs[14] = (bo.current_stats - 50) / 10;
 			inputs[15] = management_data.get_military_number_at(123) / 10;
 			inputs[16] = 0;
-			// TODO(GunChleoc): This is overwritten below due to a typo
-			// inputs[17] = (inputs_on_stock) ? 0 : -2;
+			inputs[17] = (inputs_on_stock) ? 0 : -2;
 			inputs[18] = (suppliers_exist) ? 0 : -3;
-			inputs[17] = (inputs_on_stock) ? 0 : -4;
-			// Nothing on inputs[19]
+			;
+			inputs[19] = (inputs_on_stock) ? 0 : -4;
 			inputs[20] =
 			   (mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished == 1) ?
 			      3 :
@@ -5516,7 +5530,7 @@
 			inputs[0] = (bo.total_count() <= 1) ?
 			               std::abs(management_data.get_military_number_at(110)) / 10 :
 			               0;
-			inputs[1] = -2 * bo.total_count();
+			inputs[1] = -4 * bo.total_count() + 2 * bo.total_count() + bo.total_count() / 2;
 			inputs[2] =
 			   (bo.total_count() == 0) ? std::abs(management_data.get_military_number_at(0)) / 10 : 0;
 			inputs[3] = (gametime >= 25 * 60 * 1000 && bo.inputs.empty()) ?
@@ -5529,11 +5543,11 @@
 			               management_data.get_military_number_at(3) / 10 :
 			               0;
 			inputs[6] = (needs_second_for_upgrade) ?
-			               std::abs(management_data.get_military_number_at(4)) / 10 :
+			               std::abs(management_data.get_military_number_at(4)) / 5 :
 			               0;
 			inputs[7] = (bo.cnt_under_construction + bo.unoccupied_count) * -1 *
 			            std::abs(management_data.get_military_number_at(9)) / 5;
-			inputs[8] = (!bo.outputs.empty() && bo.current_stats > 30 + 70 / bo.outputs.size()) ?
+			inputs[8] = (!bo.outputs.empty() && bo.current_stats > 25 + 70 / bo.outputs.size()) ?
 			               management_data.get_military_number_at(7) / 8 :
 			               0;
 			inputs[9] = (bo.is(BuildingAttribute::kBuildingMatProducer)) ?
@@ -5559,7 +5573,7 @@
 			                management_data.get_military_number_at(97) / 10 :
 			                0;
 			inputs[17] =
-			   (spots_ > kSpotsEnough) ? std::abs(management_data.get_military_number_at(74)) / 10 : 0;
+			   (spots_ > kSpotsEnough) ? std::abs(management_data.get_military_number_at(74)) / 8 : 0;
 			inputs[18] = management_data.get_military_number_at(98) / 10;
 			inputs[19] = (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) ?
 			                -1 * std::abs(management_data.get_military_number_at(40)) / 10 :
@@ -5592,7 +5606,7 @@
 			inputs[32] = bo.max_needed_preciousness / 2;
 			inputs[33] = -(bo.cnt_under_construction + bo.unoccupied_count) * 4;
 			if (bo.cnt_built > 0 && !bo.outputs.empty() && !bo.inputs.empty()) {
-				inputs[34] += bo.current_stats / 10;
+				inputs[34] += bo.current_stats / std::abs(management_data.get_military_number_at(192)) * 10;
 			}
 			inputs[35] = (!bo.outputs.empty() && !bo.inputs.empty() &&
 			              bo.current_stats > 10 + 70 / bo.outputs.size()) ?
@@ -5703,6 +5717,14 @@
 				inputs[105] = -2;
 				inputs[106] = -2;
 			}
+			inputs[107] = std::abs(management_data.get_military_number_at(194)) - get_stocklevel(bo, gametime);
+			inputs[108] = std::abs(management_data.get_military_number_at(191)) - get_stocklevel(bo, gametime);
+			inputs[109] = (!bo.inputs.empty() && gametime > 50 * 60 * 1000 && bo.total_count() <= 1) ?
+			                 std::abs(management_data.get_military_number_at(163)) / 10 : 0;
+			// inputs[110] = (bo.outputs.size() == 1) ?
+			                 // (tribe_->get_ware_descr(bo.outputs.at(1))->default_target_quantity(tribe_->name()) -
+			                 // get_stocklevel(bo, gametime)) * std::abs(management_data.get_military_number_at(165)) / 20 : 0;
+			inputs[111] = bo.current_stats / (bo.outputs.size() + 1);
 
 			int16_t tmp_score = 0;
 			for (uint8_t i = 0; i < kFNeuronBitSize; ++i) {


Follow ups