← Back to team overview

widelands-dev team mailing list archive

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

 

cghislai has proposed merging lp:~widelands-dev/widelands/storages_garrisons into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

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

I'm not finished working on it yet, but I already put it on review so you can check changes and suggest design changes.

This is a refactoring in order to separate storages (entities storing wares/workers) from the warehouse class and garrisons (entities storing soldiers with control) from the militarysites/trainingsites.

I try to commit only playable revisions. Please note that post-b17 savegames may not be compatible.
My plan is to move portdock stuff out of warehouse class and add a an optional garrison on warehouses for headquarters.
-- 
https://code.launchpad.net/~widelands-dev/widelands/storages_garrisons/+merge/178704
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/storages_garrisons into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.cc	2013-08-06 10:09:46 +0000
@@ -72,7 +72,7 @@
 	next_attack_consideration_due(300000),
 	inhibit_road_building        (0),
 	time_of_last_construction    (0),
-	numof_warehouses             (0)
+	numof_storages               (0)
 {}
 
 DefaultAI::~DefaultAI()
@@ -577,7 +577,7 @@
 
 					if (v > 0)
 						field.military_influence +=
-							v * v * militarysite->soldierCapacity();
+							v * v * militarysite->get_garrison()->soldierCapacity();
 				}
 
 				if (dynamic_cast<const ProductionSite *>(building))
@@ -626,7 +626,7 @@
 
 					if (v > 0)
 						field.military_influence +=
-							v * v * militarysite->soldierCapacity();
+							v * v * militarysite->get_garrison()->soldierCapacity();
 				}
 			}
 		}
@@ -881,8 +881,8 @@
 					// Check if the produced wares are needed
 					Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
 					container_iterate(std::list<EconomyObserver *>, economies, l) {
-						// Don't check if the economy has no warehouse.
-						if ((*l.current)->economy.warehouses().empty())
+						// Don't check if the economy has no storage.
+						if ((*l.current)->economy.storages().empty())
 							continue;
 						if ((*l.current)->economy.needs_ware(wt))
 							prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
@@ -918,8 +918,8 @@
 					// the ware they're refreshing
 					Ware_Index wt(static_cast<size_t>(bo.production_hint));
 					container_iterate(std::list<EconomyObserver *>, economies, l) {
-						// Don't check if the economy has no warehouse.
-						if ((*l.current)->economy.warehouses().empty())
+						// Don't check if the economy has no storages.
+						if ((*l.current)->economy.storages().empty())
 							continue;
 						if ((*l.current)->economy.needs_ware(wt)) {
 							prio += wares.at(bo.production_hint).preciousness * inout * 2;
@@ -964,8 +964,8 @@
 
 					// Check if the produced wares are needed
 					container_iterate(std::list<EconomyObserver *>, economies, l) {
-						// Don't check if the economy has no warehouse.
-						if ((*l.current)->economy.warehouses().empty())
+						// Don't check if the economy has no storages.
+						if ((*l.current)->economy.storages().empty())
 							continue;
 						for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
 							Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
@@ -1056,7 +1056,7 @@
 				//  needed for soldier training) near the frontier.
 				prio += productionsites.size() + mines.size();
 				prio += militarysites.size() / 3;
-				prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
+				prio -= (bo.cnt_under_construction + numof_storages) * 35;
 				prio *= 2;
 
 				// take care about borders and enemies
@@ -1880,13 +1880,13 @@
 
 	if (map.find_fields(Area<FCoords>(f, vision), 0, find_unowned) == 0) {
 		// If no enemy in sight - decrease the number of stationed soldiers
-		// as long as it is > 1 - BUT take care that there is a warehouse in the
+		// as long as it is > 1 - BUT take care that there is a storage in the
 		// same economy where the thrown out soldiers can go to.
-		if (ms->economy().warehouses().size()) {
-			uint32_t const j = ms->soldierCapacity();
-			if (MilitarySite::kPrefersRookies != ms->get_soldier_preference())
+		if (ms->economy().storages().size()) {
+			uint32_t const j = ms->get_garrison()->soldierCapacity();
+			if (Garrison::SoldierPref::Rookies != ms->get_garrison()->get_soldier_preference())
 			{
-					game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersRookies);
+					game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Rookies);
 			}
 			else
 			if (j > 1)
@@ -1912,7 +1912,7 @@
 						// the destruction of the flag avoids that defaultAI will have
 						// too many unused roads - if needed the road will be rebuild
 						// directly.
-						if (static_cast<int32_t>(ms->maxSoldierCapacity() * 4) < bf.military_influence) {
+						if (static_cast<int32_t>(ms->get_garrison()->maxSoldierCapacity() * 4) < bf.military_influence) {
 							if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {
 								flags_to_be_removed.push_back(ms->base_flag().get_position());
 								game().send_player_dismantle(*ms);
@@ -1964,12 +1964,12 @@
 	} else {
 		// If an enemy is in sight and the number of stationed soldier is not
 		// at maximum - set it to maximum.
-		uint32_t const j = ms->maxSoldierCapacity();
-		uint32_t const k = ms->soldierCapacity();
+		uint32_t const j = ms->get_garrison()->maxSoldierCapacity();
+		uint32_t const k = ms->get_garrison()->soldierCapacity();
 		if (j > k)
 			game().send_player_change_soldier_capacity(*ms, j - k);
-		if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())
-			game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes);
+		if (Garrison::SoldierPref::Heroes != ms->get_garrison()->get_soldier_preference())
+			game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Heroes);
 		changed = true;
 	}
 	reorder:;
@@ -2182,7 +2182,7 @@
 			militarysites.back().bo = &bo;
 			militarysites.back().checks = bo.desc->get_size();
 		} else if (bo.type == BuildingObserver::WAREHOUSE)
-			++numof_warehouses;
+			++numof_storages;
 	}
 }
 
@@ -2244,8 +2244,8 @@
 					break;
 				}
 		} else if (bo.type == BuildingObserver::WAREHOUSE) {
-			assert(numof_warehouses > 0);
-			--numof_warehouses;
+			assert(numof_storages > 0);
+			--numof_storages;
 		}
 	}
 	m_buildable_changed = true;
@@ -2310,41 +2310,28 @@
 	map.find_immovables
 		(Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
 
-	for (uint32_t j = 0; j < immovables.size(); ++j)
-		if (upcast(MilitarySite, bld, immovables.at(j).object)) {
-			if (!player->is_hostile(bld->owner()))
-				continue;
-			if (bld->canAttack()) {
-				int32_t ta = player->findAttackSoldiers(bld->base_flag());
-				if (type == NORMAL)
-					ta = ta * 2 / 3;
-				if (ta < 1)
-					continue;
-
-				int32_t const tc = ta - bld->presentSoldiers().size();
-				if (tc > chance) {
-					target = bld;
-					chance = tc;
-					attackers = ta;
-				}
-			}
-		} else if (upcast(Warehouse, wh, immovables.at(j).object)) {
-			if (!player->is_hostile(wh->owner()))
-				continue;
-			if (wh->canAttack()) {
-				int32_t ta = player->findAttackSoldiers(wh->base_flag());
-				if (ta < 1)
-					continue;
-
-				// extra priority push!
-				int32_t tc = ta * 2;
-				if (tc > chance) {
-					target = wh;
-					chance = tc;
-					attackers = ta;
-				}
+	for (uint32_t j = 0; j < immovables.size(); ++j) {
+		if (upcast(GarrisonOwner, go, immovables.at(j).object)) {
+			if (!player->is_hostile(go->get_garrison()->owner())) {
+				continue;
+			}
+			if (!go->get_garrison()->canAttack()) {
+				continue;
+			}
+			int32_t ta = player->findAttackSoldiers(go->get_building()->base_flag());
+			if (type == NORMAL)
+				ta = ta * 2 / 3;
+			if (ta < 1)
+				continue;
+
+			int32_t const tc = ta - go->get_garrison()->presentSoldiers().size();
+			if (tc > chance) {
+				target = go->get_building();
+				chance = tc;
+				attackers = ta;
 			}
 		}
+	}
 
 	// Reenque militarysite at the end of list
 	militarysites.push_back(militarysites.front());

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.h	2013-08-06 10:09:46 +0000
@@ -191,7 +191,7 @@
 	int32_t inhibit_road_building;
 	int32_t time_of_last_construction;
 
-	uint16_t numof_warehouses;
+	uint16_t numof_storages;
 };
 
 #endif

=== modified file 'src/economy/economy.cc'
--- src/economy/economy.cc	2013-07-26 20:19:36 +0000
+++ src/economy/economy.cc	2013-08-06 10:09:46 +0000
@@ -27,11 +27,10 @@
 #include "economy/route.h"
 #include "economy/routeastar.h"
 #include "economy/router.h"
-#include "economy/warehousesupply.h"
 #include "logic/game.h"
 #include "logic/player.h"
+#include "logic/storage.h"
 #include "logic/tribe.h"
-#include "logic/warehouse.h"
 #include "upcast.h"
 #include "wexception.h"
 
@@ -78,8 +77,8 @@
 		log("Warning: Economy still has requests left on destruction\n");
 	if (m_flags.size())
 		log("Warning: Economy still has flags left on destruction\n");
-	if (m_warehouses.size())
-		log("Warning: Economy still has warehouses left on destruction\n");
+	if (m_storages.size())
+		log("Warning: Economy still has storages left on destruction\n");
 
 	delete[] m_ware_target_quantities;
 	delete[] m_worker_target_quantities;
@@ -214,22 +213,22 @@
 };
 
 /**
- * Find the warehouse closest to the given starting flag.
+ * Find the storage owner closest to the given starting flag.
  *
  * If the search was successful and \p route is non-null,
  * a route is also computed.
  *
  * \param start starting flag
  * \param type whether to path-find as if the path were for a ware
- * \param route if non-null, fill in a route to the warehouse
+ * \param route if non-null, fill in a route to the storage
  * \param cost_cutoff if positive, find paths of at most
  * that length (in milliseconds)
  */
-Warehouse * Economy::find_closest_warehouse
+StorageOwner* Economy::find_closest_storage
 	(Flag & start, WareWorker type, Route * route, uint32_t cost_cutoff,
-	 const Economy::WarehouseAcceptFn & acceptfn)
+	 const Economy::StorageAcceptFn & acceptfn)
 {
-	if (!warehouses().size())
+	if (!storages().size())
 		return 0;
 
 	// A-star with zero estimator = Dijkstra
@@ -243,11 +242,11 @@
 			return 0;
 
 		Flag & flag = current->base_flag();
-		if (upcast(Warehouse, warehouse, flag.get_building())) {
-			if (!acceptfn || acceptfn(*warehouse)) {
+		if (upcast(StorageOwner, storage_owner, flag.get_building())) {
+			if (!acceptfn || acceptfn(storage_owner)) {
 				if (route)
 					astar.routeto(flag, *route);
-				return warehouse;
+				return storage_owner;
 			}
 		}
 	}
@@ -368,7 +367,7 @@
 
 /**
  * Call this whenever a ware is destroyed or consumed, e.g. food has been
- * eaten or a warehouse has been destroyed.
+ * eaten or a storage has been destroyed.
  * This is also called when a ware is removed from the economy through trade or
  * a split of the Economy.
 */
@@ -397,32 +396,32 @@
 }
 
 /**
- * Add the warehouse to our list of warehouses.
- * This also adds the wares in the warehouse to the economy. However, if wares
- * are added to the warehouse in the future, add_wares() must be called.
+ * Add the storage to our list of storages.
+ * This also adds the wares in the storage to the economy. However, if wares
+ * are added to the storage in the future, add_wares() must be called.
 */
-void Economy::add_warehouse(Warehouse & wh)
+void Economy::add_storage(Storage & storage)
 {
-	m_warehouses.push_back(&wh);
+	m_storages.push_back(&storage);
 }
 
 /**
- * Remove the warehouse and its wares from the economy.
+ * Remove the storage and its wares from the economy.
 */
-void Economy::remove_warehouse(Warehouse & wh)
+void Economy::remove_storage(Storage & storage)
 {
-	for (size_t i = 0; i < m_warehouses.size(); ++i)
-		if (m_warehouses[i] == &wh) {
-			m_warehouses[i] = *m_warehouses.rbegin();
-			m_warehouses.pop_back();
+	for (size_t i = 0; i < m_storages.size(); ++i)
+		if (m_storages[i] == &storage) {
+			m_storages[i] = *m_storages.rbegin();
+			m_storages.pop_back();
 			return;
 		}
 
 
-	//  This assert was modified, since on loading, warehouses might try to
+	//  This assert was modified, since on loading, storages might try to
 	//  remove themselves from their own economy, though they weren't added
 	//  (since they weren't initialized)
-	assert(m_warehouses.empty());
+	assert(m_storages.empty());
 }
 
 /**
@@ -495,8 +494,8 @@
 bool Economy::needs_ware(Ware_Index const ware_type) const {
 	uint32_t const t = ware_target_quantity(ware_type).permanent;
 	uint32_t quantity = 0;
-	container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
-		quantity += (*wh)->get_wares().stock(ware_type);
+	container_iterate_const(std::vector<Storage *>, m_storages, storage) {
+		quantity += (*storage)->get_wares().stock(ware_type);
 		if (t <= quantity)
 			return false;
 	}
@@ -507,8 +506,8 @@
 bool Economy::needs_worker(Ware_Index const worker_type) const {
 	uint32_t const t = worker_target_quantity(worker_type).permanent;
 	uint32_t quantity = 0;
-	container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
-		quantity += (*wh)->get_workers().stock(worker_type);
+	container_iterate_const(std::vector<Storage *>, m_storages, storage) {
+		quantity += (*storage)->get_workers().stock(worker_type);
 		if (t <= quantity)
 			return false;
 	}
@@ -796,7 +795,7 @@
 
 /**
  * Check whether there is a supply for the given request. If the request is a
- * worker request without supply, attempt to create a new worker in a warehouse.
+ * worker request without supply, attempt to create a new worker in a storage.
  */
 void Economy::_create_requested_worker(Game & game, Ware_Index index)
 {
@@ -820,7 +819,7 @@
 		return;
 
 	// We have worker demand that is not fulfilled by supplies
-	// Find warehouses where we can create the required workers,
+	// Find storages where we can create the required workers,
 	// and collect stats about existing build prerequisites
 	const Tribe_Descr & tribe = owner().tribe();
 	const Worker_Descr & w_desc = *tribe.get_worker_descr(index);
@@ -830,20 +829,20 @@
 
 	total_available.insert(total_available.begin(), cost.size(), 0);
 
-	for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
-		Warehouse * wh = m_warehouses[n_wh];
+	for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+		Storage * storage = m_storages[storage_idx];
 
-		uint32_t planned = wh->get_planned_workers(game, index);
+		uint32_t planned = storage->get_planned_workers(game, index);
 		total_planned += planned;
 
-		while (wh->can_create_worker(game, index)) {
-			wh->create_worker(game, index);
+		while (storage->can_create_worker(game, index)) {
+			storage->create_worker(game, index);
 			if (!--demand)
 				return;
 		}
 
 		std::vector<uint32_t> wh_available =
-			wh->calc_available_for_worker(game, index);
+			storage->calc_available_for_worker(game, index);
 		assert(wh_available.size() == total_available.size());
 
 		for (uint32_t idx = 0; idx < total_available.size(); ++idx)
@@ -870,25 +869,25 @@
 		// there are supplies for (otherwise, cyclic transportation might happen)
 		// Note that supplies might suddenly disappear outside our control because
 		// of loss of land or silly player actions.
-		for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
-			Warehouse * wh = m_warehouses[n_wh];
+		for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+			Storage * storage = m_storages[storage_idx];
 
-			uint32_t planned = wh->get_planned_workers(game, index);
+			uint32_t planned = storage->get_planned_workers(game, index);
 			uint32_t reduce = std::min(planned, total_planned - can_create);
-			wh->plan_workers(game, index, planned - reduce);
+			storage->plan_workers(game, index, planned - reduce);
 			total_planned -= reduce;
 		}
 	} else if (total_planned < demand) {
 		uint32_t plan_goal = std::min(can_create, demand);
 
-		for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
-			Warehouse * wh = m_warehouses[n_wh];
+		for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+			Storage * storage = m_storages[storage_idx];
 			uint32_t supply =
-				wh->calc_available_for_worker(game, index)[scarcest_idx];
+				storage->calc_available_for_worker(game, index)[scarcest_idx];
 
-			total_planned -= wh->get_planned_workers(game, index);
+			total_planned -= storage->get_planned_workers(game, index);
 			uint32_t plan = std::min(supply, plan_goal - total_planned);
-			wh->plan_workers(game, index, plan);
+			storage->plan_workers(game, index, plan);
 			total_planned += plan;
 		}
 	}
@@ -896,11 +895,11 @@
 
 /**
  * Walk all Requests and find requests of workers than aren't supplied. Then
- * try to create the worker at warehouses.
+ * try to create the worker at storages.
  */
 void Economy::_create_requested_workers(Game & game)
 {
-	if (!warehouses().size())
+	if (!storages().size())
 		return;
 
 	const Tribe_Descr & tribe = owner().tribe();
@@ -920,23 +919,23 @@
 /**
  * Helper function for \ref _handle_active_supplies
  */
-static bool accept_warehouse_if_policy
-	(Warehouse & wh, WareWorker type,
-	 Ware_Index ware, Warehouse::StockPolicy policy)
+static bool accept_storage_if_policy
+	(StorageOwner* storage, WareWorker type,
+	 Ware_Index ware, Storage::StockPolicy policy)
 {
-	return wh.get_stock_policy(type, ware) == policy;
+	return storage->get_storage()->get_stock_policy(type, ware) == policy;
 }
 
 /**
  * Send all active supplies (wares that are outside on the road network without
- * being sent to a specific request) to a warehouse.
+ * being sent to a specific request) to a storage.
  */
 void Economy::_handle_active_supplies(Game & game)
 {
-	if (!warehouses().size())
+	if (!storages().size())
 		return;
 
-	typedef std::vector<std::pair<Supply *, Warehouse *> > Assignments;
+	typedef std::vector<std::pair<Supply *, StorageOwner *> > Assignments;
 	Assignments assignments;
 
 	for (uint32_t idx = 0; idx < m_supplies.get_nrsupplies(); ++idx) {
@@ -950,38 +949,38 @@
 
 		bool haveprefer = false;
 		bool havenormal = false;
-		for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) {
-			Warehouse * wh = m_warehouses[nwh];
-			Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);
-			if (policy == Warehouse::SP_Prefer) {
+		for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
+			Storage * storage = m_storages[storage_idx];
+			Storage::StockPolicy policy = storage->get_stock_policy(type, ware);
+			if (policy == Storage::StockPolicy::Prefer) {
 				haveprefer = true;
 				break;
 			}
-			if (policy == Warehouse::SP_Normal)
+			if (policy == Storage::StockPolicy::Normal)
 				havenormal = true;
 		}
 		if (!havenormal && !haveprefer && type == wwWARE)
 			continue;
 
-		Warehouse * wh = find_closest_warehouse
+		StorageOwner * storage_owner = find_closest_storage
 			(supply.get_position(game)->base_flag(), type, 0, 0,
 			 (!haveprefer && !havenormal)
 			 ?
-			 WarehouseAcceptFn()
+			 StorageAcceptFn()
 			 :
 			 boost::bind
-				(&accept_warehouse_if_policy,
+				(&accept_storage_if_policy,
 				 _1, type, ware,
-				 haveprefer ? Warehouse::SP_Prefer : Warehouse::SP_Normal));
+				 haveprefer ? Storage::StockPolicy::Prefer : Storage::StockPolicy::Normal));
 
-		if (!wh) {
+		if (!storage_owner) {
 			log
 				("Warning: Economy::_handle_active_supplies "
-				 "didn't find warehouse\n");
+				 "didn't find storage\n");
 			return;
 		}
 
-		assignments.push_back(std::make_pair(&supply, wh));
+		assignments.push_back(std::make_pair(&supply, storage_owner));
 	}
 
 	// Actually start with the transfers in a separate second phase,
@@ -991,10 +990,10 @@
 	ss.Unsigned32(0x02decafa); // appears as facade02 in sync stream
 	ss.Unsigned32(assignments.size());
 
+	// FIXME CGH check thats working
 	container_iterate_const(Assignments, assignments, it) {
 		ss.Unsigned32(it.current->first->get_position(game)->serial());
-		ss.Unsigned32(it.current->second->serial());
-
+		ss.Unsigned32(it.current->second->get_building()->serial());
 		it.current->first->send_to_storage(game, it.current->second);
 	}
 }

=== modified file 'src/economy/economy.h'
--- src/economy/economy.h	2013-07-26 20:19:36 +0000
+++ src/economy/economy.h	2013-08-06 10:09:46 +0000
@@ -34,12 +34,15 @@
 
 
 namespace Widelands {
+
+class StorageOwner;
+
+class Storage;
 struct Player;
 struct Game;
 struct Flag;
 struct Route;
 struct RSPairStruct;
-class Warehouse;
 struct Request;
 struct Supply;
 struct Router;
@@ -102,11 +105,11 @@
 		 WareWorker type,
 		 int32_t cost_cutoff = -1);
 
-	typedef boost::function<bool (Warehouse &)> WarehouseAcceptFn;
-	Warehouse * find_closest_warehouse
+	typedef boost::function<bool (StorageOwner *)> StorageAcceptFn;
+	StorageOwner * find_closest_storage
 		(Flag & start, WareWorker type = wwWORKER, Route * route = 0,
 		 uint32_t cost_cutoff = 0,
-		 const WarehouseAcceptFn & acceptfn = WarehouseAcceptFn());
+		 const StorageAcceptFn & acceptfn = StorageAcceptFn());
 
 	std::vector<Flag *>::size_type get_nrflags() const {return m_flags.size();}
 	void    add_flag(Flag &);
@@ -122,9 +125,9 @@
 	void    add_workers(Ware_Index, uint32_t count = 1);
 	void remove_workers(Ware_Index, uint32_t count = 1);
 
-	void    add_warehouse(Warehouse &);
-	void remove_warehouse(Warehouse &);
-	const std::vector<Warehouse *>& warehouses() const {return m_warehouses;}
+	void    add_storage(Storage &);
+	void remove_storage(Storage &);
+	const std::vector<Storage *>& storages() const {return m_storages;}
 
 	void    add_request(Request &);
 	void remove_request(Request &);
@@ -208,7 +211,7 @@
 	Flags m_flags;
 	WareList m_wares;     ///< virtual storage with all wares in this Economy
 	WareList m_workers;   ///< virtual storage with all workers in this Economy
-	std::vector<Warehouse *> m_warehouses;
+	std::vector<Storage *> m_storages;
 
 	RequestList m_requests; ///< requests
 	SupplyList m_supplies;

=== modified file 'src/economy/idleworkersupply.cc'
--- src/economy/idleworkersupply.cc	2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.cc	2013-08-06 10:09:46 +0000
@@ -25,8 +25,8 @@
 #include "logic/player.h"
 #include "logic/requirements.h"
 #include "logic/soldier.h"
+#include "logic/storage.h"
 #include "logic/tribe.h"
-#include "logic/warehouse.h"
 #include "logic/worker.h"
 #include "wexception.h"
 
@@ -126,12 +126,12 @@
 	return m_worker;
 }
 
-void IdleWorkerSupply::send_to_storage(Game & game, Warehouse * wh)
+void IdleWorkerSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
 {
 	assert(!has_storage());
 
 	Transfer * t = new Transfer(game, m_worker);
-	t->set_destination(*wh);
+	t->set_destination(*storage_owner->get_building());
 	m_worker.start_task_transfer(game, t);
 }
 

=== modified file 'src/economy/idleworkersupply.h'
--- src/economy/idleworkersupply.h	2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.h	2013-08-06 10:09:46 +0000
@@ -23,6 +23,8 @@
 #include "economy/supply.h"
 
 namespace Widelands {
+
+class StorageOwner;
 class Worker;
 class Economy;
 
@@ -36,7 +38,7 @@
 	virtual bool is_active() const throw ();
 	virtual bool has_storage() const throw ();
 	virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
-	virtual void send_to_storage(Game &, Warehouse * wh);
+	virtual void send_to_storage(Game &, StorageOwner * storage_owner);
 
 	virtual uint32_t nr_supplies(const Game &, const Request &) const;
 	virtual WareInstance & launch_item(Game &, const Request &);

=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc	2013-07-26 20:19:36 +0000
+++ src/economy/portdock.cc	2013-08-06 10:09:46 +0000
@@ -488,7 +488,7 @@
 	// Put all wares from the WaresQueues back into the warehouse
 	const std::vector<WaresQueue *> & l_expedition_wares = m_warehouse->get_wares_queue_vector();
 	for (uint8_t i = 0; i < l_expedition_wares.size(); ++i) {
-		m_warehouse->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
+		m_warehouse->get_storage()->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
 		l_expedition_wares.at(i)->set_filled(0);
 		l_expedition_wares.at(i)->set_max_fill(0);
 	}
@@ -501,7 +501,7 @@
 		} else {
 			Worker * temp = ew.at(i)->worker;
 			ew.at(i)->worker = 0;
-			m_warehouse->incorporate_worker(game, *temp);
+			m_warehouse->get_storage()->incorporate_worker(game, *temp);
 		}
 	}
 	// Reset expedition workers list

=== modified file 'src/economy/request.cc'
--- src/economy/request.cc	2013-07-26 20:19:36 +0000
+++ src/economy/request.cc	2013-08-06 10:09:46 +0000
@@ -28,8 +28,8 @@
 #include "logic/player.h"
 #include "logic/productionsite.h"
 #include "logic/soldier.h"
+#include "logic/storage.h"
 #include "logic/tribe.h"
-#include "logic/warehouse.h"
 #include "logic/worker.h"
 #include "map_io/widelands_map_map_object_loader.h"
 #include "map_io/widelands_map_map_object_saver.h"
@@ -50,22 +50,27 @@
 	(PlayerImmovable & _target,
 	 Ware_Index const index,
 	 callback_t const cbfn,
-	 WareWorker const w)
+	 WareWorker const w,
+	 callback_tranfert_t const transfer_cb)
 	:
 	m_type             (w),
 	m_target           (_target),
 	m_target_building  (dynamic_cast<Building *>(&_target)),
 	m_target_productionsite  (dynamic_cast<ProductionSite *>(&_target)),
-	m_target_warehouse (dynamic_cast<Warehouse *>(&_target)),
+	m_target_storage   (nullptr),
 	m_target_constructionsite (dynamic_cast<ConstructionSite *>(&_target)),
 	m_economy          (_target.get_economy()),
 	m_index            (index),
 	m_count            (1),
 	m_callbackfn       (cbfn),
+	m_transfer_cb      (transfer_cb),
 	m_required_time    (_target.owner().egbase().get_gametime()),
 	m_required_interval(0),
 	m_last_request_time(m_required_time)
 {
+	if (upcast(StorageOwner, storage_owner, &_target)) {
+		m_target_storage = storage_owner->get_storage();
+	}
 	assert(m_type == wwWARE or m_type == wwWORKER);
 	if (w == wwWARE and _target.owner().tribe().get_nrwares() <= index)
 		throw wexception
@@ -354,8 +359,8 @@
 		modifier = m_target_building->get_priority(get_type(), get_index());
 		if (m_target_constructionsite)
 			is_construction_site = true;
-		else if (m_target_warehouse)
-			// if warehouse calculated a priority use it
+		else if (m_target_storage)
+			// if storage calculated a priority use it
 			// else lower priority based on cost
 			return
 				modifier != 100 ? modifier :
@@ -404,7 +409,7 @@
 		pri = m_target_building->get_priority(get_type(), get_index());
 		if (m_target_constructionsite)
 			return pri + 3;
-		else if (m_target_warehouse)
+		else if (m_target_storage)
 			return pri - 2;
 	}
 	return pri;
@@ -486,10 +491,13 @@
 		Worker & s = supp.launch_worker(game, *this);
 		ss.Unsigned32(s.serial());
 		t = new Transfer(game, *this, s);
+		if (m_transfer_cb) {
+			(*m_transfer_cb)(game, *this, m_index, &s, m_target);
+		}
 	} else {
 		//  Begin the transfer of an item. The item itself is passive.
 		//  launch_item() ensures the WareInstance is transported out of the
-		//  warehouse. Once it's on the flag, the flag code will decide what to
+		//  storage. Once it's on the flag, the flag code will decide what to
 		//  do with it.
 		WareInstance & item = supp.launch_item(game, *this);
 		ss.Unsigned32(item.serial());
@@ -533,7 +541,7 @@
  *
  * Re-open the request.
 */
-void Request::transfer_fail(Game &, Transfer & t) {
+void Request::transfer_fail(Game & game, Transfer & t) {
 	bool const wasopen = is_open();
 
 	t.m_worker = 0;
@@ -541,8 +549,12 @@
 
 	remove_transfer(find_transfer(t));
 
-	if (!wasopen)
+	if (!wasopen) {
 		m_economy->add_request(*this);
+	}
+	if (m_transfer_cb) {
+		m_transfer_cb(game, *this, m_index, nullptr, m_target);
+	}
 }
 
 /// Cancel the transfer with the given index.

=== modified file 'src/economy/request.h'
--- src/economy/request.h	2013-07-25 21:05:20 +0000
+++ src/economy/request.h	2013-08-06 10:09:46 +0000
@@ -20,6 +20,8 @@
 #ifndef REQUEST_H
 #define REQUEST_H
 
+#include <functional>
+
 #include "logic/requirements.h"
 #include "logic/wareworker.h"
 #include "logic/widelands.h"
@@ -39,11 +41,11 @@
 class RequestList;
 struct Requirements;
 struct Supply;
+class Storage;
 struct Transfer;
 class Worker;
 class Building;
 class ProductionSite;
-class Warehouse;
 class ConstructionSite;
 
 /**
@@ -63,8 +65,12 @@
 
 	typedef void (*callback_t)
 		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+	typedef void (*callback_tranfert_t)
+		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
 
-	Request(PlayerImmovable & target, Ware_Index, callback_t, WareWorker);
+	Request
+		(PlayerImmovable & target, Ware_Index, callback_t, WareWorker,
+		 callback_tranfert_t transfer_cb = nullptr);
 	~Request();
 
 	PlayerImmovable & target() const throw () {return m_target;}
@@ -120,7 +126,7 @@
 	//  are filled with nulls.
 	Building        * m_target_building;
 	ProductionSite  * m_target_productionsite;
-	Warehouse       * m_target_warehouse;
+	Storage         * m_target_storage;
 	ConstructionSite * m_target_constructionsite;
 
 	Economy         * m_economy;
@@ -128,6 +134,7 @@
 	uint32_t          m_count;             //  how many do we need in total
 
 	callback_t        m_callbackfn;        //  called on request success
+	callback_tranfert_t m_transfer_cb; // called on worker transfer start/cancel
 
 	//  when do we need the first ware (can be in the past)
 	int32_t           m_required_time;

=== modified file 'src/economy/supply.h'
--- src/economy/supply.h	2013-07-26 19:16:51 +0000
+++ src/economy/supply.h	2013-08-06 10:09:46 +0000
@@ -25,10 +25,12 @@
 
 namespace Widelands {
 
+class StorageOwner;
+
 struct PlayerImmovable;
 struct Game;
 struct Request;
-class Warehouse;
+class StorageOwner;
 struct Ware_Index;
 class WareInstance;
 class Worker;
@@ -77,7 +79,7 @@
 	 * Sets up all the required transfers; assumes that \ref has_storage
 	 * returns \c false.
 	 */
-	virtual void send_to_storage(Game &, Warehouse * wh) = 0;
+	virtual void send_to_storage(Game &, StorageOwner * storage_owner) = 0;
 
 	/**
 	 * \return the number of items or workers that can be launched right

=== modified file 'src/economy/transfer.cc'
--- src/economy/transfer.cc	2013-07-26 20:19:36 +0000
+++ src/economy/transfer.cc	2013-08-06 10:09:46 +0000
@@ -191,6 +191,7 @@
 		Flag & curflag(m_route.get_flag(m_game, 0));
 		Flag & nextflag(m_route.get_flag(m_game, 1));
 		if (!curflag.get_road(nextflag)) {
+			//FIXME CGH
 			upcast(Warehouse, wh, curflag.get_building());
 			assert(wh);
 

=== modified file 'src/economy/ware_instance.cc'
--- src/economy/ware_instance.cc	2013-07-26 20:19:36 +0000
+++ src/economy/ware_instance.cc	2013-08-06 10:09:46 +0000
@@ -27,8 +27,8 @@
 #include "economy/transfer.h"
 #include "logic/game.h"
 #include "logic/ship.h"
+#include "logic/storage.h"
 #include "logic/tribe.h"
-#include "logic/warehouse.h"
 #include "logic/worker.h"
 #include "map_io/widelands_map_map_object_loader.h"
 #include "map_io/widelands_map_map_object_saver.h"
@@ -54,7 +54,7 @@
 	virtual bool is_active() const throw ();
 	virtual bool has_storage() const throw ();
 	virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
-	virtual void send_to_storage(Game &, Warehouse * wh);
+	virtual void send_to_storage(Game &, StorageOwner * wh);
 
 	virtual uint32_t nr_supplies(const Game &, const Request &) const;
 	virtual WareInstance & launch_item(Game &, const Request &);
@@ -166,12 +166,12 @@
 	throw wexception("IdleWareSupply::launch_worker makes no sense");
 }
 
-void IdleWareSupply::send_to_storage(Game & game, Warehouse * wh)
+void IdleWareSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
 {
 	assert(!has_storage());
 
 	Transfer * t = new Transfer(game, m_ware);
-	t->set_destination(*wh);
+	t->set_destination(*storage_owner->get_building());
 	m_ware.set_transfer(game, *t);
 }
 
@@ -290,8 +290,8 @@
 
 /**
  * Performs the state updates necessary for the current location:
- * - if it's a building, acknowledge the Request or incorporate into warehouse
- * - if it's a flag and we have no request, start the return to warehouse timer
+ * - if it's a building, acknowledge the Request or incorporate into strage
+ * - if it's a flag and we have no request, start the return to storage timer
  * and issue a Supply
  *
  * \note \ref update() may result in the deletion of this object.
@@ -405,22 +405,22 @@
 				return;
 			}
 
-			// There are some situations where we might end up in a warehouse
+			// There are some situations where we might end up in a storage
 			// as part of a requested route, and we need to move out of it
 			// again, e.g.:
 			//  - we were requested just when we were being carried into the
-			//    warehouse
+			//    storage
 			//  - we were carried into a harbour/warehouse to be
 			//    shipped across the sea, but a better, land-based route has been
 			//    found
-			if (upcast(Warehouse, warehouse, &building)) {
-				warehouse->do_launch_item(game, *this);
+			if (upcast(StorageOwner, storage_owner, &building)) {
+				storage_owner->get_storage()->do_launch_ware(game, *this);
 				return;
 			}
 
 			throw wexception
 				("MO(%u): ware(%s): do not know how to move from building %u (%s at (%u,%u)) "
-				 "to %u (%s) -> not a warehouse!",
+				 "to %u (%s) -> not a storage owner!",
 				 serial(), m_descr->name().c_str(), building.serial(),
 				 building.name().c_str(), building.get_position().x,
 				 building.get_position().y, nextstep->serial(),

=== removed file 'src/economy/warehousesupply.h'
--- src/economy/warehousesupply.h	2013-07-26 20:19:36 +0000
+++ src/economy/warehousesupply.h	1970-01-01 00:00:00 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2008-2010 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef WAREHOUSESUPPLY_H
-#define WAREHOUSESUPPLY_H
-
-#include "logic/warelist.h"
-#include "logic/wareworker.h"
-#include "economy/supply.h"
-
-namespace Widelands {
-
-/*
-WarehouseSupply is the implementation of Supply that is used by Warehouses.
-It also manages the list of wares in the warehouse.
-*/
-struct WarehouseSupply : public Supply {
-	WarehouseSupply(Warehouse * const wh) : m_economy(0), m_warehouse(wh) {}
-	virtual ~WarehouseSupply();
-
-	void set_economy(Economy *);
-
-	void set_nrworkers(Ware_Index);
-	void set_nrwares  (Ware_Index);
-
-	const WareList & get_wares  () const {return m_wares;}
-	const WareList & get_workers() const {return m_workers;}
-	uint32_t stock_wares  (Ware_Index const i) const {
-		return m_wares  .stock(i);
-	}
-	uint32_t stock_workers(Ware_Index const i) const {
-		return m_workers.stock(i);
-	}
-	void add_wares     (Ware_Index, uint32_t count);
-	void remove_wares  (Ware_Index, uint32_t count);
-	void add_workers   (Ware_Index, uint32_t count);
-	void remove_workers(Ware_Index, uint32_t count);
-
-	// Supply implementation
-	virtual PlayerImmovable * get_position(Game &);
-	virtual bool is_active() const throw ();
-	virtual bool has_storage() const throw ();
-	virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
-
-	virtual void send_to_storage(Game &, Warehouse * wh);
-	virtual uint32_t nr_supplies(const Game &, const Request &) const;
-	virtual WareInstance & launch_item(Game &, const Request &);
-	virtual Worker & launch_worker(Game &, const Request &);
-
-private:
-	Economy   * m_economy;
-	WareList    m_wares;
-	WareList    m_workers; //  we use this to keep the soldiers
-	Warehouse * m_warehouse;
-};
-
-}
-
-
-#endif

=== removed file 'src/logic/attackable.h'
--- src/logic/attackable.h	2012-02-15 21:25:34 +0000
+++ src/logic/attackable.h	1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008-2009 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef ATTACKABLE_H
-#define ATTACKABLE_H
-
-namespace Widelands {
-
-struct Player;
-class Soldier;
-
-enum {
-	/**
-	 * This is the maximum radius that a military building can protect
-	 * in the sense that an enemy soldier that enters the player's territory
-	 * will call \ref Attackable::aggressor if it is that close.
-	 */
-	MaxProtectionRadius = 25
-};
-
-/**
- * Buildings can implement this interface to indicate that
- * they can be attacked.
- */
-struct Attackable {
-	/**
-	 * Return the player that owns this attackable.
-	 */
-	virtual Player & owner() const = 0;
-
-	/**
-	 * Determines whether this building can be attacked right now.
-	 *
-	 * This should only return false for military sites that have not
-	 * been occupied yet.
-	 */
-	virtual bool canAttack() = 0;
-
-	/**
-	 * Called by an enemy soldier that enters a node with distance
-	 * less than or equal to \ref MaxProtectionRadius from the building.
-	 *
-	 * This allows the building to send protective forces to intercept
-	 * the soldier.
-	 */
-	virtual void aggressor(Soldier &) = 0;
-
-	/**
-	 * Called by a soldier who is standing on the building's flag
-	 * to attack the building.
-	 *
-	 * The building must send a soldier for defense, and return \c true.
-	 * Otherwise, i.e. if the building cannot defend itself anymore,
-	 * it must destroy itself or turn over to the attacking player,
-	 * and return \c false.
-	 *
-	 * \return \c true if a soldier was launched in defense of the building,
-	 * or \c false if the building cannot defend itself any longer.
-	 */
-	virtual bool attack(Soldier &) = 0;
-
-protected:
-	virtual ~Attackable() {}
-};
-
-}
-
-#endif

=== modified file 'src/logic/building.h'
--- src/logic/building.h	2013-08-02 18:36:03 +0000
+++ src/logic/building.h	2013-08-06 10:09:46 +0000
@@ -258,6 +258,9 @@
 	void set_defeating_player(Player_Number const player_number) {
 		m_defeating_player = player_number;
 	}
+	Player_Number get_defeating_player() {
+		return m_defeating_player;
+	}
 
 	void    add_worker(Worker &);
 	void remove_worker(Worker &);

=== modified file 'src/logic/findimmovable.cc'
--- src/logic/findimmovable.cc	2013-07-26 20:19:36 +0000
+++ src/logic/findimmovable.cc	2013-08-06 10:09:46 +0000
@@ -20,7 +20,6 @@
 #include "logic/findimmovable.h"
 
 #include "economy/flag.h"
-#include "logic/attackable.h"
 #include "logic/immovable.h"
 #include "logic/militarysite.h"
 #include "upcast.h"
@@ -61,7 +60,8 @@
 }
 
 bool FindImmovableAttackable        ::accept(const BaseImmovable & imm) const {
-	return dynamic_cast<Attackable const *>(&imm);
+	upcast(const GarrisonOwner, go, &imm);
+	return (go && go->get_garrison()->canAttack());
 }
 
 bool FindImmovableByDescr::accept(const BaseImmovable & baseimm) const {

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2013-07-26 20:19:36 +0000
+++ src/logic/game.cc	2013-08-06 10:09:46 +0000
@@ -792,7 +792,8 @@
 		 	(get_gametime(), building.owner().player_number(), building));
 }
 
-void Game::send_player_militarysite_set_soldier_preference (Building & building, uint8_t my_preference)
+void Game::send_player_militarysite_set_soldier_preference
+	(Building & building, Garrison::SoldierPref my_preference)
 {
 	send_player_command
 		(*new Cmd_MilitarySiteSetSoldierPreference

=== modified file 'src/logic/game.h'
--- src/logic/game.h	2013-07-26 20:19:36 +0000
+++ src/logic/game.h	2013-08-06 10:09:46 +0000
@@ -22,6 +22,7 @@
 
 #include "logic/cmd_queue.h"
 #include "logic/editor_game_base.h"
+#include "logic/garrison.h"
 #include "md5.h"
 #include "random.h"
 #include "save_handler.h"
@@ -151,7 +152,7 @@
 	void send_player_build_road (int32_t, Path &);
 	void send_player_flagaction (Flag &);
 	void send_player_start_stop_building (Building &);
-	void send_player_militarysite_set_soldier_preference (Building &, uint8_t preference);
+	void send_player_militarysite_set_soldier_preference (Building &, Garrison::SoldierPref preference);
 	void send_player_start_or_cancel_expedition    (Building &);
 
 	void send_player_enhance_building (Building &, Building_Index);

=== added file 'src/logic/garrison.h'
--- src/logic/garrison.h	1970-01-01 00:00:00 +0000
+++ src/logic/garrison.h	2013-08-06 10:09:46 +0000
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2008-2009 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef GARRISON_H
+#define GARRISON_H
+
+#include <vector>
+
+#include "logic/widelands.h"
+
+namespace Widelands {
+
+
+class Building;
+class Editor_Game_Base;
+class Game;
+struct Player;
+class Soldier;
+
+enum {
+	/**
+	 * This is the maximum radius that a military building can protect
+	 * in the sense that an enemy soldier that enters the player's territory
+	 * will call \ref Attackable::aggressor if it is that close.
+	 */
+	MaxProtectionRadius = 25
+};
+
+/**
+ * A garrison represents a bunch of soldiers. Garrisons are owned by GarrisonOwner
+ * buildings. This interface provides various methods to deal with soldier control
+ * and attacks.
+ */
+class Garrison {
+public:
+	enum SoldierPref  : uint8_t {
+		None,
+		Rookies,
+		Heroes,
+	};
+	/**
+	 * Return the player that owns this attackable.
+	 */
+	virtual Player & owner() const = 0;
+
+	/**
+	 * Determines whether this building can be attacked right now.
+	 *
+	 * This should only return false for military sites that have not
+	 * been occupied yet, or by passivve garrison such as training sites.
+	 */
+	virtual bool canAttack() const = 0;
+
+	/**
+	 * Called by an enemy soldier that enters a node with distance
+	 * less than or equal to \ref MaxProtectionRadius from the building.
+	 *
+	 * This allows the building to send protective forces to intercept
+	 * the soldier.
+	 */
+	virtual void aggressor(Soldier &) = 0;
+
+	/**
+	 * Called by a soldier who is standing on the building's flag
+	 * to attack the building.
+	 *
+	 * The building must send a soldier for defense, and return \c true.
+	 * Otherwise, i.e. if the building cannot defend itself anymore,
+	 * it must destroy itself or turn over to the attacking player,
+	 * and return \c false.
+	 *
+	 * \return \c true if a soldier was launched in defense of the building,
+	 * or \c false if the building cannot defend itself any longer.
+	 */
+	virtual bool attack(Soldier &) = 0;
+
+	/**
+	 * \return a list of soldiers that are currently present in the building.
+	 */
+	virtual const std::vector<Soldier *> presentSoldiers() const = 0;
+
+	/**
+	 * \return a list of soldiers that are currently stationed in the building.
+	 * That is, all soldiers occupying a slot in the garrison.
+	 */
+	virtual const std::vector<Soldier *> stationedSoldiers() const = 0;
+
+	/**
+	 * \return the minimum number of soldiers that this building can be
+	 * configured to hold.
+	 */
+	virtual uint32_t minSoldierCapacity() const = 0;
+
+	/**
+	 * \return the maximum number of soldiers that this building can be
+	 * configured to hold.
+	 */
+	virtual uint32_t maxSoldierCapacity() const = 0;
+
+	/**
+	 * \return the number of soldiers this building is configured to hold
+	 * right now.
+	 */
+	virtual uint32_t soldierCapacity() const = 0;
+
+	/**
+	 * Sets the capacity for soldiers of this building.
+	 *
+	 * New soldiers will be requested and old soldiers will be evicted
+	 * as necessary.
+	 */
+	virtual void setSoldierCapacity(uint32_t capacity) = 0;
+	void changeSoldierCapacity(int32_t const difference) {
+		uint32_t const old_capacity = soldierCapacity();
+		uint32_t const new_capacity =
+			std::min
+				(static_cast<uint32_t>
+				 	(std::max
+				 	 	(static_cast<int32_t>(old_capacity) + difference,
+				 	 	 static_cast<int32_t>(minSoldierCapacity()))),
+				 static_cast<uint32_t>(maxSoldierCapacity()));
+		if (old_capacity != new_capacity)
+			setSoldierCapacity(new_capacity);
+	}
+	/**
+	 * Evict the given soldier from the building immediately,
+	 * without changing the building's capacity.
+	 *
+	 * \note This has no effect if the soldier is currently involved in a battle
+	 * or otherwise blocked from leaving the building.
+	 */
+	virtual void dropSoldier(Soldier &) = 0;
+
+	/**
+	 * Add a new soldier into this site. Returns -1 if there is no space
+	 * for him, 0 on success
+	 */
+	virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
+
+	/**
+	 * Remove a soldier from the internal list. Most SoldierControls will be
+	 * informed by the soldier when it is removed, but WareHouses for example
+	 * will not.
+	 */
+	virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
+
+	/**
+	 * Returns the conquer radius of this garrison
+	 */
+	virtual uint32_t conquerRadius() const = 0;
+	/**
+	 * Set the soldier preference. Heroes or rookies?
+	 */
+	virtual void set_soldier_preference(SoldierPref p) = 0;
+	/**
+	 * \return the current soldier preference
+	 */
+	virtual SoldierPref get_soldier_preference() const = 0;
+	/**
+	 * Try to send the given soldier to attack the fiven target building.
+	 * This will fail if the soldier already has a job.
+	 */
+	virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat) = 0;
+};
+
+
+/**
+ * A Garrison owner holds a garrison. This interface is to be implemented by
+ * buildings that want to store some soldiers. The GarrionHandler Garrison
+ * implementation may be used as the Garrison provider.
+ */
+class GarrisonOwner {
+public:
+	/**
+	 * \return the garrison instance
+	 */
+	virtual Garrison* get_garrison() const = 0;
+	/**
+	 * @return the building owning the garrison
+	 */
+	virtual Building* get_building() = 0;
+	/**
+	 * Called when the garrison has been lost. \param defeating is set to the
+	 * enemy owner, or this owner if we keep military presence. if \param captured,
+	 * the enemy captured the building and a new one must be force built.
+	 *
+	 * Will not be called by passive garrisons
+	 */
+	virtual void garrison_lost(Game & game, Player_Number defeating, bool captured) = 0;
+	/**
+	 * Called when the garrison is occupied. You may light up the fire now
+	 *
+	 * Will not be called by passive garrison
+	 */
+	virtual void garrison_occupied() = 0;
+	/**
+	 * Called on the new site when a site has been conquered
+	 *
+	 * Will not be called by passive garrison
+	 */
+	virtual void reinit_after_conqueral(Game & game) = 0;
+};
+
+}
+
+#endif

=== added file 'src/logic/garrisonhandler.cc'
--- src/logic/garrisonhandler.cc	1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.cc	2013-08-06 10:09:46 +0000
@@ -0,0 +1,869 @@
+/*
+* Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+*/
+
+#include "logic/garrisonhandler.h"
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
+#include "container_iterate.h"
+#include "economy/flag.h"
+#include "economy/request.h"
+#include "log.h"
+#include "logic/building.h"
+#include "logic/findbob.h"
+#include "logic/instances.h"
+#include "logic/militarysite.h"
+#include "logic/player.h"
+#include "logic/soldier.h"
+#include "upcast.h"
+
+namespace Widelands {
+
+GarrisonHandler::GarrisonHandler
+	(Building& building, uint32_t min_soldiers, uint32_t max_soldiers, uint32_t conquer_radius,
+	uint32_t heal_per_second, SoldierPref soldier_pref, bool passive)
+: Garrison(),
+m_building(building),
+m_min_capacity(min_soldiers),
+m_max_capacity(max_soldiers),
+m_capacity(max_soldiers),
+m_passive(passive),
+m_heal_per_second(heal_per_second),
+m_last_heal_time(0),
+m_conquer_radius(conquer_radius),
+m_didconquer(false),
+m_soldier_preference(soldier_pref),
+m_last_swap_soldiers_time(0),
+m_try_soldier_upgrade(false),
+m_doing_upgrade_request(false)
+{
+	assert(is_a(GarrisonOwner, &m_building));
+}
+
+GarrisonHandler::~GarrisonHandler()
+{
+	assert(m_normal_soldier_request.get() == nullptr);
+	assert(m_upgrade_soldier_request.get() == nullptr);
+}
+
+void GarrisonHandler::init(Editor_Game_Base & egbase)
+{
+	// Ensure all soldiers are fresh and give them a new task
+	upcast(Game, game, &egbase);
+	container_iterate_const(std::vector<Worker *>, m_building.get_workers(), i) {
+		if (upcast(Soldier, soldier, *i.current)) {
+			soldier->set_location_initially(m_building);
+			assert(!soldier->get_state()); //  Should be newly created.
+			if (game) {
+				soldier->start_task_buildingwork(*game);
+			}
+		}
+	}
+	// Update requests and timers
+	update_soldier_request();
+	m_last_heal_time = egbase.get_gametime();
+}
+
+void GarrisonHandler::reinit_after_conqueral(Game& game)
+{
+	m_soldier_requirements = Requirements();
+	conquer_area(game);
+	update_soldier_request();
+}
+
+void GarrisonHandler::cleanup(Editor_Game_Base& egbase)
+{
+	if (m_didconquer && !m_passive) {
+		egbase.unconquer_area
+			(Player_Area<Area<FCoords> >
+				(owner().player_number(),
+					Area<FCoords>(egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)),
+		m_building.get_defeating_player());
+	}
+}
+
+void GarrisonHandler::cleanup_requests(Editor_Game_Base&)
+{
+	m_normal_soldier_request.reset();
+	m_upgrade_soldier_request.reset();
+}
+
+
+void GarrisonHandler::act(Game& game)
+{
+	const int32_t timeofgame = game.get_gametime();
+	// Ensure requests integrity
+	if (m_normal_soldier_request && m_upgrade_soldier_request)
+	{
+		throw wexception("GarrisonHandler::act: Two soldier requests are ongoing -- should never happen!\n");
+	}
+	// Update requests periodically
+	bool full = stationedSoldiers().size() >= m_capacity;
+	if (!full && !m_doing_upgrade_request && !m_normal_soldier_request) {
+		// if we miss soldiers
+		update_soldier_request();
+	} else {
+		// If we may issue a new upgrade request
+		int32_t time_since_last_swap = (timeofgame - m_last_swap_soldiers_time);
+		if (time_since_last_swap > GARRISON_SWAP_TIMEOUT) {
+			time_since_last_swap = timeofgame;
+			update_soldier_request();
+		}
+	}
+
+	// Calculate the amount of heal point to distribute
+	uint32_t to_heal_amount = static_cast<uint32_t>
+		((timeofgame - m_last_heal_time) * m_heal_per_second / 1000);
+	const std::vector<Soldier*> soldiers = presentSoldiers();
+	BOOST_FOREACH(Soldier* soldier, soldiers) {
+		uint32_t to_heal = soldier->get_max_hitpoints() - soldier->get_current_hitpoints();
+		if (to_heal > to_heal_amount) to_heal = to_heal_amount;
+		if (to_heal > 0) {
+			soldier->heal(to_heal);
+			to_heal_amount -= to_heal;
+		}
+		if (to_heal_amount <= 0) break;
+	}
+	m_last_heal_time = timeofgame;
+}
+
+void GarrisonHandler::popSoldier(Soldier* soldier)
+{
+	// Pop the soldier and update requests
+	popSoldierJob(soldier, nullptr, nullptr);
+	update_soldier_request();
+}
+
+void GarrisonHandler::set_economy(Economy * const e)
+{
+	// update requests
+	if (m_normal_soldier_request && e)
+		m_normal_soldier_request->set_economy(e);
+	if (m_upgrade_soldier_request && e)
+		m_upgrade_soldier_request->set_economy(e);
+}
+
+bool GarrisonHandler::get_garrison_work(Game& game, Soldier* soldier)
+{
+	// Evict soldiers that have returned home if the capacity is too low
+	if (m_capacity < stationedSoldiers().size()) {
+		soldier->reset_tasks(game);
+		soldier->start_task_leavebuilding(game, true);
+		return true;
+	}
+
+	bool stayhome;
+	uint8_t retreat;
+	if (Map_Object* enemy = popSoldierJob(soldier, &stayhome, &retreat)) {
+		if (upcast(Building, building, enemy)) {
+			soldier->start_task_attack(game, *building, retreat);
+			return true;
+		} else if (upcast(Soldier, opponent, enemy)) {
+			if (!opponent->getBattle()) {
+				soldier->start_task_defense(game, stayhome, retreat);
+				if (stayhome)
+					opponent->send_signal(game, "sleep");
+				return true;
+			}
+		} else
+			throw wexception("GarrisonHandler::get_garrison_work: bad SoldierJob");
+	}
+	return false;
+}
+
+void GarrisonHandler::set_soldier_requirements(Requirements req)
+{
+	m_soldier_requirements = req;
+}
+
+//
+// Garrison implementation
+//
+
+Player& GarrisonHandler::owner() const
+{
+	return m_building.owner();
+}
+
+bool GarrisonHandler::canAttack() const
+{
+	return m_didconquer && !m_passive;
+}
+
+void GarrisonHandler::aggressor(Soldier& enemy)
+{
+	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+	Map  & map  = game.map();
+	// Do not react if enemy is occupied or too far away
+	if
+		(enemy.get_owner() == &owner() || enemy.getBattle()
+		 || m_conquer_radius <= map.calc_distance
+			(enemy.get_position(), m_building.get_position()))
+	{
+		return;
+	}
+
+	// Do not react if enemy is at our door
+	if
+		(map.find_bobs
+		 	(Area<FCoords>(map.get_fcoords(m_building.base_flag().get_position()), 2), 0,
+		 	 FindBobEnemySoldier(&owner())))
+	{
+		return;
+	}
+
+	// Send some soldiers to defend, keeping min capacity inside
+	// This will send 1 soldier out to defend each time agressor()
+	// is called //FIXME?
+	const std::vector<Soldier*>& presents = presentSoldiers();
+	if (presents.size() >  m_min_capacity) {
+		container_iterate_const(std::vector<Soldier *>, presents, i) {
+			if (!haveSoldierJob(**i.current)) {
+				SoldierJob sj;
+				sj.soldier  = *i.current;
+				sj.enemy = &enemy;
+				sj.stayhome = false;
+				sj.retreat = owner().get_retreat_percentage();
+				m_soldierjobs.push_back(sj);
+				(*i.current)->update_task_buildingwork(game);
+				return;
+			}
+		}
+	}
+
+	// Inform the player, that we are under attack by adding a new entry to the
+	// message queue - a sound will automatically be played.
+	inform_owner(game, InfoType::AGGRESSSED);
+}
+
+bool GarrisonHandler::attack(Soldier& enemy)
+{
+	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+
+	const std::vector<Soldier*>& present = presentSoldiers();
+	Soldier * defender = 0;
+
+	if (!present.empty()) {
+		// Find soldier with greatest hitpoints
+		uint32_t current_max = 0;
+		container_iterate_const(std::vector<Soldier *>, present, i) {
+			if ((*i.current)->get_current_hitpoints() > current_max) {
+				defender = *i.current;
+				current_max = defender->get_current_hitpoints();
+			}
+		}
+	} else {
+		// If one of our stationed soldiers is currently walking into the
+		// building, give us another chance.
+		const std::vector<Soldier *>& stationed = stationedSoldiers();
+		container_iterate_const(std::vector<Soldier *>, stationed, i) {
+			if ((*i.current)->get_position() == m_building.get_position()) {
+				defender = *i.current;
+				break;
+			}
+		}
+	}
+
+	if (defender) {
+		popSoldierJob(defender); // defense overrides all other jobs
+
+		SoldierJob sj;
+		sj.soldier = defender;
+		sj.enemy = &enemy;
+		sj.stayhome = true;
+		sj.retreat = 0;         // Flag defenders could not retreat
+		m_soldierjobs.push_back(sj);
+
+		defender->update_task_buildingwork(game);
+
+		// Inform the player, that we are under attack by adding a new entry to
+		// the message queue - a sound will automatically be played.
+		inform_owner(game, InfoType::UNDER_ATTACK);
+		return true;
+	}
+
+	// The enemy has defeated our forces, we should inform the player
+	// Code for handling change of owner are handled in the garrison
+	// owner class.
+	upcast(GarrisonOwner, go, &m_building);
+	if (military_presence_kept(game)) {
+		inform_owner(game, InfoType::GARRISON_LOST);
+		go->garrison_lost(game, owner().player_number(), false);
+	} else {
+		inform_owner(game, InfoType::GARRISON_CAPTURED);
+		go->garrison_lost(game, enemy.owner().player_number(), true);
+	}
+	return false;
+}
+
+const std::vector< Soldier* > GarrisonHandler::presentSoldiers() const
+{
+	std::vector<Soldier *> present_soldiers;
+	container_iterate_const(std::vector<Worker*>, m_building.get_workers(), i) {
+		if (upcast(Soldier, s, *i.current)) {
+			if (isPresent(*s)) {
+				present_soldiers.push_back(s);
+			}
+		}
+	}
+	return present_soldiers;
+}
+
+const std::vector< Soldier* > GarrisonHandler::stationedSoldiers() const
+{
+	std::vector<Soldier *> soldiers;
+	container_iterate_const(std::vector<Worker*>, m_building.get_workers(), i) {
+		if (upcast(Soldier, s, *i.current)) {
+			soldiers.push_back(s);
+		}
+	}
+	return soldiers;
+}
+
+uint32_t GarrisonHandler::minSoldierCapacity() const
+{
+	return m_min_capacity;
+}
+
+uint32_t GarrisonHandler::maxSoldierCapacity() const
+{
+	return m_max_capacity;
+}
+
+uint32_t GarrisonHandler::soldierCapacity() const
+{
+	return m_capacity;
+}
+
+void GarrisonHandler::setSoldierCapacity(uint32_t capacity)
+{
+	assert(minSoldierCapacity() <= capacity);
+	assert                        (capacity <= maxSoldierCapacity());
+	assert(m_capacity != capacity);
+	m_capacity = capacity;
+	update_soldier_request();
+}
+
+void GarrisonHandler::dropSoldier(Soldier& soldier)
+{
+	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+
+	if (!isPresent(soldier)) {
+		// This can happen when the "drop soldier" player command is delayed
+		// by network delay or a client has bugs.
+		return;
+	}
+	// Ensure min capacity is respected
+	if (presentSoldiers().size() <= minSoldierCapacity()) {
+		return;
+	}
+	// Drop the soldier and update requests
+	soldier.reset_tasks(game);
+	soldier.start_task_leavebuilding(game, true);
+	update_soldier_request();
+}
+
+int GarrisonHandler::incorporateSoldier(Editor_Game_Base& egbase, Soldier& s)
+{
+	// Adjust the soldier location if required.
+	if (s.get_location(egbase) != &m_building)
+	{
+		s.set_location(&m_building);
+	}
+
+	upcast(Game, game, &egbase);
+	// If it's the first soldier, conquer the area
+	if (!m_passive && !m_didconquer) {
+		conquer_area(egbase);
+		if (game) {
+			inform_owner(*game, InfoType::GARRISON_OCCUPIED);
+		}
+		upcast(GarrisonOwner, go, &m_building);
+		go->garrison_occupied();
+	}
+
+	// Bind the worker into this house, hide him on the map
+	if (game) {
+		s.reset_tasks(*game);
+		if (m_passive) {
+			s.start_task_idle(*game, 0, -1);
+		} else {
+			s.start_task_buildingwork(*game);
+		}
+	}
+	// Make sure the request count is reduced or the request is deleted.
+	update_soldier_request();
+	return 0;
+}
+
+int GarrisonHandler::outcorporateSoldier(Editor_Game_Base&, Soldier&)
+{
+	// not needed
+	log("CGH Outcorporate called\n");
+	return -1;
+}
+
+uint32_t GarrisonHandler::conquerRadius() const
+{
+	return m_conquer_radius;
+}
+
+void GarrisonHandler::set_soldier_preference(GarrisonHandler::SoldierPref p)
+{
+	assert(SoldierPref::Heroes == p || SoldierPref::Rookies == p);
+	m_soldier_preference = p;
+	update_normal_soldier_request();
+}
+
+
+void GarrisonHandler::sendAttacker(Soldier& soldier, Building& target, uint8_t retreat)
+{
+	assert(isPresent(soldier));
+
+	if (haveSoldierJob(soldier)) {
+		return;
+	}
+
+	SoldierJob sj;
+	sj.soldier  = &soldier;
+	sj.enemy    = &target;
+	sj.stayhome = false;
+	sj.retreat  = retreat;
+	m_soldierjobs.push_back(sj);
+
+	soldier.update_task_buildingwork(ref_cast<Game, Editor_Game_Base>(owner().egbase()));
+}
+
+//
+// Private helper methods
+//
+void GarrisonHandler::inform_owner(Game& game, GarrisonHandler::InfoType info)
+{
+	if (m_passive) {
+		return;
+	}
+	std::string message;
+	std::string message_id;
+	std::string message_title;
+	std::string building_name = m_building.descname();
+	switch (info) {
+		case InfoType::AGGRESSSED:
+			message =
+				(boost::format
+					(_("Your %s discovered an aggressor")) % building_name)
+				.str();
+			message_id = "under_attack";
+			message_title = _("You are under attack");
+			break;
+		case InfoType::UNDER_ATTACK:
+			message =
+				(boost::format
+					(_("Your %s is under attack")) % building_name)
+				.str();
+			message_id = "under_attack";
+			message_title = _("You are under attack");
+			break;
+		case InfoType::GARRISON_LOST:
+			message =
+				(boost::format
+					(_("The enemy defeated your soldiers and destroyed your %s")) % building_name)
+				.str();
+			message_id = "garrison_lost";
+			message_title = _("Garrison lost");
+			break;
+		case InfoType::GARRISON_CAPTURED:
+			message =
+				(boost::format
+					(_("The enemy defeated your soldiers and captured your %s")) % building_name)
+				.str();
+			message_id = "garrison_lost";
+			message_title = _("Garrison captured");
+			break;
+		case InfoType::GARRISON_OCCUPIED:
+			message =
+				(boost::format
+					(_("Your soldier occupied your %s")) % building_name)
+				.str();
+			message_id = "garrison_occupied";
+			message_title = _("Garrison occupied");
+			break;
+		default:
+			assert(false);
+	}
+	m_building.send_message(game, message_id, message_title, message);
+}
+
+bool GarrisonHandler::isPresent(Soldier& soldier) const
+{
+	if
+		(soldier.get_location(owner().egbase()) != &m_building
+		|| soldier.get_position() != m_building.get_position())
+	{
+		return false;
+	}
+	// Present soldiers are working for the garrison only if it is not passive
+	if (!m_passive) {
+		return
+			soldier.get_state() == soldier.get_state(Worker::taskBuildingwork);
+	}
+	return true;
+}
+
+void GarrisonHandler::conquer_area(Editor_Game_Base& egbase)
+{
+	assert(!m_didconquer);
+	egbase.conquer_area
+		(Player_Area<Area<FCoords> >
+			(owner().player_number(),
+			Area<FCoords>
+				(egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)));
+	m_didconquer = true;
+}
+
+bool GarrisonHandler::military_presence_kept(Game& game)
+{
+	// collect information about immovables in the area
+	std::vector<ImmovableFound> immovables;
+
+	// Search in a radius of 3 (needed for big militarysites)
+	FCoords const fc = game.map().get_fcoords(m_building.get_position());
+	game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
+
+	for (uint32_t i = 0; i < immovables.size(); ++i) {
+		upcast(GarrisonOwner, go, immovables[i].object);
+		if (!go) {
+			continue;
+		}
+		Garrison* g = go->get_garrison();
+		upcast(GarrisonOwner, mygo, &m_building);
+		// NOCOM I changed the logic here to check for any stationed soldier
+		// and not for m_didconquer. So a msite with all slots empty and soldiers
+		// on their way won't keep military presence anymore.
+
+		// Presence kept if any non-empty garrison with higher conquer radius
+		// and owned by our owner is nearby
+		if
+			(mygo != go
+			&& owner().player_number() == g->owner().player_number()
+			&& conquerRadius() < g->conquerRadius()
+			&& !g->stationedSoldiers().empty())
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+//FIXME CGH use a cleaner way without polling required
+void GarrisonHandler::update_soldier_request(bool upgraded_in)
+{
+/*
+ * I have update_soldier_request
+ *        update_upgrade_soldier_request
+ *        update_normal_soldier_request
+ *
+ * The first one handles state switching between site fill (normal more)
+ * and grabbing soldiers with proper training (upgrade mode). The last
+ * two actually make the requests.
+ *
+ * The input parameter incd is true, if we just incorporated a new soldier
+ * as a result of an upgrade request. In such cases, we will re-arm the
+ * upgrade request.
+ */
+	const uint32_t capacity = soldierCapacity();
+	const uint32_t stationed = stationedSoldiers().size();
+
+	if (m_doing_upgrade_request) {
+		if (upgraded_in && m_upgrade_soldier_request) {// update requests always ask for one soldier at time!
+			m_upgrade_soldier_request.reset();
+		}
+		if (capacity > stationed) {
+			// Somebody is killing my soldiers in the middle of upgrade
+			// or I have kicked out his predecessor already.
+			if
+				((m_upgrade_soldier_request)
+				&& (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
+			{
+				// Economy was not able to find the soldiers I need.
+				// I can safely drop the upgrade request and go to fill mode.
+				m_upgrade_soldier_request.reset();
+			}
+			if (!m_upgrade_soldier_request) {
+				//phoo -- I can safely request new soldiers.
+				m_doing_upgrade_request = false;
+				update_normal_soldier_request();
+			}
+			// else -- ohno please help me! Player is in trouble -- evil grin
+			// An upgraded soldier is on his way, but since we only make one request
+			// at a time, we have to wait for him to arrive before doing another
+			// request to fill capacity.
+			//FIXME
+		} else if (capacity < stationed) {// player is reducing capacity
+			drop_least_suited_soldier();
+		} else {// capacity == stationed size
+			update_upgrade_soldier_request();
+		}
+	} else {// not doing upgrade request
+		if ((capacity != stationed) or (m_normal_soldier_request)) {
+			update_normal_soldier_request();
+		}
+		if ((capacity == stationed) && (! m_normal_soldier_request) && !m_passive) {
+			// Our site is full, we might try to get upgraded soldiers
+			// TODO not allowed for passive garrison for now
+			if (presentSoldiers().size() == capacity && capacity > m_min_capacity) {
+				m_doing_upgrade_request = true;
+			}
+		}
+	}
+}
+
+void GarrisonHandler::update_normal_soldier_request()
+{
+	// Request new soldiers if needed
+	std::vector<Soldier*> soldiers = stationedSoldiers();
+	if (soldiers.size() < m_capacity) {
+		if (!m_normal_soldier_request) {
+			// No ongoing request, fill a new one
+			Request* r = new Request
+				(m_building, m_building.tribe().safe_worker_index("soldier"),
+				 GarrisonHandler::request_soldier_callback, wwWORKER);
+			r->set_requirements(m_soldier_requirements);
+			m_normal_soldier_request.reset(r);
+		}
+		// Already an ongoing request, update counts
+		m_normal_soldier_request->set_count(m_capacity - soldiers.size());
+	} else {
+		// No new soldier required. Destroy request if there is one
+		m_normal_soldier_request.reset();
+	}
+	// Evict present soldiers if required
+	const std::vector<Soldier *>& present = presentSoldiers();
+	if (present.size() > m_capacity) {
+		Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+		for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
+			Soldier & soldier = *present[i];
+			soldier.reset_tasks(game);
+			soldier.start_task_leavebuilding(game, true);
+		}
+	}
+}
+
+void GarrisonHandler::update_upgrade_soldier_request()
+{
+	bool reqirement_changed = update_upgrade_requirements();
+	// Update the requirements
+	if (!m_try_soldier_upgrade) {
+		return;
+	}
+	// Do not perform a new request if someone is on his way
+	// or if we are going to request the same thing
+	if (m_upgrade_soldier_request) {
+		if (!m_upgrade_soldier_request->is_open()) {
+			// upgraded soldier is on his way
+			return;
+		}
+		if (!reqirement_changed && m_upgrade_soldier_request->get_count() > 0) {
+			// Current request is still valid
+			return;
+		}
+	}
+	// Issue a new request
+	Request* r = new Request
+		(m_building, m_building.tribe().safe_worker_index("soldier"),
+		GarrisonHandler::request_soldier_callback, wwWORKER,
+		GarrisonHandler::request_soldier_transfer_callback);
+	// Honor soldier requirements if set by the garrison owner
+	RequireAnd upgrade_requirement;
+	upgrade_requirement.add(m_soldier_requirements);
+	upgrade_requirement.add(m_soldier_upgrade_requirements);
+	r->set_requirements(upgrade_requirement);
+	r->set_count(1);
+	m_upgrade_soldier_request.reset(r);
+}
+
+void GarrisonHandler::request_soldier_callback
+	(Game& game, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
+{
+	Soldier& s = ref_cast<Soldier, Worker>(*w);
+	upcast(GarrisonOwner, go, &pi);
+	upcast(GarrisonHandler, gh, go->get_garrison());
+
+	if (!gh->m_doing_upgrade_request) {
+		gh->incorporateSoldier(game, s);
+	} else {
+		gh->incorporateUpgradedSoldier(game, s);
+	}
+}
+
+void GarrisonHandler::request_soldier_transfer_callback
+	(Game&, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
+{
+	Soldier& s = ref_cast<Soldier, Worker>(*w);
+	upcast(GarrisonOwner, go, &pi);
+	upcast(GarrisonHandler, gh, go->get_garrison());
+
+	if (!gh->m_doing_upgrade_request) {
+		gh->drop_least_suited_soldier(&s);
+	}
+}
+
+bool GarrisonHandler::update_upgrade_requirements()
+{
+	int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
+	int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
+
+	if
+		(SoldierPref::Heroes != m_soldier_preference
+		 && SoldierPref::Rookies != m_soldier_preference)
+	{
+		m_try_soldier_upgrade = false;
+		return false;
+	}
+
+	// Find the level of the soldier that is currently least-suited.
+	Soldier * worst_guy = find_least_suited_soldier();
+	if (worst_guy == nullptr) {
+		// There could be no soldier in the militarysite right now. No reason to freak out.
+		return false;
+	}
+	int32_t wg_level = worst_guy->get_level(atrTotal);
+
+	// Micro-optimization: I assume that the majority of military sites have only level-zero
+	// soldiers and prefer rookies. Handle them separately.
+	if (m_soldier_preference == SoldierPref::Rookies && wg_level == 0) {
+		m_try_soldier_upgrade = false;
+		return false;
+	}
+	m_try_soldier_upgrade = true;
+
+	// Now I actually build the new requirements.
+	int32_t reqmin = SoldierPref::Heroes == m_soldier_preference ? 1 + wg_level : 0;
+	int32_t reqmax = SoldierPref::Heroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
+
+	bool maxchanged = reqmax != soldier_upgrade_required_max;
+	bool minchanged = reqmin != soldier_upgrade_required_min;
+
+	if (maxchanged or minchanged) {
+		m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
+		return true;
+	}
+	return false;
+}
+
+bool GarrisonHandler::incorporateUpgradedSoldier(Editor_Game_Base& egbase, Soldier& s)
+{
+	// Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
+	assert(isPresent(s));
+	std::vector<Soldier*> stationned = stationedSoldiers();
+	if (stationned.size() <= m_capacity || drop_least_suited_soldier(&s)) {
+		Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
+		s.set_location(&m_building);
+		s.reset_tasks(game);
+		if (!m_passive) {
+			s.start_task_buildingwork(game);
+		} else {
+			s.start_task_idle(game, 0, -1);
+		}
+		// Reset timer for new request
+		m_upgrade_soldier_request.reset();
+		m_last_swap_soldiers_time = game.get_gametime();
+		return true;
+	}
+	return false;
+}
+
+Soldier* GarrisonHandler::find_least_suited_soldier()
+{
+	const std::vector<Soldier *>& present = presentSoldiers();
+	const int32_t multiplier = m_soldier_preference == SoldierPref::Heroes ? -1 : 1;
+	int worst_soldier_level = INT_MIN;
+	Soldier * worst_soldier = nullptr;
+	BOOST_FOREACH(Soldier * sld, present)
+	{
+		int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
+		if (this_soldier_level > worst_soldier_level)
+		{
+			worst_soldier_level = this_soldier_level;
+			worst_soldier = sld;
+		}
+	}
+	return worst_soldier;
+}
+
+bool GarrisonHandler::drop_least_suited_soldier(Soldier* newguy)
+{
+	const std::vector<Soldier *>& present = presentSoldiers();
+	// Don't drop under the minimum capacity if new guy is not here yet
+	if (newguy == nullptr && present.size() <= m_min_capacity) {
+		return false;
+	}
+	Soldier * kickoutCandidate = find_least_suited_soldier();
+
+	// If the arriving guy is worse than worst present, I wont't release.
+	if (newguy != nullptr && kickoutCandidate != nullptr) {
+		int32_t old_level = kickoutCandidate->get_level(atrTotal);
+		int32_t new_level = newguy->get_level(atrTotal);
+		if (m_soldier_preference == SoldierPref::Heroes && old_level >= new_level) {
+			return false;
+		} else if (m_soldier_preference == SoldierPref::Rookies && old_level <= new_level) {
+			return false;
+		}
+	}
+
+	// Now I know that the new guy is worthy.
+	if (kickoutCandidate != nullptr) {
+		Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
+		kickoutCandidate->reset_tasks(game);
+		kickoutCandidate->start_task_leavebuilding(game, true);
+		return true;
+	}
+	return false;
+}
+
+bool GarrisonHandler::haveSoldierJob(Soldier& soldier) const
+{
+	container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i) {
+		if (i.current->soldier == &soldier) {
+			return true;
+		}
+	}
+	return false;
+}
+
+Map_Object* GarrisonHandler::popSoldierJob(Soldier* soldier, bool* stayhome, uint8_t* retreat)
+{
+	container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
+		if (i.current->soldier == soldier) {
+			Map_Object * const enemy = i.current->enemy.get(owner().egbase());
+			if (stayhome)
+				*stayhome = i.current->stayhome;
+			if (retreat)
+				*retreat = i.current->retreat;
+			m_soldierjobs.erase(i.current);
+			return enemy;
+		}
+	return 0;
+}
+
+}

=== added file 'src/logic/garrisonhandler.h'
--- src/logic/garrisonhandler.h	1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.h	2013-08-06 10:09:46 +0000
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef GARRISON_HANDLER_H
+#define GARRISON_HANDLER_H
+
+#include "logic/instances.h"
+#include "logic/garrison.h"
+#include "logic/requirements.h"
+#include "logic/worker.h"
+
+namespace Widelands {
+
+struct Building;
+struct Request;
+class Soldier;
+
+#define GARRISON_SWAP_TIMEOUT 20000
+/**
+ * Implementation of the Garrison interface to used by GarrisonOwner.
+ */
+class GarrisonHandler : public Garrison {
+friend struct Map_Buildingdata_Data_Packet;
+public:
+	/**
+	 * Create a new garrison handler
+	 * \param building The building that holds this garrison. Must implements GarrisonOwner
+	 * \param min_soldiers The minimum soldiers to be present in the garrison
+	 * \param max_soldiers The maximum soldiers that can be present in this garrison
+	 * \param conquer_radius The radius of the area conqered by this garrison
+	 * \param heal_per_second The speed at which soldiers will be healed
+	 * \param soldier_pref The soldier preference for rookies or heroes
+	 * \param passive A passive garrison is only helpful to keep some soldiers around. It can't
+	 * attack nor be attacked. I think of training site or ships
+	 */
+	GarrisonHandler
+		(Building& building, uint32_t min_soldiers, uint32_t max_soldiers,
+		 uint32_t conquer_radius, uint32_t heal_per_second, SoldierPref soldier_pref,
+		 bool passive = false);
+	virtual ~GarrisonHandler();
+
+	/**
+	 * Must be called once
+	 */
+	void init(Editor_Game_Base &);
+	/**
+	 * Must be called once after conqueral
+	 */
+	void reinit_after_conqueral(Game & game);
+	/**
+	 * Cleanup handled objects
+	 */
+	void cleanup(Editor_Game_Base &);
+	/**
+	 * Eequests must be cleaned up after the building has
+	 * been cleaned up, hence this seperate function.
+	 */
+	void cleanup_requests(Editor_Game_Base &);
+	/**
+	 * Must be called regularly. It is not time dependant though.
+	 */
+	void act(Game &);
+	/**
+	 * Must be called when the owner building changes economy
+	 */
+	void set_economy(Economy * const e);
+	/**
+	 * Pop the given soldier out of the building, while keeping it
+	 * in the garrion.
+	 */
+	void popSoldier(Soldier* soldier);
+	/**
+	 * Get some work for a soldier that asks for it
+	 */
+	bool get_garrison_work(Game & game, Soldier* soldier);
+	/**
+	 * Set the requirements for that soldier. This will be used when filling
+	 * request for soldiers.
+	 */
+	void set_soldier_requirements(Requirements req);
+
+	// Garrison implementation
+	virtual Player & owner() const;
+	virtual bool canAttack() const;
+	virtual void aggressor(Soldier &);
+	virtual bool attack(Soldier &);
+	virtual const std::vector<Soldier *> presentSoldiers() const;
+	virtual const std::vector<Soldier *> stationedSoldiers() const;
+	virtual uint32_t minSoldierCapacity() const;
+	virtual uint32_t maxSoldierCapacity() const;
+	virtual uint32_t soldierCapacity() const;
+	virtual void setSoldierCapacity(uint32_t capacity);
+	virtual void dropSoldier(Soldier &);
+	virtual int incorporateSoldier(Editor_Game_Base &, Soldier &);
+	virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &);
+	virtual uint32_t conquerRadius() const;
+	virtual void set_soldier_preference(SoldierPref p);
+	virtual SoldierPref get_soldier_preference() const {
+		return m_soldier_preference;
+	}
+	virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat);
+
+
+private:
+	enum class InfoType : uint8_t {
+		AGGRESSSED,
+		UNDER_ATTACK,
+		GARRISON_LOST,
+		GARRISON_CAPTURED,
+		GARRISON_OCCUPIED
+	};
+	// Helper methods
+	/**
+	 * Sends a message to the owner
+	 */
+	void inform_owner(Game&, InfoType);
+	/**
+	 * Check if a soldier is actually present in building
+	 */
+	bool isPresent(Soldier &) const;
+	/**
+	 * Conquers the area once a soldier occupied the site
+	 */
+	void conquer_area(Editor_Game_Base &);
+	/**
+	 * Check if we keep military influence once our garrison
+	 * has been conquered
+	 */
+	bool military_presence_kept(Game &);
+	/**
+	 * Update the soldier requests. If upgraded_incorporated, a soldier
+	 * requested by an upgrade request has just been incorporated. This
+	 * method handle requesting for normal case (filling slots) or for
+	 * upgrading to a better suited soldier
+	 */
+	void update_soldier_request(bool upgraded_incorporated = false);
+	/**
+	 * Request new soldiers or evict some to fill the capacity
+	 */
+	void update_normal_soldier_request();
+	/* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
+	* more soldiers, and "upgrade" which is used when there is a preference for either heroes or
+	* rookies.
+	*
+	* In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
+	* is exchanged at a time.
+	*
+	* There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
+	* field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
+	* to reduce the benefits of site micromanagement. The intention is not to make gameplay easier
+	* in other ways.
+	*/
+	void update_upgrade_soldier_request();
+	/**
+	 * The callback function, called whenever one of our soldier requested arrived
+	 */
+	static void request_soldier_callback
+		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+	/**
+	 * The transfer callback function, called whenever one of our requested
+	 * soldier started to move towards the garrison
+	 */
+	static void request_soldier_transfer_callback
+		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
+	/*
+	* When upgrading soldiers, we do not ask for just any soldiers, but soldiers
+	* that are better than what we already have. This routine sets the requirements
+	* used by the request.
+	*
+	* The routine returns true if upgrade request thresholds have changed. This information could be
+	* used to decide whether the soldier-Request should be upgraded. Additionally, the m_try_soldier_upgrade
+	* field will be set so to know if an attempt to get better soldier sould be performed.
+	*/
+	bool update_upgrade_requirements();
+	/**
+	 * Called when an upgraded soldier comes to join the garrison
+	 */
+	bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
+	/**
+	 * Find the least suited soldier for this garrison. We don't play
+	 * in the same league
+	 */
+	Soldier * find_least_suited_soldier();
+	/**
+	 * Try to drop the lease suited soldier, return true on success.
+	 * If a new soldier s has arrived, extra care will be taken to not drop
+	 * anyone if the new one is even worst
+	 */
+	bool drop_least_suited_soldier(Soldier * s = nullptr);
+	/**
+	 * Return true if we hold a running job for that soldied
+	 */
+	bool haveSoldierJob(Soldier &) const;
+	/**
+	* \return the enemy, if any, that the given soldier was scheduled
+	* to attack, and remove the job.
+	*/
+	Map_Object * popSoldierJob(Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
+
+	// Basic fields
+	Building& m_building;
+	uint32_t m_min_capacity;
+	uint32_t m_max_capacity;
+	uint32_t m_capacity;
+	bool m_passive;
+
+	// Healing
+	uint32_t m_heal_per_second;
+	uint32_t m_last_heal_time;
+
+	// Requests
+	Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
+	RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
+	std::unique_ptr<Request> m_normal_soldier_request;  // filling the site
+	std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
+
+	// Conqueral
+	uint32_t m_conquer_radius;
+	bool m_didconquer;
+
+	// Job
+	struct SoldierJob {
+		Soldier    * soldier;
+		Object_Ptr  enemy;
+		bool        stayhome;
+		uint8_t     retreat;
+	};
+	std::vector<SoldierJob> m_soldierjobs;
+
+	// Soldier preferences
+	SoldierPref m_soldier_preference;
+	uint32_t m_last_swap_soldiers_time;
+	bool m_try_soldier_upgrade; // optimization -- if everybody is zero-level, do not downgrade
+	bool m_doing_upgrade_request;
+};
+
+}
+
+#endif

=== modified file 'src/logic/item_ware_descr.h'
--- src/logic/item_ware_descr.h	2013-07-26 20:19:36 +0000
+++ src/logic/item_ware_descr.h	2013-08-06 10:09:46 +0000
@@ -41,7 +41,7 @@
 namespace Widelands {
 
 /**
- * Wares can be stored in warehouses. They can be transferred across an
+ * Wares can be stored in storages. They can be transferred across an
  * Economy. They can be traded.
  * Both items (lumber, stone, ...) and workers are considered wares.
  * Every ware has a unique name. Note that an item must not have the same
@@ -75,7 +75,7 @@
 	/// \return ware's localized descriptive text
 	const std::string & helptext() const throw () {return m_helptext;}
 
-	/// How much of the ware type that an economy should store in warehouses.
+	/// How much of the ware type that an economy should store in storages.
 	/// The special value std::numeric_limits<uint32_t>::max() means that the
 	/// the target quantity of this ware type will never be checked and should
 	/// not be configurable.

=== modified file 'src/logic/militarysite.cc'
--- src/logic/militarysite.cc	2013-07-31 17:00:28 +0000
+++ src/logic/militarysite.cc	2013-08-06 10:09:46 +0000
@@ -21,8 +21,10 @@
 
 #include <clocale>
 #include <cstdio>
+#include <memory>
 
 #include <boost/foreach.hpp>
+#include <boost/format.hpp>
 #include <libintl.h>
 
 #include "economy/flag.h"
@@ -33,6 +35,7 @@
 #include "logic/editor_game_base.h"
 #include "logic/findbob.h"
 #include "logic/game.h"
+#include "logic/garrisonhandler.h"
 #include "logic/message_queue.h"
 #include "logic/player.h"
 #include "logic/soldier.h"
@@ -61,7 +64,6 @@
 	if (m_conquer_radius > 0)
 		m_workarea_info[m_conquer_radius].insert(descname() + _(" conquer"));
 	m_prefers_heroes_at_start = global_s.get_safe_bool("prefer_heroes");
-
 }
 
 /**
@@ -83,96 +85,39 @@
 */
 
 MilitarySite::MilitarySite(const MilitarySite_Descr & ms_descr) :
-ProductionSite(ms_descr),
-m_didconquer  (false),
-m_capacity    (ms_descr.get_max_number_of_soldiers()),
-m_nexthealtime(0),
-m_soldier_preference(ms_descr.m_prefers_heroes_at_start ? kPrefersHeroes : kPrefersRookies),
-m_soldier_upgrade_try(false)
+ProductionSite(ms_descr)
 {
-	m_next_swap_soldiers_time = 0;
+	GarrisonHandler* gh = new GarrisonHandler
+		(*this, 1,
+		 descr().get_max_number_of_soldiers(),
+		 descr().get_conquers(), descr().get_heal_per_second(),
+		 descr().m_prefers_heroes_at_start ? GarrisonHandler::SoldierPref::Heroes
+			: GarrisonHandler::SoldierPref::Rookies);
+	m_garrison.reset(gh);
 }
 
-
 MilitarySite::~MilitarySite()
 {
-	assert(!m_normal_soldier_request);
-	assert(!m_upgrade_soldier_request);
-}
-
-
-/**
-===============
-Display number of soldiers.
-===============
-*/
-std::string MilitarySite::get_statistics_string()
-{
-	char buffer[255];
-	std::string str;
-	uint32_t present = presentSoldiers().size();
-	uint32_t total = stationedSoldiers().size();
-
-	if (present == total) {
-		snprintf
-			(buffer, sizeof(buffer),
-			 ngettext("%u soldier", "%u soldiers", total),
-			 total);
-	} else {
-		snprintf
-			(buffer, sizeof(buffer),
-			 ngettext("%u(+%u) soldier", "%u(+%u) soldiers", total),
-			 present, total - present);
-	}
-	str = buffer;
-
-	if (m_capacity > total) {
-		snprintf(buffer, sizeof(buffer), " (+%u)", m_capacity - total);
-		str += buffer;
-	}
-
-	return str;
-}
-
+}
 
 void MilitarySite::init(Editor_Game_Base & egbase)
 {
 	ProductionSite::init(egbase);
-
+	m_garrison->init(egbase);
 	upcast(Game, game, &egbase);
 
 	const std::vector<Worker*>& ws = get_workers();
-	container_iterate_const(std::vector<Worker *>, ws, i)
+	container_iterate_const(std::vector<Worker *>, ws, i) {
 		if (upcast(Soldier, soldier, *i.current)) {
 			soldier->set_location_initially(*this);
-			assert(!soldier->get_state()); //  Should be newly created.
-			if (game)
-				soldier->start_task_buildingwork(*game);
+			m_garrison->incorporateSoldier(egbase, *soldier);
 		}
-	update_soldier_request();
-
-	//  schedule the first healing
-	m_nexthealtime = egbase.get_gametime() + 1000;
-	if (game)
+	}
+	if (game) {
 		schedule_act(*game, 1000);
-}
-
-
-/**
-===============
-Change the economy for the wares queues.
-Note that the workers are dealt with in the PlayerImmovable code.
-===============
-*/
-void MilitarySite::set_economy(Economy * const e)
-{
-	ProductionSite::set_economy(e);
-
-	if (m_normal_soldier_request && e)
-		m_normal_soldier_request->set_economy(e);
-	if (m_upgrade_soldier_request && e)
-		m_upgrade_soldier_request->set_economy(e);
-}
+	}
+}
+
 
 /**
 ===============
@@ -181,362 +126,12 @@
 */
 void MilitarySite::cleanup(Editor_Game_Base & egbase)
 {
-	// unconquer land
-	if (m_didconquer)
-		egbase.unconquer_area
-			(Player_Area<Area<FCoords> >
-			 	(owner().player_number(),
-			 	 Area<FCoords>
-			 	 	(egbase.map().get_fcoords(get_position()), get_conquers())),
-			 m_defeating_player);
-
+	// Order matters. Building needed to unconquer, building
+	// cleanup will trigger new requests in garrison, garrison
+	// cleanup will destroy them
+	m_garrison->cleanup(egbase);
 	ProductionSite::cleanup(egbase);
-
-	// Note that removing workers during ProductionSite::cleanup can generate
-	// new requests; that's why we delete it at the end of this function.
-	m_normal_soldier_request.reset();
-	m_upgrade_soldier_request.reset();
-}
-
-
-/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int MilitarySite::incorporateSoldier(Editor_Game_Base & egbase, Soldier & s)
-{
-
-	if (s.get_location(egbase) != this)
-	{
-		s.set_location(this);
-	}
-
-	// Soldier upgrade is done once the site is full. In soldier upgrade, we
-	// request one new soldier who is better suited than the existing ones.
-	// Normally, I kick out one existing soldier as soon as a new guy starts walking
-	// towards here. However, since that is done via infrequent polling, a new soldier
-	// can sometimes reach the site before such kick-out happens. In those cases, we
-	// should either drop one of the existing soldiers or reject the new guy, to
-	// avoid overstocking this site.
-
-	if (stationedSoldiers().size()  > descr().get_max_number_of_soldiers())
-	{
-		return incorporateUpgradedSoldier(egbase, s) ? 0 : -1;
-	}
-
-	if (!m_didconquer) {
-		conquer_area(egbase);
-		// Building is now occupied - idle animation should be played
-		start_animation(egbase, descr().get_animation("idle"));
-
-		if (upcast(Game, game, &egbase)) {
-			char message[256];
-			snprintf
-				(message, sizeof(message),
-				 _("Your soldiers occupied your %s."),
-				 descname().c_str());
-			send_message
-				(*game,
-				 "site_occupied",
-				 descname(),
-				 message);
-		}
-	}
-
-	if (upcast(Game, game, &egbase)) {
-		// Bind the worker into this house, hide him on the map
-		s.reset_tasks(*game);
-		s.start_task_buildingwork(*game);
-	}
-
-	// Make sure the request count is reduced or the request is deleted.
-	update_soldier_request(true);
-
-	return 0;
-}
-
-
-/*
- * Returns the least wanted soldier -- If player prefers zero-level guys,
- * the most trained soldier is the "weakest guy".
- */
-
-Soldier *
-MilitarySite::find_least_suited_soldier()
-{
-	const std::vector<Soldier *> present = presentSoldiers();
-	const int32_t multiplier = kPrefersHeroes == m_soldier_preference ? -1:1;
-	int worst_soldier_level = INT_MIN;
-	Soldier * worst_soldier = nullptr;
-	BOOST_FOREACH (Soldier * sld, present)
-	{
-		int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
-		if (this_soldier_level > worst_soldier_level)
-		{
-			worst_soldier_level = this_soldier_level;
-			worst_soldier = sld;
-		}
-	}
-	return worst_soldier;
-}
-
-
-/*
- * Kicks out the least wanted soldier -- If player prefers zero-level guys,
- * the most trained soldier is the "weakest guy".
- *
- * Returns false, if there is only one soldier (won't drop last soldier)
- * or the new guy is not better than the weakest one present, in which case
- * nobody is dropped. If a new guy arrived and nobody was dropped, then
- * caller of this should not allow the new guy to enter.
- *
- * Situations like the above may happen if, for example, when weakest guy
- * that was supposed to be dropped is not present at the moment his replacement
- * arrives.
- */
-
-bool
-MilitarySite::drop_least_suited_soldier(bool new_soldier_has_arrived, Soldier * newguy)
-{
-	const std::vector<Soldier *> present = presentSoldiers();
-
-	// If I have only one soldier, and the  new guy is not here yet, I can't release.
-	if (new_soldier_has_arrived || 1 < present.size())
-	{
-		Soldier * kickoutCandidate = find_least_suited_soldier();
-
-		// If the arriving guy is worse than worst present, I wont't release.
-		if (nullptr != newguy && nullptr != kickoutCandidate)
-		{
-			int32_t old_level = kickoutCandidate->get_level(atrTotal);
-			int32_t new_level = newguy->get_level(atrTotal);
-			if (kPrefersHeroes == m_soldier_preference && old_level >= new_level)
-			{
-				return false;
-			}
-			else
-			if (kPrefersRookies == m_soldier_preference && old_level <= new_level)
-			{
-				return false;
-			}
-		}
-
-		// Now I know that the new guy is worthy.
-		if (nullptr != kickoutCandidate)
-		{
-			Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-			kickoutCandidate->reset_tasks(game);
-			kickoutCandidate->start_task_leavebuilding(game, true);
-			return true;
-		}
-	}
-	return false;
-}
-
-/*
- * This finds room for a soldier in an already full occupied military building.
- *
- * Returns false if the soldier was not incorporated.
- */
-bool
-MilitarySite::incorporateUpgradedSoldier(Editor_Game_Base & egbase, Soldier & s)
-{
-	// Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
-	if (stationedSoldiers().size() < m_capacity || drop_least_suited_soldier(true, &s))
-	{
-		Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
-		s.set_location(this);
-		s.reset_tasks(game);
-		s.start_task_buildingwork(game);
-		return true;
-	}
-	return false;
-}
-
-/*
-===============
-Called when our soldier arrives.
-===============
-*/
-void MilitarySite::request_soldier_callback
-	(Game            &       game,
-	 Request         &,
-	 Ware_Index,
-	 Worker          * const w,
-	 PlayerImmovable &       target)
-{
-	MilitarySite & msite = ref_cast<MilitarySite, PlayerImmovable>(target);
-	Soldier      & s     = ref_cast<Soldier,      Worker>         (*w);
-
-	msite.incorporateSoldier(game, s);
-}
-
-
-/**
- * Update the request for soldiers and cause soldiers to be evicted
- * as appropriate.
- */
-void MilitarySite::update_normal_soldier_request()
-{
-	std::vector<Soldier *> present = presentSoldiers();
-	uint32_t const stationed = stationedSoldiers().size();
-
-	if (stationed < m_capacity) {
-		if (!m_normal_soldier_request) {
-			m_normal_soldier_request.reset
-				(new Request
-					(*this,
-					 tribe().safe_worker_index("soldier"),
-					 MilitarySite::request_soldier_callback,
-					 wwWORKER));
-			m_normal_soldier_request->set_requirements (m_soldier_requirements);
-		}
-
-		m_normal_soldier_request->set_count(m_capacity - stationed);
-	} else {
-		m_normal_soldier_request.reset();
-	}
-
-	if (m_capacity < present.size()) {
-		Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-		for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
-			Soldier & soldier = *present[i];
-			soldier.reset_tasks(game);
-			soldier.start_task_leavebuilding(game, true);
-		}
-	}
-}
-
-/* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
- * more soldiers, and "upgrade" which is used when there is a preference for either heroes or
- * rookies.
- *
- * In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
- * is exchanged at a time.
- *
- * There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
- * field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
- * to reduce the benefits of site micromanagement. The intention is not to make gameplay easier in other ways.
- */
-void MilitarySite::update_upgrade_soldier_request()
-{
-	bool reqch = update_upgrade_requirements();
-	if (!m_soldier_upgrade_try)
-		return;
-
-	bool do_rebuild_request = reqch;
-
-	if (m_upgrade_soldier_request)
-	{
-		if (!m_upgrade_soldier_request->is_open())
-			// If a replacement is already walking this way, let's not change our minds.
-			do_rebuild_request = false;
-		if (0 == m_upgrade_soldier_request->get_count())
-			do_rebuild_request = true;
-	}
-	else
-		do_rebuild_request = true;
-
-	if (do_rebuild_request)
-	{
-		m_upgrade_soldier_request.reset
-				(new Request
-				(*this,
-				tribe().safe_worker_index("soldier"),
-				MilitarySite::request_soldier_callback,
-				wwWORKER));
-
-		m_upgrade_soldier_request->set_requirements(m_soldier_upgrade_requirements);
-		m_upgrade_soldier_request->set_count(1);
-	}
-}
-
-/*
- * I have update_soldier_request
- *        update_upgrade_soldier_request
- *        update_normal_soldier_request
- *
- * The first one handles state switching between site fill (normal more)
- * and grabbing soldiers with proper training (upgrade mode). The last
- * two actually make the requests.
- *
- * The input parameter incd is true, if we just incorporated a new soldier
- * as a result of an upgrade request. In such cases, we will re-arm the
- * upgrade request.
- */
-
-void MilitarySite::update_soldier_request(bool incd)
-{
-	const uint32_t capacity = soldierCapacity();
-	const uint32_t stationed = stationedSoldiers().size();
-
-	if (m_doing_upgrade_request)
-	{
-		if (incd && m_upgrade_soldier_request) // update requests always ask for one soldier at time!
-		{
-			m_upgrade_soldier_request.reset();
-		}
-		if (capacity > stationed)
-		{
-			// Somebody is killing my soldiers in the middle of upgrade
-			// or I have kicked out his predecessor already.
-			if
-				((m_upgrade_soldier_request)
-				&& (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
-			{
-				// Economy was not able to find the soldiers I need.
-				// I can safely drop the upgrade request and go to fill mode.
-				m_upgrade_soldier_request.reset();
-			}
-			if (! m_upgrade_soldier_request)
-			{
-				//phoo -- I can safely request new soldiers.
-				m_doing_upgrade_request = false;
-				update_normal_soldier_request();
-			}
-			// else -- ohno please help me! Player is in trouble -- evil grin
-		}
-		else // military site is full or overfull
-		if (capacity < stationed) // player is reducing capacity
-		{
-			drop_least_suited_soldier(false, nullptr);
-		}
-		else // capacity == stationed size
-		{
-			if
-				(m_upgrade_soldier_request
-				&& (!(m_upgrade_soldier_request->is_open()))
-				&& 1 == m_upgrade_soldier_request->get_count()
-				&& (!incd))
-			{
-				drop_least_suited_soldier(false, nullptr);
-			}
-			else
-			{
-				update_upgrade_soldier_request();
-			}
-		}
-	}
-	else // not doing upgrade request
-	{
-		if ((capacity != stationed) or (m_normal_soldier_request))
-			update_normal_soldier_request();
-
-		if ((capacity == stationed) and (! m_normal_soldier_request))
-		{
-			if (presentSoldiers().size() == capacity)
-			{
-				m_doing_upgrade_request = true;
-				update_upgrade_soldier_request();
-			}
-			// Note -- if there are non-present stationed soldiers, nothing gets
-			// called. Therefore, I revisit this routine periodically without apparent
-			// reason, hoping that all stationed soldiers would be present.
-		}
-	}
+	m_garrison->cleanup_requests(egbase);
 }
 
 /*
@@ -553,60 +148,53 @@
 	// Maybe a new queueing system like MilitaryAct could be introduced.
 
 	ProductionSite::act(game, data);
-
-	const int32_t timeofgame = game.get_gametime();
-	if (m_normal_soldier_request && m_upgrade_soldier_request)
-	{
-		throw wexception("MilitarySite::act: Two soldier requests are ongoing -- should never happen!\n");
-	}
-
-	// I do not get a callback when stationed, non-present soldier returns --
-	// Therefore I must poll in some occasions. Let's do that rather infrequently,
-	// to keep the game lightweight.
-
-	//TODO: I would need two new callbacks, to get rid ot this polling.
-	if (timeofgame > m_next_swap_soldiers_time)
-		{
-			m_next_swap_soldiers_time = timeofgame + (m_soldier_upgrade_try ? 20000 : 100000);
-			update_soldier_request();
-		}
-
-	if (m_nexthealtime <= game.get_gametime()) {
-		uint32_t total_heal = descr().get_heal_per_second();
-		std::vector<Soldier *> soldiers = presentSoldiers();
-
-		for (uint32_t i = 0; i < soldiers.size(); ++i) {
-			Soldier & s = *soldiers[i];
-
-			// The healing algorithm is totally arbitrary
-			if (s.get_current_hitpoints() < s.get_max_hitpoints()) {
-				s.heal(total_heal);
-				break;
-			}
-		}
-
-		m_nexthealtime = game.get_gametime() + 1000;
-		schedule_act(game, 1000);
-	}
-}
-
-
-/**
- * The worker is about to be removed.
- *
- * After the removal of the worker, check whether we need to request
- * new soldiers.
- */
-void MilitarySite::remove_worker(Worker & w)
-{
-	ProductionSite::remove_worker(w);
-
-	if (upcast(Soldier, soldier, &w))
-		popSoldierJob(soldier, 0, 0);
-
-	update_soldier_request();
-}
-
+	m_garrison->act(game);
+	schedule_act(game, 1000);
+}
+
+/**
+===============
+Display number of soldiers.
+===============
+*/
+std::string MilitarySite::get_statistics_string()
+{
+	std::string str;
+	uint32_t present = m_garrison->presentSoldiers().size();
+	uint32_t total = m_garrison->stationedSoldiers().size();
+	uint32_t capacity = m_garrison->soldierCapacity();
+
+	if (present == total) {
+		str =
+			(boost::format
+				(ngettext(_("%u soldier"), _("%u soldiers"), total)) % total)
+				.str();
+	} else {
+		str =
+			(boost::format
+				(ngettext(_("%u(+%u) soldier"), _("%u(+%u) soldiers"), present))
+				% present % (total - present))
+				.str();
+	}
+
+	if (capacity > total) {
+		str += (boost::format(" (+%u)") %  (capacity - total)).str();
+	}
+
+	return str;
+}
+
+/**
+===============
+Change the economy for the wares queues.
+Note that the workers are dealt with in the PlayerImmovable code.
+===============
+*/
+void MilitarySite::set_economy(Economy * const e)
+{
+	ProductionSite::set_economy(e);
+	m_garrison->set_economy(e);
+}
 
 /**
  * Called by soldiers in the building.
@@ -614,490 +202,84 @@
 bool MilitarySite::get_building_work(Game & game, Worker & worker, bool)
 {
 	if (upcast(Soldier, soldier, &worker)) {
-		// Evict soldiers that have returned home if the capacity is too low
-		if (m_capacity < presentSoldiers().size()) {
-			worker.reset_tasks(game);
-			worker.start_task_leavebuilding(game, true);
-			return true;
-		}
-
-		bool stayhome;
-		uint8_t retreat;
-		if
-			(Map_Object * const enemy
-			 =
-			 popSoldierJob(soldier, &stayhome, &retreat))
-		{
-			if (upcast(Building, building, enemy)) {
-				soldier->start_task_attack
-					(game, *building, retreat);
-				return true;
-			} else if (upcast(Soldier, opponent, enemy)) {
-				if (!opponent->getBattle()) {
-					soldier->start_task_defense
-						(game, stayhome, retreat);
-					if (stayhome)
-						opponent->send_signal(game, "sleep");
-					return true;
-				}
-			} else
-				throw wexception("MilitarySite::get_building_work: bad SoldierJob");
-		}
+		return m_garrison->get_garrison_work(game, soldier);
 	}
-
 	return false;
 }
 
 
-/**
- * \return \c true if the soldier is currently present and idle in the building.
- */
-bool MilitarySite::isPresent(Soldier & soldier) const
-{
-	return
-		soldier.get_location(owner().egbase()) == this                     &&
-		soldier.get_state() == soldier.get_state(Worker::taskBuildingwork) &&
-		soldier.get_position() == get_position();
-}
-
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier *> MilitarySite::presentSoldiers() const
-{
-	std::vector<Soldier *> soldiers;
-
-	const std::vector<Worker *>& w = get_workers();
-	container_iterate_const(std::vector<Worker *>, w, i)
-		if (upcast(Soldier, soldier, *i.current))
-			if (isPresent(*soldier))
-				soldiers.push_back(soldier);
-
-	return soldiers;
-}
-
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier *> MilitarySite::stationedSoldiers() const
-{
-	std::vector<Soldier *> soldiers;
-
-	const std::vector<Worker *>& w = get_workers();
-	container_iterate_const(std::vector<Worker *>, w, i)
-		if (upcast(Soldier, soldier, *i.current))
-			soldiers.push_back(soldier);
-
-	return soldiers;
-}
-
-uint32_t MilitarySite::minSoldierCapacity() const throw () {
-	return 1;
-}
-uint32_t MilitarySite::maxSoldierCapacity() const throw () {
-	return descr().get_max_number_of_soldiers();
-}
-uint32_t MilitarySite::soldierCapacity() const
-{
-	return m_capacity;
-}
-
-void MilitarySite::setSoldierCapacity(uint32_t const capacity) {
-	assert(minSoldierCapacity() <= capacity);
-	assert                        (capacity <= maxSoldierCapacity());
-	assert(m_capacity != capacity);
-	m_capacity = capacity;
-	update_soldier_request();
-}
-
-void MilitarySite::dropSoldier(Soldier & soldier)
-{
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
-	if (!isPresent(soldier)) {
-		// This can happen when the "drop soldier" player command is delayed
-		// by network delay or a client has bugs.
-		molog("MilitarySite::dropSoldier(%u): not present\n", soldier.serial());
-		return;
-	}
-	if (presentSoldiers().size() <= minSoldierCapacity()) {
-		molog("cannot drop last soldier(s)\n");
-		return;
-	}
-
-	soldier.reset_tasks(game);
-	soldier.start_task_leavebuilding(game, true);
-
-	update_soldier_request();
-}
-
-
-void MilitarySite::conquer_area(Editor_Game_Base & egbase) {
-	assert(!m_didconquer);
-	egbase.conquer_area
-		(Player_Area<Area<FCoords> >
-		 	(owner().player_number(),
-		 	 Area<FCoords>
-		 	 	(egbase.map().get_fcoords(get_position()), get_conquers())));
-	m_didconquer = true;
-}
-
-
-bool MilitarySite::canAttack()
-{
-	return m_didconquer;
-}
-
-void MilitarySite::aggressor(Soldier & enemy)
-{
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-	Map  & map  = game.map();
-	if
-		(enemy.get_owner() == &owner() ||
-		 enemy.getBattle() ||
-		 get_conquers()
-		 <=
-		 map.calc_distance(enemy.get_position(), get_position()))
-		return;
-
-	if
-		(map.find_bobs
-		 	(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2),
-		 	 0,
-		 	 FindBobEnemySoldier(&owner())))
-		return;
-
-	// We're dealing with a soldier that we might want to keep busy
-	// Now would be the time to implement some player-definable
-	// policy as to how many soldiers are allowed to leave as defenders
-	std::vector<Soldier *> present = presentSoldiers();
-
-	if (1 < present.size())
-		container_iterate_const(std::vector<Soldier *>, present, i)
-			if (!haveSoldierJob(**i.current)) {
-				SoldierJob sj;
-				sj.soldier  = *i.current;
-				sj.enemy = &enemy;
-				sj.stayhome = false;
-				sj.retreat = owner().get_retreat_percentage();
-				m_soldierjobs.push_back(sj);
-				(*i.current)->update_task_buildingwork(game);
-				return;
-			}
-
-	// Inform the player, that we are under attack by adding a new entry to the
-	// message queue - a sound will automatically be played.
-	informPlayer(game, true);
-}
-
-bool MilitarySite::attack(Soldier & enemy)
-{
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
-	std::vector<Soldier *> present = presentSoldiers();
-	Soldier * defender = 0;
-
-	if (!present.empty()) {
-		// Find soldier with greatest hitpoints
-		uint32_t current_max = 0;
-		container_iterate_const(std::vector<Soldier *>, present, i)
-			if ((*i.current)->get_current_hitpoints() > current_max) {
-				defender = *i.current;
-				current_max = defender->get_current_hitpoints();
-			}
-	} else {
-		// If one of our stationed soldiers is currently walking into the
-		// building, give us another chance.
-		std::vector<Soldier *> stationed = stationedSoldiers();
-		container_iterate_const(std::vector<Soldier *>, stationed, i)
-			if ((*i.current)->get_position() == get_position()) {
-				defender = *i.current;
-				break;
-			}
-	}
-
-	if (defender) {
-		popSoldierJob(defender); // defense overrides all other jobs
-
-		SoldierJob sj;
-		sj.soldier = defender;
-		sj.enemy = &enemy;
-		sj.stayhome = true;
-		sj.retreat = 0;         // Flag defenders could not retreat
-		m_soldierjobs.push_back(sj);
-
-		defender->update_task_buildingwork(game);
-
-		// Inform the player, that we are under attack by adding a new entry to
-		// the message queue - a sound will automatically be played.
-		informPlayer(game);
-
-		return true;
-	} else {
-		// The enemy has defeated our forces, we should inform the player
-		const Coords coords = get_position();
-		{
-			char message[2048];
-			snprintf
-				(message, sizeof(message),
-				 _("The enemy defeated your soldiers at the %s."),
-				 descname().c_str());
-			send_message
-				(game,
-				 "site_lost",
-				 _("Militarysite lost!"),
-				 message);
-		}
-
-		// Now let's see whether the enemy conquers our militarysite, or whether
-		// we still hold the bigger military presence in that area (e.g. if there
-		// is a fortress one or two points away from our sentry, the fortress has
-		// a higher presence and thus the enemy can just burn down the sentry.
-		if (military_presence_kept(game)) {
-			// Okay we still got the higher military presence, so the attacked
-			// militarysite will be destroyed.
-			set_defeating_player(enemy.owner().player_number());
-			schedule_destroy(game);
-			return false;
-		}
-
-		// The enemy conquers the building
-		// In fact we do not conquer it, but place a new building of same type at
-		// the old location.
-		Player            * enemyplayer = enemy.get_owner();
-		const Tribe_Descr & enemytribe  = enemyplayer->tribe();
-
-		// Add suffix to all descr in former buildings in cases
-		// the new owner comes from another tribe
-		Building_Descr::FormerBuildings former_buildings;
-		BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
-			std::string bldname = old_descr->name();
-			// Has this building already a suffix? == conquered building?
-			std::string::size_type const dot = bldname.rfind('.');
-			if (dot >= bldname.size()) {
-				// Add suffix, if the new owner uses another tribe than we.
-				if (enemytribe.name() != owner().tribe().name())
-					bldname += "." + owner().tribe().name();
-			} else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
-				bldname = bldname.substr(0, dot);
-			Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
-			const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
-			former_buildings.push_back(former_descr);
-		}
-
-		// Now we destroy the old building before we place the new one.
-		set_defeating_player(enemy.owner().player_number());
+Garrison* MilitarySite::get_garrison() const
+{
+	return m_garrison.get();
+}
+
+Building* MilitarySite::get_building()
+{
+	return this;
+}
+
+void MilitarySite::garrison_occupied()
+{
+	start_animation(owner().egbase(), descr().get_animation("idle"));
+}
+
+void MilitarySite::garrison_lost(Game& game, Widelands::Player_Number defeating, bool captured)
+{
+	if (!captured) {
 		schedule_destroy(game);
-
-		enemyplayer->force_building(coords, former_buildings);
-		BaseImmovable * const newimm = game.map()[coords].get_immovable();
-		upcast(MilitarySite, newsite, newimm);
-		newsite->reinit_after_conqueration(game);
-
-		// Of course we should inform the victorious player as well
-		char message[2048];
-		snprintf
-			(message, sizeof(message),
-			 _("Your soldiers defeated the enemy at the %s."),
-			 newsite->descname().c_str());
-		newsite->send_message
-			(game,
-			 "site_defeated",
-			 _("Enemy at site defeated!"),
-			 message);
-
-		return false;
-	}
+		return;
+	}
+	// The enemy conquers the building
+	// In fact we do not conquer it, but place a new building of same type at
+	// the old location.
+	Player            * enemyplayer = game.get_player(defeating);
+	const Tribe_Descr & enemytribe  = enemyplayer->tribe();
+
+	// Add suffix to all descr in former buildings in cases
+	// the new owner comes from another tribe
+	Building_Descr::FormerBuildings former_buildings;
+	BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
+		std::string bldname = old_descr->name();
+		// Has this building already a suffix? == conquered building?
+		std::string::size_type const dot = bldname.rfind('.');
+		if (dot >= bldname.size()) {
+			// Add suffix, if the new owner uses another tribe than we.
+			if (enemytribe.name() != owner().tribe().name())
+				bldname += "." + owner().tribe().name();
+		} else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
+			bldname = bldname.substr(0, dot);
+		Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
+		const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
+		former_buildings.push_back(former_descr);
+	}
+
+	const Coords coords = get_position();
+	// Now we destroy the old building before we place the new one.
+	set_defeating_player(defeating);
+	schedule_destroy(game);
+
+	enemyplayer->force_building(coords, former_buildings);
+	BaseImmovable * const newimm = game.map()[coords].get_immovable();
+	upcast(GarrisonOwner, go, newimm);
+	go->reinit_after_conqueral(game);
+
+	// Of course we should inform the victorious player as well
+	upcast(Building, new_building, newimm);
+	std::string message =
+		(boost::format
+			(_("Your soldiers defeated the enemy at the %s."))
+			% new_building->descname())
+			.str();
+	new_building->send_message
+		(game, "site_defeated",
+			_("Enemy at site defeated!"),
+			message);
 }
 
-/// Initialises the militarysite after it was "conquered" (the old was replaced)
-void MilitarySite::reinit_after_conqueration(Game & game)
+void MilitarySite::reinit_after_conqueral(Game& game)
 {
-	clear_requirements();
-	conquer_area(game);
-	update_soldier_request();
+	m_garrison->reinit_after_conqueral(game);
 	start_animation(game, descr().get_animation("idle"));
 }
 
-/// Calculates whether the military presence is still kept and \returns true if.
-bool MilitarySite::military_presence_kept(Game & game)
-{
-	// collect information about immovables in the area
-	std::vector<ImmovableFound> immovables;
-
-	// Search in a radius of 3 (needed for big militarysites)
-	FCoords const fc = game.map().get_fcoords(get_position());
-	game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
-
-	for (uint32_t i = 0; i < immovables.size(); ++i)
-		if (upcast(MilitarySite const, militarysite, immovables[i].object))
-			if
-				(this       !=  militarysite          and
-				 &owner  () == &militarysite->owner() and
-				 get_size() <=  militarysite->get_size() and
-				 militarysite->m_didconquer)
-				return true;
-	return false;
-}
-
-/// Informs the player about an attack of his opponent.
-void MilitarySite::informPlayer(Game & game, bool const discovered)
-{
-	char message[2048];
-	snprintf
-		(message, sizeof(message),
-		 discovered ?
-		 _("Your %s discovered an aggressor.</p>") :
-		 _("Your %s is under attack.</p>"),
-		 descname().c_str());
-
-	// Add a message as long as no previous message was send from a point with
-	// radius <= 5 near the current location in the last 60 seconds
-	send_message
-		(game,
-		 "under_attack",
-		 _("You are under attack"),
-		 message,
-		 60 * 1000, 5);
-}
-
-
-/*
-   MilitarySite::set_requirements
-
-   Easy to use, overwrite with given requirements.
-*/
-void MilitarySite::set_requirements (const Requirements & r)
-{
-	m_soldier_requirements = r;
-}
-
-/*
-   MilitarySite::clear_requirements
-
-   This should cancel any requirement pushed at this house
-*/
-void MilitarySite::clear_requirements ()
-{
-	m_soldier_requirements = Requirements();
-}
-
-void MilitarySite::sendAttacker
-	(Soldier & soldier, Building & target, uint8_t retreat)
-{
-	assert(isPresent(soldier));
-
-	if (haveSoldierJob(soldier))
-		return;
-
-	SoldierJob sj;
-	sj.soldier  = &soldier;
-	sj.enemy    = &target;
-	sj.stayhome = false;
-	sj.retreat  = retreat;
-	m_soldierjobs.push_back(sj);
-
-	soldier.update_task_buildingwork
-		(ref_cast<Game, Editor_Game_Base>(owner().egbase()));
-}
-
-
-bool MilitarySite::haveSoldierJob(Soldier & soldier)
-{
-	container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i)
-		if (i.current->soldier == &soldier)
-			return true;
-
-	return false;
-}
-
-
-/**
- * \return the enemy, if any, that the given soldier was scheduled
- * to attack, and remove the job.
- */
-Map_Object * MilitarySite::popSoldierJob
-	(Soldier * const soldier, bool * const stayhome, uint8_t * const retreat)
-{
-	container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
-		if (i.current->soldier == soldier) {
-			Map_Object * const enemy = i.current->enemy.get(owner().egbase());
-			if (stayhome)
-				*stayhome = i.current->stayhome;
-			if (retreat)
-				*retreat = i.current->retreat;
-			m_soldierjobs.erase(i.current);
-			return enemy;
-		}
-	return 0;
-}
-
-
-/*
- * When upgrading soldiers, we do not ask for just any soldiers, but soldiers
- * that are better than what we already have. This routine sets the requirements
- * used by the request.
- *
- * The routine returns true if upgrade request thresholds have changed. This information could be
- * used to decide whether the soldier-Request should be upgraded.
- */
-bool
-MilitarySite::update_upgrade_requirements()
-{
-	int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
-	int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
-
-	if (kPrefersHeroes != m_soldier_preference && kPrefersRookies != m_soldier_preference)
-	{
-		log("MilitarySite::swapSoldiers: error: Unknown player preference %d.\n", m_soldier_preference);
-		m_soldier_upgrade_try = false;
-		return false;
-	}
-
-	// Find the level of the soldier that is currently least-suited.
-	Soldier * worst_guy = find_least_suited_soldier();
-	if (worst_guy == nullptr) {
-		// There could be no soldier in the militarysite right now. No reason to freak out.
-		return false;
-	}
-	int32_t wg_level = worst_guy->get_level(atrTotal);
-
-	// Micro-optimization: I assume that the majority of military sites have only level-zero
-	// soldiers and prefer rookies. Handle them separately.
-	m_soldier_upgrade_try = true;
-	if (kPrefersRookies == m_soldier_preference) {
-		if (0 == wg_level)
-			{
-				m_soldier_upgrade_try = false;
-				return false;
-			}
-	}
-
-	// Now I actually build the new requirements.
-	int32_t reqmin = kPrefersHeroes == m_soldier_preference ? 1 + wg_level : 0;
-	int32_t reqmax = kPrefersHeroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
-
-	bool maxchanged = reqmax != soldier_upgrade_required_max;
-	bool minchanged = reqmin != soldier_upgrade_required_min;
-
-	if (maxchanged or minchanged)
-	{
-		if (m_upgrade_soldier_request && (m_upgrade_soldier_request->is_open()))
-		{
-			m_upgrade_soldier_request.reset();
-		}
-		m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
-
-		return true;
-	}
-
-	return false;
-}
-
-// setters
-
-void
-MilitarySite::set_soldier_preference(MilitarySite::SoldierPreference p)
-{
-	assert(kPrefersHeroes == p || kPrefersRookies == p);
-	m_soldier_preference = p;
-	m_next_swap_soldiers_time = 0;
-}
-
 }

=== modified file 'src/logic/militarysite.h'
--- src/logic/militarysite.h	2013-07-26 20:19:36 +0000
+++ src/logic/militarysite.h	2013-08-06 10:09:46 +0000
@@ -20,10 +20,10 @@
 #ifndef MILITARYSITE_H
 #define MILITARYSITE_H
 
-#include "logic/attackable.h"
+#include "logic/garrison.h"
+#include "logic/garrisonhandler.h"
 #include "logic/productionsite.h"
 #include "logic/requirements.h"
-#include "logic/soldiercontrol.h"
 
 namespace Widelands {
 
@@ -53,121 +53,38 @@
 };
 
 class MilitarySite :
-	public ProductionSite, public SoldierControl, public Attackable
+	public ProductionSite, public GarrisonOwner
 {
 	friend struct Map_Buildingdata_Data_Packet;
 	MO_DESCR(MilitarySite_Descr);
 
 public:
-	// I assume elsewhere, that enum SoldierPreference fits to uint8_t.
-	enum SoldierPreference  : uint8_t {
-		kNoPreference,
-		kPrefersRookies,
-		kPrefersHeroes,
-	};
-
 	MilitarySite(const MilitarySite_Descr &);
 	virtual ~MilitarySite();
 
-	char const * type_name() const throw () {return "militarysite";}
-	virtual std::string get_statistics_string();
-
 	virtual void init(Editor_Game_Base &);
 	virtual void cleanup(Editor_Game_Base &);
 	virtual void act(Game &, uint32_t data);
-	virtual void remove_worker(Worker &);
+
+	char const * type_name() const throw () {return "militarysite";}
+	virtual std::string get_statistics_string();
 
 	virtual void set_economy(Economy *);
 	virtual bool get_building_work(Game &, Worker &, bool success);
 
-	// Begin implementation of SoldierControl
-	virtual std::vector<Soldier *> presentSoldiers() const;
-	virtual std::vector<Soldier *> stationedSoldiers() const;
-	virtual uint32_t minSoldierCapacity() const throw ();
-	virtual uint32_t maxSoldierCapacity() const throw ();
-	virtual uint32_t soldierCapacity() const;
-	virtual void setSoldierCapacity(uint32_t capacity);
-	virtual void dropSoldier(Soldier &);
-	virtual int incorporateSoldier(Editor_Game_Base & game, Soldier & s);
-	// End implementation of SoldierControl
-
-	// Begin implementation of Attackable
-	virtual Player & owner() const {return Building::owner();}
-	virtual bool canAttack();
-	virtual void aggressor(Soldier &);
-	virtual bool attack   (Soldier &);
-	// End implementation of Attackable
-
-	/**
-	 * Launch the given soldier on an attack towards the given
-	 * target building.
-	 */
-	void sendAttacker(Soldier &, Building &, uint8_t);
-
-	/// This methods are helper for use at configure this site.
-	void set_requirements  (const Requirements &);
-	void clear_requirements();
-	const Requirements & get_requirements () const {
-		return m_soldier_requirements;
-	}
-
-	void reinit_after_conqueration(Game &);
-
-	void update_soldier_request(bool i = false);
-
-	void set_soldier_preference(SoldierPreference);
-	SoldierPreference get_soldier_preference() const {
-			return m_soldier_preference;
-	}
+	// GarrisonOwner implementation
+	virtual Garrison* get_garrison() const;
+	virtual Building* get_building();
+	virtual void garrison_occupied();
+	virtual void garrison_lost(Game & game, Player_Number defeating, bool captured);
+	virtual void reinit_after_conqueral(Game& game);
 
 protected:
-	void conquer_area(Editor_Game_Base &);
-
 	virtual void create_options_window
 		(Interactive_GameBase &, UI::Window * & registry);
 
 private:
-	bool isPresent(Soldier &) const;
-	static void request_soldier_callback
-		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
-
-	Map_Object * popSoldierJob
-		(Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
-	bool haveSoldierJob(Soldier &);
-	bool military_presence_kept(Game &);
-	void informPlayer(Game &, bool discovered = false);
-	bool update_upgrade_requirements();
-	void update_normal_soldier_request();
-	void update_upgrade_soldier_request();
-	bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
-	Soldier * find_least_suited_soldier();
-	bool drop_least_suited_soldier(bool new_has_arrived, Soldier * s);
-
-
-private:
-	Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
-	RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
-	std::unique_ptr<Request> m_normal_soldier_request;  // filling the site
-	std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
-	bool m_didconquer;
-	uint32_t m_capacity;
-
-	/**
-	 * Next gametime where we should heal something.
-	 */
-	int32_t m_nexthealtime;
-
-	struct SoldierJob {
-		Soldier    * soldier;
-		Object_Ptr  enemy;
-		bool        stayhome;
-		uint8_t     retreat;
-	};
-	std::vector<SoldierJob> m_soldierjobs;
-	SoldierPreference m_soldier_preference;
-	int32_t m_next_swap_soldiers_time;
-	bool m_soldier_upgrade_try; // optimization -- if everybody is zero-level, do not downgrade
-	bool m_doing_upgrade_request;
+	std::unique_ptr<GarrisonHandler> m_garrison;
 };
 
 }

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2013-08-02 18:36:03 +0000
+++ src/logic/player.cc	2013-08-06 10:09:46 +0000
@@ -38,7 +38,6 @@
 #include "logic/militarysite.h"
 #include "logic/playercommand.h"
 #include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
 #include "logic/trainingsite.h"
 #include "logic/tribe.h"
 #include "logic/warehouse.h"
@@ -699,12 +698,14 @@
 
 void Player::military_site_set_soldier_preference(PlayerImmovable & imm, uint8_t m_soldier_preference)
 {
-	if (&imm.owner() == this)
-		if (upcast(MilitarySite, milsite, &imm))
-			milsite->set_soldier_preference(static_cast<MilitarySite::SoldierPreference>(m_soldier_preference));
+	if (&imm.owner() == this) {
+		if (upcast(GarrisonOwner, go, &imm)) {
+			Garrison* const garrison = go->get_garrison();
+			garrison->set_soldier_preference(static_cast<Garrison::SoldierPref>(m_soldier_preference));
+		}
+	}
 }
 
-
 /*
  * enhance this building, remove it, but give the constructionsite
  * an idea of enhancing
@@ -861,8 +862,9 @@
 		return;
 	if (soldier.get_worker_type() != Worker_Descr::SOLDIER)
 		return;
-	if (upcast(SoldierControl, ctrl, &imm))
-		ctrl->dropSoldier(soldier);
+	if (upcast(GarrisonOwner, go, &imm)) {
+		go->get_garrison()->dropSoldier(soldier);
+	}
 }
 
 /*
@@ -920,9 +922,10 @@
 
 	container_iterate_const(std::vector<BaseImmovable *>, flags, i) {
 		const Flag * attackerflag = static_cast<Flag *>(*i.current);
-		const MilitarySite * ms = static_cast<MilitarySite *>(attackerflag->get_building());
-		std::vector<Soldier *> const present = ms->presentSoldiers();
-		uint32_t const nr_staying = ms->minSoldierCapacity();
+		GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(attackerflag->get_building());
+		Garrison * garrison = go->get_garrison();
+		std::vector<Soldier *> const present = garrison->presentSoldiers();
+		uint32_t const nr_staying = garrison->minSoldierCapacity();
 		uint32_t const nr_present = present.size();
 		if (nr_staying < nr_present) {
 			uint32_t const nr_taken =
@@ -958,8 +961,8 @@
 		log("enemyflagaction: count is 0\n");
 	else if (is_hostile(flag.owner()))
 		if (Building * const building = flag.get_building())
-			if (upcast(Attackable, attackable, building))
-				if (attackable->canAttack()) {
+			if (upcast(GarrisonOwner, go, building))
+				if (go->get_garrison()->canAttack()) {
 					std::vector<Soldier *> attackers;
 					findAttackSoldiers(flag, &attackers, count);
 					assert(attackers.size() <= count);
@@ -969,10 +972,10 @@
 					retreat = std::min
 						(retreat, tribe().get_military_data().get_max_retreat());
 
-					container_iterate_const(std::vector<Soldier *>, attackers, i)
-						ref_cast<MilitarySite, PlayerImmovable>
-							(*(*i.current)->get_location(egbase()))
-						.sendAttacker(**i.current, *building, retreat);
+					container_iterate_const(std::vector<Soldier *>, attackers, i) {
+						upcast(GarrisonOwner, igo, (*i.current)->get_location(egbase()));
+						igo->get_garrison()->sendAttacker(**i.current, *building, retreat);
+					}
 				}
 }
 
@@ -1174,13 +1177,13 @@
 
 	const uint32_t nrecos = get_nr_economies();
 	for (uint32_t i = 0; i < nrecos; ++i) {
-		const std::vector<Widelands::Warehouse *> & warehouses =
-			get_economy_by_number(i)->warehouses();
+		const std::vector<Widelands::Storage *> & storages =
+			get_economy_by_number(i)->storages();
 
 		for
-			(std::vector<Widelands::Warehouse *>::const_iterator it =
-			 warehouses.begin();
-			 it != warehouses.end();
+			(std::vector<Widelands::Storage *>::const_iterator it =
+			 storages.begin();
+			 it != storages.end();
 			 ++it)
 		{
 			const Widelands::WareList & wares = (*it)->get_wares();

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2013-08-01 03:23:11 +0000
+++ src/logic/player.h	2013-08-06 10:09:46 +0000
@@ -638,7 +638,7 @@
 	std::vector< std::vector<uint32_t> > m_ware_consumptions;
 
 	/**
-	 * Statistics of wares stored inside of warehouses over the
+	 * Statistics of wares stored inside of storages over the
 	 * life of the game, indexed as
 	 * m_ware_stocks[ware_id][time_index]
 	 */

=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc	2013-07-31 17:00:28 +0000
+++ src/logic/playercommand.cc	2013-08-06 10:09:46 +0000
@@ -520,7 +520,7 @@
 PlayerCommand (0, des.Unsigned8())
 {
 	serial = des.Unsigned32();
-	preference = des.Unsigned8();
+	preference = static_cast<Garrison::SoldierPref>(des.Unsigned8());
 }
 
 void Cmd_MilitarySiteSetSoldierPreference::serialize (StreamWrite & ser)
@@ -528,7 +528,7 @@
 	ser.Unsigned8 (PLCMD_MILITARYSITESETSOLDIERPREFERENCE);
 	ser.Unsigned8 (sender());
 	ser.Unsigned32(serial);
-	ser.Unsigned8 (preference);
+	ser.Unsigned8 (static_cast<uint8_t>(preference));
 }
 
 void Cmd_MilitarySiteSetSoldierPreference::execute (Game & game)
@@ -549,7 +549,7 @@
 
 	// Now serial
 	const Map_Object & obj = *egbase.objects().get_object(serial);
-	fw.Unsigned8(preference);
+	fw.Unsigned8(static_cast<uint8_t>(preference));
 	fw.Unsigned32(mos.get_object_file_index(obj));
 }
 
@@ -561,7 +561,7 @@
 		const uint16_t packet_version = fr.Unsigned16();
 		if (packet_version == PLAYER_CMD_SOLDIERPREFERENCE_VERSION) {
 			PlayerCommand::Read(fr, egbase, mol);
-			preference = fr.Unsigned8();
+			preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
 			const uint32_t building_serial = fr.Unsigned32();
 			try {
 				serial = mol.get<Map_Object>(building_serial).serial();
@@ -1607,8 +1607,8 @@
 {
 	if (upcast(Building, building, game.objects().get_object(serial)))
 		if (&building->owner() == game.get_player(sender()))
-			if (upcast(SoldierControl, ctrl, building))
-				ctrl->changeSoldierCapacity(val);
+			if (upcast(GarrisonOwner, go, building))
+				go->get_garrison()->changeSoldierCapacity(val);
 }
 
 void Cmd_ChangeSoldierCapacity::serialize (StreamWrite & ser)
@@ -1906,18 +1906,18 @@
 /*** struct Cmd_SetStockPolicy ***/
 Cmd_SetStockPolicy::Cmd_SetStockPolicy
 	(int32_t time, Player_Number p,
-	 Warehouse & wh, bool isworker, Ware_Index ware,
-	 Warehouse::StockPolicy policy)
+	 StorageOwner & storage_owner, bool isworker, Ware_Index ware,
+	 Storage::StockPolicy policy)
 : PlayerCommand(time, p)
 {
-	m_warehouse = wh.serial();
+	m_storage_owner = storage_owner.get_building()->serial();
 	m_isworker = isworker;
 	m_ware = ware;
 	m_policy = policy;
 }
 
 Cmd_SetStockPolicy::Cmd_SetStockPolicy()
-: PlayerCommand(), m_warehouse(0), m_isworker(false), m_policy()
+: PlayerCommand(), m_storage_owner(0), m_isworker(false), m_policy()
 {
 }
 
@@ -1930,20 +1930,20 @@
 {
 	// Sanitize data that could have come from the network
 	if (Player * plr = game.get_player(sender())) {
-		if (upcast(Warehouse, warehouse, game.objects().get_object(m_warehouse)))
+		if (upcast(StorageOwner, storage_owner, game.objects().get_object(m_storage_owner)))
 		{
-			if (&warehouse->owner() != plr) {
+			if (&storage_owner->get_building()->owner() != plr) {
 				log
-					("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n",
-					 sender(), warehouse->owner().player_number());
+					("Cmd_SetStockPolicy: sender %u, but storage owner %u\n",
+					 sender(), storage_owner->get_building()->owner().player_number());
 				return;
 			}
 
 			switch (m_policy) {
-			case Warehouse::SP_Normal:
-			case Warehouse::SP_Prefer:
-			case Warehouse::SP_DontStock:
-			case Warehouse::SP_Remove:
+			case Storage::StockPolicy::Normal:
+			case Storage::StockPolicy::Prefer:
+			case Storage::StockPolicy::DontStock:
+			case Storage::StockPolicy::Remove:
 				break;
 			default:
 				log
@@ -1952,7 +1952,7 @@
 				return;
 			}
 
-			const Tribe_Descr & tribe = warehouse->tribe();
+			const Tribe_Descr & tribe = storage_owner->get_building()->tribe();
 			if (m_isworker) {
 				if (!(m_ware < tribe.get_nrworkers())) {
 					log
@@ -1960,7 +1960,7 @@
 						 sender(), m_ware.value());
 					return;
 				}
-				warehouse->set_worker_policy(m_ware, m_policy);
+				storage_owner->get_storage()->set_worker_policy(m_ware, m_policy);
 			} else {
 				if (!(m_ware < tribe.get_nrwares())) {
 					log
@@ -1968,7 +1968,7 @@
 						 sender(), m_ware.value());
 					return;
 				}
-				warehouse->set_ware_policy(m_ware, m_policy);
+				storage_owner->get_storage()->set_ware_policy(m_ware, m_policy);
 			}
 		}
 	}
@@ -1977,20 +1977,20 @@
 Cmd_SetStockPolicy::Cmd_SetStockPolicy(StreamRead & des)
 	: PlayerCommand(0, des.Unsigned8())
 {
-	m_warehouse = des.Unsigned32();
+	m_storage_owner = des.Unsigned32();
 	m_isworker = des.Unsigned8();
 	m_ware = Ware_Index(des.Unsigned8());
-	m_policy = static_cast<Warehouse::StockPolicy>(des.Unsigned8());
+	m_policy = static_cast<Storage::StockPolicy>(des.Unsigned8());
 }
 
 void Cmd_SetStockPolicy::serialize(StreamWrite & ser)
 {
 	ser.Unsigned8(PLCMD_SETSTOCKPOLICY);
 	ser.Unsigned8(sender());
-	ser.Unsigned32(m_warehouse);
+	ser.Unsigned32(m_storage_owner);
 	ser.Unsigned8(m_isworker);
 	ser.Unsigned8(m_ware.value());
-	ser.Unsigned8(m_policy);
+	ser.Unsigned8(static_cast<uint8_t>(m_policy));
 }
 
 #define PLAYER_CMD_SETSTOCKPOLICY_VERSION 1
@@ -2002,10 +2002,10 @@
 		if (version != PLAYER_CMD_SETSTOCKPOLICY_VERSION)
 			throw game_data_error("unknown/unhandled version %u", version);
 		PlayerCommand::Read(fr, egbase, mol);
-		m_warehouse = fr.Unsigned32();
+		m_storage_owner = fr.Unsigned32();
 		m_isworker = fr.Unsigned8();
 		m_ware = Ware_Index(fr.Unsigned8());
-		m_policy = static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
+		m_policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
 	} catch (const std::exception & e) {
 		throw game_data_error("Cmd_SetStockPolicy: %s", e.what());
 	}
@@ -2016,10 +2016,10 @@
 {
 	fw.Unsigned8(PLAYER_CMD_SETSTOCKPOLICY_VERSION);
 	PlayerCommand::Write(fw, egbase, mos);
-	fw.Unsigned32(m_warehouse);
+	fw.Unsigned32(m_storage_owner);
 	fw.Unsigned8(m_isworker);
 	fw.Unsigned8(m_ware.value());
-	fw.Unsigned8(m_policy);
+	fw.Unsigned8(static_cast<uint8_t>(m_policy));
 }
 
 }

=== modified file 'src/logic/playercommand.h'
--- src/logic/playercommand.h	2013-07-26 20:19:36 +0000
+++ src/logic/playercommand.h	2013-08-06 10:09:46 +0000
@@ -24,8 +24,8 @@
 #include "economy/flag.h"
 #include "logic/message_id.h"
 #include "logic/path.h"
+#include "logic/storage.h"
 #include "logic/trainingsite.h"
-#include "logic/warehouse.h"
 #include "logic/worker.h"
 
 namespace Widelands {
@@ -196,7 +196,8 @@
 
 struct Cmd_MilitarySiteSetSoldierPreference : public PlayerCommand {
 	Cmd_MilitarySiteSetSoldierPreference() : PlayerCommand(), serial(0) {} // For savegame loading
-	Cmd_MilitarySiteSetSoldierPreference (const int32_t t, const Player_Number p, Building & b, uint8_t prefs)
+	Cmd_MilitarySiteSetSoldierPreference
+		(const int32_t t, const Player_Number p, Building & b, Garrison::SoldierPref prefs)
 		: PlayerCommand(t, p), serial(b.serial()), preference(prefs)
 	{}
 
@@ -212,7 +213,7 @@
 
 private:
 	Serial serial;
-	uint8_t preference;
+	Garrison::SoldierPref preference;
 };
 struct Cmd_StartOrCancelExpedition : public PlayerCommand {
 	Cmd_StartOrCancelExpedition() : PlayerCommand() {} // For savegame loading
@@ -722,13 +723,13 @@
 };
 
 /**
- * Command to change the stock policy for a ware or worker in a warehouse.
+ * Command to change the stock policy for a ware or worker in a storage.
  */
 struct Cmd_SetStockPolicy : PlayerCommand {
 	Cmd_SetStockPolicy
 		(int32_t time, Player_Number p,
-		 Warehouse & wh, bool isworker, Ware_Index ware,
-		 Warehouse::StockPolicy policy);
+		 StorageOwner & storage_owner, bool isworker, Ware_Index ware,
+		 Storage::StockPolicy policy);
 
 	virtual uint8_t id() const;
 
@@ -744,10 +745,10 @@
 	void Read (FileRead  &, Editor_Game_Base &, Map_Map_Object_Loader &);
 
 private:
-	Serial m_warehouse;
+	Serial m_storage_owner;
 	bool m_isworker;
 	Ware_Index m_ware;
-	Warehouse::StockPolicy m_policy;
+	Storage::StockPolicy m_policy;
 };
 
 }

=== modified file 'src/logic/production_program.cc'
--- src/logic/production_program.cc	2013-07-26 20:19:36 +0000
+++ src/logic/production_program.cc	2013-08-06 10:09:46 +0000
@@ -32,12 +32,12 @@
 #include "logic/findnode.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
+#include "logic/garrison.h"
 #include "logic/mapregion.h"
 #include "logic/message_queue.h"
 #include "logic/player.h"
 #include "logic/productionsite.h"
 #include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
 #include "logic/trainingsite.h"
 #include "logic/tribe.h"
 #include "logic/worker_program.h"
@@ -1273,8 +1273,13 @@
 void ProductionProgram::ActCheck_Soldier::execute
 	(Game & game, ProductionSite & ps) const
 {
-	SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
-	const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
+	GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
+	if (!go) {
+		log("CGH no garrison owner for %s %u\n", ps.descr().descname().c_str(), ps.serial());
+		return;
+	}
+	Garrison* ga = go->get_garrison();
+	const std::vector<Soldier *> soldiers = ga->presentSoldiers();
 	const std::vector<Soldier *>::const_iterator soldiers_end = soldiers.end();
 
 	ps.molog("  Checking soldier (%u) level %d)\n", attribute, level);
@@ -1359,8 +1364,10 @@
 void ProductionProgram::ActTrain::execute
 	(Game & game, ProductionSite & ps) const
 {
-	SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
-	const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
+	GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
+	assert(go);
+	const Garrison* ga = go->get_garrison();
+	const std::vector<Soldier *> soldiers = ga->presentSoldiers();
 	const std::vector<Soldier *>::const_iterator soldiers_end =
 		soldiers.end();
 	std::vector<Soldier *>::const_iterator it = soldiers.begin();

=== modified file 'src/logic/soldier.cc'
--- src/logic/soldier.cc	2013-08-06 03:28:00 +0000
+++ src/logic/soldier.cc	2013-08-06 10:09:46 +0000
@@ -28,7 +28,6 @@
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "helper.h"
-#include "logic/attackable.h"
 #include "logic/battle.h"
 #include "logic/building.h"
 #include "logic/checkstep.h"
@@ -38,11 +37,11 @@
 #include "logic/findnode.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
+#include "logic/garrison.h"
 #include "logic/message_queue.h"
 #include "logic/militarysite.h"
 #include "logic/player.h"
 #include "logic/tribe.h"
-#include "logic/warehouse.h"
 #include "map_io/widelands_map_map_object_loader.h"
 #include "map_io/widelands_map_map_object_saver.h"
 #include "profile/profile.h"
@@ -764,7 +763,7 @@
 struct FindNodeOwned {
 	FindNodeOwned(Player_Number owner) : m_owner(owner)
 	{};
-	bool accept(const Map & map, const FCoords & coords) const {
+	bool accept(const Map &, const FCoords & coords) const {
 		return (coords.field->get_owned_by() == m_owner);
 	}
 private:
@@ -789,8 +788,6 @@
 void Soldier::start_task_attack
 	(Game & game, Building & building, uint8_t retreat)
 {
-	//dynamic_cast<const Attackable &>(building);
-
 	push_task(game, taskAttack);
 	State & state  = top_state();
 	state.objvar1  = &building;
@@ -960,13 +957,8 @@
 
 	// Count remaining defenders
 	if (enemy) {
-		if (upcast(MilitarySite, ms, enemy)) {
-			defenders = ms->presentSoldiers().size();
-		}
-		if (upcast(Warehouse, wh, enemy)) {
-			Requirements noreq;
-			defenders = wh->count_workers
-				(game, wh->tribe().worker_index("soldier"), noreq);
+		if (upcast(GarrisonOwner, garrison_owner, enemy)) {
+			defenders = garrison_owner->get_garrison()->presentSoldiers().size();
 		}
 		//  Any enemy soldier at baseflag count as defender.
 		std::vector<Bob *> soldiers;
@@ -996,20 +988,18 @@
 			BaseImmovable * const newimm = game.map()[state.coords].get_immovable();
 			upcast(MilitarySite, newsite, newimm);
 			if (newsite and (&newsite->owner() == &owner())) {
-				if (upcast(SoldierControl, ctrl, newsite)) {
-					state.objvar1 = 0;
-					if
-						(ctrl->stationedSoldiers().size() < ctrl->soldierCapacity() and
-						location->base_flag().get_position()
-						!=
-						newsite ->base_flag().get_position())
-					{
-						molog("[attack] enemy belongs to us now, move in\n");
-						pop_task(game);
-						set_location(newsite);
-						newsite->update_soldier_request();
-						return schedule_act(game, 10);
-					}
+				state.objvar1 = 0;
+				if
+					(newsite->get_garrison()->stationedSoldiers().size()
+						< newsite->get_garrison()->soldierCapacity() and
+					location->base_flag().get_position()
+					!=
+					newsite ->base_flag().get_position())
+				{
+					molog("[attack] enemy belongs to us now, move in\n");
+					pop_task(game);
+					set_location(newsite);
+					return schedule_act(game, 10);
 				}
 			}
 		}
@@ -1039,12 +1029,12 @@
 		}
 	}
 
-	upcast(Attackable, attackable, enemy);
-	assert(attackable);
+	upcast(GarrisonOwner, garrison_o, enemy);
+	assert(garrison_o);
 
 	molog("[attack] attacking target building\n");
 	//  give the enemy soldier some time to act
-	schedule_act(game, attackable->attack(*this) ? 1000 : 10);
+	schedule_act(game, garrison_o->get_garrison()->attack(*this) ? 1000 : 10);
 }
 
 void Soldier::attack_pop(Game & game, State &)
@@ -1788,13 +1778,17 @@
 			 CheckStepWalkOn(descr().movecaps(), false),
 			 FindImmovableAttackable());
 
-		container_iterate_const(std::vector<BaseImmovable *>, attackables, i)
+		container_iterate_const(std::vector<BaseImmovable *>, attackables, i) {
+			const BaseImmovable* base_imm = *i.current;
 			if
-				(ref_cast<PlayerImmovable const, BaseImmovable const>(**i.current)
-				 .get_owner()->player_number()
-				 ==
-				 land_owner)
-				dynamic_cast<Attackable &>(**i.current).aggressor(*this);
+				(ref_cast<PlayerImmovable const, BaseImmovable const>(*base_imm)
+				 .get_owner()->player_number() == land_owner)
+			{
+				if (upcast(const GarrisonOwner, go, base_imm)) {
+					go->get_garrison()->aggressor(*this);
+				}
+			}
+		}
 	}
 }
 

=== removed file 'src/logic/soldiercontrol.h'
--- src/logic/soldiercontrol.h	2012-02-15 21:25:34 +0000
+++ src/logic/soldiercontrol.h	1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2008 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef SOLDIERCONTROL_H
-#define SOLDIERCONTROL_H
-
-#include <vector>
-
-namespace Widelands {
-
-class Soldier;
-
-/**
- * This interface is implemented by buildings that explicitly house soldiers.
- *
- * It is used to implement queries for building UI and to implement commands
- * that change the soldiers stationed in a building.
- *
- * Soldiers are \em stationed in a building if that building is their
- * \ref Worker::location. Stationed soldiers are \em present in a building
- * if their current position is inside the building. So for a TrainingSite,
- * the two concepts are equal. However, they're different for a MilitarySite,
- * where soldiers can be outside in combat.
- */
-struct SoldierControl {
-	/**
-	 * \return a list of soldiers that are currently present in the building.
-	 */
-	virtual std::vector<Soldier *> presentSoldiers() const = 0;
-
-	/**
-	 * \return a list of soldiers that are currently stationed in the building.
-	 */
-	virtual std::vector<Soldier *> stationedSoldiers() const = 0;
-
-	/**
-	 * \return the minimum number of soldiers that this building can be
-	 * configured to hold.
-	 */
-	virtual uint32_t minSoldierCapacity() const = 0;
-
-	/**
-	 * \return the maximum number of soldiers that this building can be
-	 * configured to hold.
-	 */
-	virtual uint32_t maxSoldierCapacity() const = 0;
-
-	/**
-	 * \return the number of soldiers this building is configured to hold
-	 * right now.
-	 */
-	virtual uint32_t soldierCapacity() const = 0;
-
-	/**
-	 * Sets the capacity for soldiers of this building.
-	 *
-	 * New soldiers will be requested and old soldiers will be evicted
-	 * as necessary.
-	 */
-	virtual void setSoldierCapacity(uint32_t capacity) = 0;
-
-	void changeSoldierCapacity(int32_t const difference) {
-		uint32_t const old_capacity = soldierCapacity();
-		uint32_t const new_capacity =
-			std::min
-				(static_cast<uint32_t>
-				 	(std::max
-				 	 	(static_cast<int32_t>(old_capacity) + difference,
-				 	 	 static_cast<int32_t>(minSoldierCapacity()))),
-				 maxSoldierCapacity());
-		if (old_capacity != new_capacity)
-			setSoldierCapacity(new_capacity);
-	}
-
-	/**
-	 * Evict the given soldier from the building immediately,
-	 * without changing the building's capacity.
-	 *
-	 * \note This has no effect if the soldier is currently involved in a battle
-	 * or otherwise blocked from leaving the building.
-	 */
-	virtual void dropSoldier(Soldier &) = 0;
-
-	/**
-	 * Add a new soldier into this site. Returns -1 if there is no space
-	 * for him, 0 on success
-	 */
-	virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
-
-	/**
-	 * Remove a soldier from the internal list. Most SoldierControls will be
-	 * informed by the soldier when it is removed, but WareHouses for example
-	 * will not.
-	 */
-	virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) {return 0;}
-
-protected:
-	virtual ~SoldierControl() {}
-};
-
-}
-
-#endif // SOLDIERCONTROL_H

=== added file 'src/logic/storage.h'
--- src/logic/storage.h	1970-01-01 00:00:00 +0000
+++ src/logic/storage.h	2013-08-06 10:09:46 +0000
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include <vector>
+
+#include "logic/requirements.h"
+#include "logic/wareworker.h"
+#include "logic/widelands.h"
+
+namespace Widelands {
+
+class Building;
+class Worker;
+class Editor_Game_Base;
+class Game;
+class WareInstance;
+class WareList;
+class Player;
+
+/**
+ *  A storage represents wares and workers stocks. It is owned by StrorageOwner buildings.
+ * This interface contains various method used to deal with wares requests, prioriies
+ * and disponibility.
+ */
+class Storage {
+public:
+	/**
+	 * Each ware and worker type has an associated per-storage
+	 * stock policy that defines whether it will be stocked by this
+	 * warehouse.
+	 *
+	 * \note The values of this enum are written directly into savegames,
+	 * so be careful when changing them.
+	 */
+	enum class StockPolicy : uint8_t {
+		/**
+		 * The default policy allows stocking wares without any special priority.
+		 */
+		Normal = 0,
+
+		/**
+		 * As long as there are warehouses with this policy for a ware, all
+		 * available unstocked supplies will be transferred to warehouses
+		 * with this policy.
+		 */
+		Prefer = 1,
+
+		/**
+		 * If a ware has this stock policy, no new items of this ware will enter
+		 * the warehouse.
+		 */
+		DontStock = 2,
+
+		/**
+		 * Like \ref SP_DontStock, but in addition, existing stock of this ware
+		 * will be transported out of the warehouse over time.
+		 */
+		Remove = 3,
+	};
+
+	/**
+	 * \return the player that own this storage
+	 */
+	virtual Player & owner() const = 0;
+	/**
+	 * \return the wares present in this storage
+	 */
+	virtual const WareList & get_wares() const = 0;
+	/**
+	 * \return the workers present in this storage
+	 */
+	virtual const WareList & get_workers() const = 0;
+	/**
+	 * Increase the stock of the specified ware type
+	 */
+	virtual void insert_wares  (Ware_Index, uint32_t count) = 0;
+	/**
+	 * Decrease the stock of the specified ware type
+	 */
+	virtual void remove_wares  (Ware_Index, uint32_t count) = 0;
+	/**
+	 * Increase the stock of the specified worker type
+	 */
+	virtual void insert_workers(Ware_Index, uint32_t count) = 0;
+	/**
+	 * Decrease the stock of the specified worker type
+	 */
+	virtual void remove_workers(Ware_Index, uint32_t count) = 0;
+	/**
+	 * Get a specified ware from the storage.
+	 * \return the wareinstance
+	 */
+	virtual WareInstance & launch_ware(Game &, Ware_Index) = 0;
+	/**
+	 * Launch a ware already instanciated
+	 */
+	virtual void do_launch_ware(Game &, WareInstance&) = 0;
+	/**
+	 * Adds the specified ware to the storage. The ware might
+	 * be removed from the game following this call.
+	 */
+	virtual void incorporate_ware(Editor_Game_Base &, WareInstance &) = 0;
+	/**
+	 * Get the specified worker from the storage.
+	 * \return the worker
+	 */
+	virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements()) = 0;
+	/**
+	 * Adds the specified worker to the storage. The worker might
+	 * be removed from the game following this call.
+	 */
+	virtual void incorporate_worker(Editor_Game_Base &, Worker &) = 0;
+	/**
+	 * \return the storage stock policy for the specified ware
+	 */
+	virtual StockPolicy get_ware_policy(Ware_Index ware) const = 0;
+	/**
+	 * \return the storage stock policy for the specified worker
+	 */
+	virtual StockPolicy get_worker_policy(Ware_Index ware) const = 0;
+	/**
+	 * \return the sotrage stock policy for the specified ware or worker
+	 */
+	virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const = 0;
+	/**
+	 * Set the storage stock policy for the specified ware
+	 */
+	virtual void set_ware_policy(Ware_Index ware, StockPolicy policy) = 0;
+	/**
+	 * Set the storage stock policy for the specified worker
+	 */
+	virtual void set_worker_policy(Ware_Index ware, StockPolicy policy) = 0;
+	/**
+	 * Return true if the storage has all requirement in stock to create
+	 * the specified worker
+	 */
+	virtual bool can_create_worker(Game& game, Ware_Index ware_index) = 0;
+	/**
+	 * Create a worker.
+	 */
+	virtual void create_worker(Game& game, Ware_Index worker_idx) = 0;
+	/**
+	 * Return the amount of planned worker of the given worker idx
+	 */
+	virtual uint32_t get_planned_workers(Game &, Ware_Index index) const = 0;
+	/**
+	 * Plan to create the specified workers
+	 */
+	virtual void plan_workers(Game &, Ware_Index index, uint32_t amount) = 0;
+	/**
+	 * Calculate the supply of wares available to this warehouse in each of the
+	 * buildcost items for the given worker.
+	 *
+	 * This is the current stock plus any incoming transfers.
+	 */
+	virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const = 0;
+};
+
+/**
+ * A Storage owner holds a sorage instance.
+ */
+class StorageOwner {
+public:
+	/**
+	 * Return the storage instance
+	 */
+	virtual Storage* get_storage() const = 0;
+	/**
+	 * Return the building owning the storage
+	 */
+	virtual Building* get_building() = 0;
+};
+
+}
+
+#endif

=== added file 'src/logic/storagehandler.cc'
--- src/logic/storagehandler.cc	1970-01-01 00:00:00 +0000
+++ src/logic/storagehandler.cc	2013-08-06 10:09:46 +0000
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "logic/storagehandler.h"
+
+#include <utility>
+
+#include <boost/foreach.hpp>
+
+#include "economy/economy.h"
+#include "economy/flag.h"
+#include "logic/player.h"
+#include "logic/soldier.h"
+#include "upcast.h"
+#include <helper.h>
+
+namespace Widelands {
+
+//************************************************************
+// CLASS Storage Handler
+//************************************************************
+
+StorageHandler::StorageHandler(Building& building)
+:  m_building(building),
+	m_supply(new StorageSupply(this))
+{
+}
+
+StorageHandler::~StorageHandler()
+{
+}
+
+
+void StorageHandler::init(Editor_Game_Base& )
+{
+	Ware_Index const nr_wares   = owner().tribe().get_nrwares  ();
+	Ware_Index const nr_workers = owner().tribe().get_nrworkers();
+	m_supply->set_nrwares  (nr_wares);
+	m_supply->set_nrworkers(nr_workers);
+	m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+	m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
+
+	// Init autospawn
+	const std::vector <Widelands::Ware_Index> worker_types_without_cost =
+		owner().tribe().worker_types_without_cost();
+	BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
+		const Worker_Descr & worker_descr = *owner().tribe().get_worker_descr(idx);
+		if (not worker_descr.is_buildable()) {
+			continue;
+		}
+		if (!owner().is_worker_type_allowed(idx)) {
+			continue;
+		}
+		if (worker_descr.buildcost().empty()) {
+			//  Workers of this type can be spawned in warehouses. Start it.
+			add_worker_spawn(idx);
+		}
+	}
+}
+
+void StorageHandler::load_finish(Editor_Game_Base& )
+{
+	// Ensure consistency of PlannedWorker requests
+	uint32_t pwidx = 0;
+	while (pwidx < m_planned_workers.size()) {
+		if (!load_finish_planned_workers(m_planned_workers[pwidx])) {
+			m_planned_workers[pwidx].cleanup();
+			m_planned_workers.erase(m_planned_workers.begin() + pwidx);
+		} else {
+			pwidx++;
+		}
+	}
+	// Verify autospawning for free workers
+	const std::vector <Widelands::Ware_Index> worker_types_without_cost =
+		owner().tribe().worker_types_without_cost();
+	BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
+		if (!owner().is_worker_type_allowed(idx)) {
+			continue;
+		}
+		if (is_worker_spawn_set(idx)) {
+			continue;
+		}
+		add_worker_spawn(idx);
+		log
+			("WARNING: player %u is allowed to create worker type %s but his "
+				"%s %u at (%i, %i) does not have spawning set for that "
+				"worker type; setting it to default values\n",
+				owner().player_number(),
+				owner().tribe().get_worker_descr(idx)->descname().c_str(),
+				m_building.descname().c_str(), m_building.serial(),
+			   m_building.get_position().x, m_building.get_position().y);
+	}
+}
+
+
+void StorageHandler::cleanup(Editor_Game_Base&)
+{
+	while (!m_planned_workers.empty()) {
+		m_planned_workers.back().cleanup();
+		m_planned_workers.pop_back();
+	}
+}
+
+//TODO return a value so the owner can schedule_act
+uint32_t StorageHandler::act(Game& game)
+{
+	uint32_t gametime = static_cast<uint32_t>(game.get_gametime());
+	uint32_t spawn_act = update_spawns(game, gametime);
+	uint32_t removal_act = update_removals(game, gametime);
+	// Update planned workers; this is to update the request amounts and
+	// check because whether we suddenly can produce a requested worker. This
+	// is mostly previously available wares may become unavailable due to
+	// secondary requests.
+	update_all_planned_workers(game);
+	// Act in 5 sec, or before if timers will run down
+	uint32_t min_act = 5000;
+	if (spawn_act > 0 && spawn_act < min_act) {
+		min_act = spawn_act;
+	}
+	if (removal_act > 0 && removal_act < min_act) {
+		min_act = removal_act;
+	}
+	return min_act;
+}
+
+void StorageHandler::set_economy(Economy* economy)
+{
+	Economy * const old = m_building.get_economy();
+
+	if (old == economy) {
+		return;
+	}
+
+	if (old) {
+		old->remove_storage(*this);
+	}
+
+	m_supply->set_economy(economy);
+
+	container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
+		container_iterate_const(std::vector<Request *>, pw_it.current->requests, req_it) {
+				(*req_it.current)->set_economy(economy);
+			}
+	}
+
+	if (economy) {
+		economy->add_storage(*this);
+	}
+}
+
+uint32_t StorageHandler::count_workers(Game& game, Ware_Index idx, const Requirements& req)
+{
+	uint32_t stock = m_supply->stock_workers(idx);
+	if (stock <= 0) {
+		return stock;
+	}
+	uint32_t matching = 0;
+	// Get list of those for which we stored the attributes
+	// This is similar logic than in launch_worker
+	std::vector<const StockedWorkerAtr*> workers_with_atr;
+	BOOST_FOREACH(StockedWorkerAtr& atr, m_stocked_workers_atr) {
+		if (atr.index == idx) {
+			workers_with_atr.push_back(&atr);
+		}
+	}
+	// First check those without atr
+	Worker* w;
+	bool checkpass = false;
+	const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
+	if (stock > workers_with_atr.size()) {
+		w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
+		checkpass = req.check(*w);
+		if (checkpass) {
+			matching += stock - workers_with_atr.size();
+		}
+		w->remove(game);
+	}
+	// Check with our atr
+	// TODO CGH use smarter way of storing atr, maybe with map
+	BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
+		w = create_with_atr(game, *atr);
+		checkpass = req.check(*w);
+		if (checkpass) {
+			matching++;
+		}
+		w->remove(game);
+	}
+	return matching;
+}
+
+
+void StorageHandler::launch_all_workers(Game & game, bool exp_only, const WareList& excluded)
+{
+	if (!exp_only) {
+		for (Ware_Index id = Ware_Index::First(); id < m_supply->get_workers().get_nrwareids(); ++id) {
+			if (excluded.stock(id)) {
+				continue;
+			}
+			const uint32_t stock = m_supply->get_workers().stock(id);
+			if (stock > 0) {
+				for (uint32_t i = 0; i < stock; ++i) {
+					launch_worker(game, id).start_task_leavebuilding(game, true);
+				}
+			}
+		}
+		return;
+	}
+	BOOST_FOREACH(StockedWorkerAtr atr, m_stocked_workers_atr) {
+		if (excluded.stock(atr.index)) {
+			continue;
+		}
+		if (m_supply->get_workers().stock(atr.index) <= 0) {
+			continue;
+		}
+		Worker* w = create_with_atr(game, atr);
+		w->start_task_leavebuilding(game, true);
+		m_supply->remove_workers(atr.index, 1);
+	}
+}
+
+void StorageHandler::add_ware_spawn
+	(const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
+{
+	if (m_spawn_wares.count(idx)) {
+		remove_ware_spawn(idx);
+	}
+	if (dont_exceed) {
+		std::vector<uint32_t> values = {interval, interval, stock_max};
+		m_spawn_wares.insert(std::make_pair(idx, values));
+	} else {
+		std::vector<uint32_t> values = {interval, interval, stock_max, counter};
+		m_spawn_wares.insert(std::make_pair(idx, values));
+	}
+}
+
+void StorageHandler::remove_ware_spawn(const Ware_Index idx)
+{
+	m_spawn_wares.erase(idx);
+}
+bool StorageHandler::is_ware_spawn_set(Ware_Index idx)
+{
+	return m_spawn_wares.count(idx);
+}
+
+
+void StorageHandler::add_worker_spawn
+	(const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
+{
+	if (m_spawn_workers.count(idx)) {
+		remove_worker_spawn(idx);
+	}
+	if (dont_exceed) {
+		std::vector<uint32_t> values = {interval, interval, stock_max};
+		m_spawn_workers.insert(std::make_pair(idx, values));
+	} else {
+		std::vector<uint32_t> values = {interval, interval, stock_max, counter};
+		m_spawn_workers.insert(std::make_pair(idx, values));
+	}
+}
+
+void StorageHandler::remove_worker_spawn(const Ware_Index idx)
+{
+	m_spawn_workers.erase(idx);
+}
+bool StorageHandler::is_worker_spawn_set(Ware_Index idx)
+{
+	return m_spawn_workers.count(idx);
+}
+
+//
+//
+//  Storage implementation
+//
+//
+
+Player& StorageHandler::owner() const
+{
+	return m_building.owner();
+}
+
+const WareList& StorageHandler::get_wares() const
+{
+	return m_supply->get_wares();
+}
+
+const WareList& StorageHandler::get_workers() const
+{
+	return m_supply->get_workers();
+}
+
+void StorageHandler::insert_wares(Ware_Index idx, uint32_t count)
+{
+	m_supply->add_wares(idx, count);
+}
+
+void StorageHandler::remove_wares(Ware_Index idx, uint32_t count)
+{
+	m_supply->remove_wares(idx, count);
+}
+
+void StorageHandler::insert_workers(Ware_Index idx, uint32_t count)
+{
+	m_supply->add_workers(idx, count);
+}
+
+void StorageHandler::remove_workers(Ware_Index idx, uint32_t count)
+{
+	m_supply->remove_workers(idx, count);
+}
+
+WareInstance& StorageHandler::launch_ware(Game& game, Ware_Index idx)
+{
+	WareInstance & item = *new WareInstance(idx, owner().tribe().get_ware_descr(idx));
+	item.init(game);
+	do_launch_ware(game, item);
+
+	m_supply->remove_wares(idx, 1);
+
+	return item;
+}
+
+
+void StorageHandler::do_launch_ware(Game& game, WareInstance& ware_inst)
+{
+	// Create a carrier
+	Ware_Index const carrierid = owner().tribe().worker_index("carrier");
+	const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(carrierid);
+
+	Worker & worker = workerdescr.create(game, owner(), &m_building, m_building.get_position());
+
+	// Yup, this is cheating.
+	if (m_supply->stock_workers(carrierid))
+		m_supply->remove_workers(carrierid, 1);
+
+	// Setup the carrier
+	worker.start_task_dropoff(game, ware_inst);
+}
+
+
+void StorageHandler::incorporate_ware(Editor_Game_Base& egbase, WareInstance& item)
+{
+	m_supply->add_wares(item.descr_index(), 1);
+	return item.destroy(egbase);
+}
+
+Worker& StorageHandler::launch_worker(Game& game, Ware_Index idx, const Requirements& req)
+{
+	do {
+		uint32_t stock = m_supply->stock_workers(idx);
+		if (stock > 0) {
+			// Get list of those for which we stored the attributes, as pointers to actual objects
+			// TODO smarter storage for atrs
+			std::vector<const StockedWorkerAtr*> workers_with_atr;
+			for
+				(std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
+					it != m_stocked_workers_atr.end(); ++it)
+			{
+				if ((*it).index == idx) {
+					workers_with_atr.push_back(&(*it));
+				}
+			}
+			// First check if one without atr is enough
+			Worker* w;
+			if (stock > workers_with_atr.size()) {
+				const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
+				w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
+				if (req.check(*w)) {
+					m_supply->remove_workers(idx, 1);
+					return *w;
+				}
+			}
+			// Check with our atr
+			BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
+				w = create_with_atr(game, *atr);
+				if (req.check(*w)) {
+					// We need to find back our atr in original vector to erase it
+					bool removed = false;
+					for
+						(std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
+						 it != m_stocked_workers_atr.end(); ++it)
+					{
+						if (&(*it) == atr) {
+							m_stocked_workers_atr.erase(it);
+							removed = true;
+							break;
+						}
+					}
+					assert(removed);
+					m_supply->remove_workers(idx, 1);
+					return *w;
+				}
+			}
+		}
+		// Check if we got the tools to create a new one
+		if (can_create_worker(game, idx)) {
+			// don't want to use an upgraded worker, so create new one.
+			create_worker(game, idx);
+		} else {
+			idx = owner().tribe().get_worker_descr(idx)->becomes();
+		}
+	} while (idx != Ware_Index::Null());
+
+	throw wexception
+		("StorageHandler::launch_worker: worker does not actually exist");
+}
+
+void StorageHandler::incorporate_worker(Editor_Game_Base& egbase, Worker& w)
+{
+	assert(w.get_owner() == &owner());
+	// Rescue carried ware
+	if (WareInstance * const item = w.fetch_carried_item(egbase)) {
+		incorporate_ware(egbase, *item);
+	}
+	// Add to supply
+	Ware_Index worker_index = owner().tribe().worker_index(w.name().c_str());
+	m_supply->add_workers(worker_index, 1);
+
+	// Store the attributes.
+	// FIXME CGH handle soldiers : hp & healing
+	StockedWorkerAtr* atr = store_worker_atr(w);
+	if (atr != nullptr) {
+		m_stocked_workers_atr.push_back(*atr);
+	}
+	// Destroy the instance
+	w.remove(egbase);
+}
+
+Storage::StockPolicy StorageHandler::get_ware_policy(Ware_Index ware) const
+{
+	assert(ware.value() < m_ware_policy.size());
+	return m_ware_policy[ware.value()];
+}
+
+Storage::StockPolicy StorageHandler::get_worker_policy(Ware_Index ware) const
+{
+	assert(ware.value() < m_worker_policy.size());
+	return m_worker_policy[ware.value()];
+}
+
+Storage::StockPolicy StorageHandler::get_stock_policy(WareWorker waretype, Ware_Index wareindex) const
+{
+	if (waretype == wwWORKER)
+		return get_worker_policy(wareindex);
+	else
+		return get_ware_policy(wareindex);
+}
+
+void StorageHandler::set_ware_policy(Ware_Index ware, Storage::StockPolicy policy)
+{
+	assert(ware.value() < m_ware_policy.size());
+	m_ware_policy[ware.value()] = policy;
+}
+
+void StorageHandler::set_worker_policy(Ware_Index ware, Storage::StockPolicy policy)
+{
+	assert(ware.value() < m_worker_policy.size());
+	m_worker_policy[ware.value()] = policy;
+}
+
+bool StorageHandler::can_create_worker(Game&, Ware_Index worker_idx)
+{
+	if (not (worker_idx < m_supply->get_workers().get_nrwareids())) {
+		throw wexception
+			("worker type %d does not exists (max is %d)",
+			 worker_idx.value(), m_supply->get_workers().get_nrwareids().value());
+	}
+
+	const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
+	assert(&w_desc);
+	if (not w_desc.is_buildable()) {
+		return false;
+	}
+
+	//  see if we have the resources
+	const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
+	container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
+		const std::string & input_name = it.current->first;
+		if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+			if (m_supply->stock_wares  (id_w) < it.current->second)
+				return false;
+		} else if ((id_w = owner().tribe().worker_index(input_name))) {
+			if (m_supply->stock_workers(id_w) < it.current->second)
+				return false;
+		} else
+			throw wexception
+				("worker type %s needs \"%s\" to be built but that is neither "
+				 "a ware type nor a worker type defined in the tribe %s",
+				 w_desc.descname().c_str(), input_name.c_str(),
+				 owner().tribe().name().c_str());
+	}
+	return true;
+}
+
+void StorageHandler::create_worker(Game& game, Ware_Index worker_idx)
+{
+	assert(can_create_worker (game, worker_idx));
+
+	const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
+	const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
+	container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
+		const std::string & input = i.current->first;
+		if (Ware_Index const id_ware = owner().tribe().ware_index(input)) {
+			remove_wares  (id_ware,                        i.current->second);
+			//update statistic accordingly
+			owner().ware_consumed(id_ware, i.current->second);
+		} else
+			remove_workers(owner().tribe().safe_worker_index(input), i.current->second);
+	}
+
+	incorporate_worker(game, w_desc.create(game, owner(), &m_building, m_building.get_position()));
+
+	// Update PlannedWorkers::amount here if appropriate, because this function
+	// may have been called directly by the Economy.
+	// Do not update anything else about PlannedWorkers here, because this
+	// function is called by _update_planned_workers, so avoid recursion
+	container_iterate(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
+		if (pw_it.current->index == worker_idx && pw_it.current->amount) {
+			pw_it.current->amount--;
+		}
+	}
+}
+
+uint32_t StorageHandler::get_planned_workers(Game&, Ware_Index index) const
+{
+	container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
+		if (i.current->index == index)
+			return i.current->amount;
+	}
+
+	return 0;
+}
+
+void StorageHandler::plan_workers(Game& game, Ware_Index index, uint32_t amount)
+{
+	PlannedWorkers * pw = 0;
+
+	container_iterate(std::vector<PlannedWorkers>, m_planned_workers, i) {
+		if (i.current->index == index) {
+			pw = &*i.current;
+			break;
+		}
+	}
+
+	if (!pw) {
+		if (!amount)
+			return;
+
+		m_planned_workers.push_back(PlannedWorkers());
+		pw = &m_planned_workers.back();
+		pw->index = index;
+		pw->amount = 0;
+
+		const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(pw->index);
+		const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+		container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
+			const std::string & input_name = cost_it.current->first;
+
+			if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+				pw->requests.push_back
+					(new Request
+					 (m_building, id_w, &StorageHandler::planned_worker_callback, wwWARE));
+			} else if ((id_w = owner().tribe().worker_index(input_name))) {
+				pw->requests.push_back
+					(new Request
+					 (m_building, id_w, &StorageHandler::planned_worker_callback, wwWORKER));
+			} else
+				throw wexception
+					("plan_workers: bad buildcost '%s'", input_name.c_str());
+		}
+	}
+
+	pw->amount = amount;
+	update_planned_workers(game, *pw);
+}
+
+std::vector< uint32_t > StorageHandler::calc_available_for_worker(Game&, Ware_Index index) const
+{
+	const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(index);
+	const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+	std::vector<uint32_t> available;
+
+	container_iterate_const(Worker_Descr::Buildcost, cost, bc) {
+		const std::string & input_name = bc.current->first;
+		if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
+			available.push_back(get_wares().stock(id_w));
+		} else if ((id_w = owner().tribe().worker_index(input_name))) {
+			available.push_back(get_workers().stock(id_w));
+		} else
+			throw wexception
+				("StorageHandler::calc_available_for_worker: buildcost inconsistency '%s'",
+				 input_name.c_str());
+	}
+
+	container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
+		if (i.current->index == index) {
+			assert(available.size() == i.current->requests.size());
+
+			for (uint32_t idx = 0; idx < available.size(); ++idx)
+				available[idx] += i.current->requests[idx]->get_num_transfers();
+		}
+	}
+
+	return available;
+}
+
+
+//
+//
+//
+// Private methods
+//
+//
+
+uint32_t StorageHandler::update_spawns(Game&, uint32_t gametime)
+{
+	uint32_t min_act = 0;
+	// Update spawnings
+	SpawnMapType::iterator it;
+	for (it = m_spawn_wares.begin(); it != m_spawn_wares.end();) {
+		Ware_Index idx = (*it).first;
+		std::vector<uint32_t> values = (*it).second;
+		bool dont_exceed = values.size() < 4;
+		bool infinite = dont_exceed || values[3] == 0;
+		uint32_t stock = m_supply->stock_wares(idx);
+		uint32_t stock_max = values[2];
+		// Skip if max stock excessed for non infinite spawns
+		if (stock_max > 0 && stock >= stock_max && !dont_exceed) {
+			++it;
+			continue;
+		}
+		// update timer
+		uint32_t* next_act = &((*it).second[0]);
+		if (*next_act > gametime) {
+			++it;
+			continue;
+		}
+		uint32_t interval = values[1];
+		while (*next_act <= gametime) {
+			*next_act += interval;
+		}
+		if (!infinite) {
+			// decrease counter
+			uint32_t* counter_p = &((*it).second[3]);
+			(*counter_p)--;
+			m_supply->add_wares(idx, 1);
+			if ((*counter_p) == 0) {
+				m_spawn_wares.erase(it++);
+				continue;
+			}
+		} else {
+			// infinte spawns
+			if (stock < stock_max) {
+				m_supply->add_wares(idx, 1);
+			} else if (stock > stock_max && dont_exceed) {
+				m_supply->remove_wares(idx, 1);
+			}
+		}
+		++it;
+		uint32_t time_till_next_act = *next_act - gametime;
+		min_act = (min_act == 0 ? time_till_next_act :
+			min_act > time_till_next_act ? time_till_next_act : min_act);
+	}
+	for (it = m_spawn_workers.begin(); it != m_spawn_workers.end();) {
+		Ware_Index idx = (*it).first;
+		std::vector<uint32_t> values = (*it).second;
+		bool dont_exceed = values.size() < 4;
+		bool infinite = dont_exceed || values[3] == 0;
+		uint32_t stock = m_supply->stock_workers(idx);
+		uint32_t stock_max = values[2];
+		// Skip if max stock excessed for non infinite spawns
+		if (stock_max > 0 && stock >= stock_max && !dont_exceed) {
+			++it;
+			continue;
+		}
+		// update timer
+		uint32_t* next_act = &((*it).second[0]);
+		if (*next_act > gametime) {
+			++it;
+			continue;
+		}
+		uint32_t interval = values[1];
+		while (*next_act <= gametime) {
+			*next_act += interval;
+		}
+		if (!infinite) {
+			// decrease counter
+			uint32_t* counter_p = &((*it).second[3]);
+			(*counter_p)--;
+			m_supply->add_workers(idx, 1);
+			if ((*counter_p) == 0) {
+				m_spawn_workers.erase(it++);
+				continue;
+			}
+		} else {
+			// infinte spawns
+			if (stock < stock_max) {
+				m_supply->add_workers(idx, 1);
+			} else if (stock > stock_max && dont_exceed) {
+				m_supply->remove_workers(idx, 1);
+			}
+		}
+		++it;
+		uint32_t time_till_next_act = *next_act - gametime;
+		min_act = (min_act == 0 ? time_till_next_act :
+			min_act > time_till_next_act ? time_till_next_act : min_act);
+	}
+
+	return min_act;
+}
+
+uint32_t StorageHandler::update_removals(Game& game, uint32_t gametime)
+{
+	if (m_removal_next_act > gametime) {
+		return gametime - m_removal_next_act;
+	}
+	while (m_removal_next_act <= gametime) {
+		m_removal_next_act += STORAGE_REMOVAL_INTERVAL;
+	}
+	if (m_building.base_flag().current_items() < m_building.base_flag().total_capacity() / 2) {
+		for (Ware_Index ware = Ware_Index::First(); ware.value() < m_ware_policy.size(); ++ware) {
+			if (get_ware_policy(ware) != StockPolicy::Remove || !get_wares().stock(ware)) {
+				continue;
+			}
+			launch_ware(game, ware);
+			break;
+		}
+	}
+
+	for (Ware_Index widx = Ware_Index::First(); widx.value() < m_worker_policy.size(); ++widx) {
+		if (get_worker_policy(widx) != StockPolicy::Remove || !get_workers().stock(widx)) {
+			continue;
+		}
+		Worker & worker = launch_worker(game, widx);
+		worker.start_task_leavebuilding(game, true);
+		break;
+	}
+	return gametime - m_removal_next_act;
+}
+
+void StorageHandler::update_all_planned_workers(Game& game)
+{
+	uint32_t idx = 0;
+	while (idx < m_planned_workers.size()) {
+		update_planned_workers(game, m_planned_workers[idx]);
+
+		if (!m_planned_workers[idx].amount) {
+			m_planned_workers[idx].cleanup();
+			m_planned_workers.erase(m_planned_workers.begin() + idx);
+		} else {
+			idx++;
+		}
+	}
+}
+
+void StorageHandler::update_planned_workers
+	(Game& game, StorageHandler::PlannedWorkers& planned_workers)
+{
+	const Tribe_Descr& tribe_descr = owner().tribe();
+	const Worker_Descr & w_desc = *tribe_descr.get_worker_descr(planned_workers.index);
+	const Worker_Descr::Buildcost & cost = w_desc.buildcost();
+
+	while (planned_workers.amount && can_create_worker(game, planned_workers.index)) {
+		create_worker(game, planned_workers.index);
+	}
+
+	uint32_t idx = 0;
+	container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
+		const std::string & input_name = cost_it.current->first;
+		uint32_t supply;
+
+		if (Ware_Index id_w = tribe_descr.ware_index(input_name)) {
+			supply = m_supply->stock_wares(id_w);
+		} else if ((id_w = tribe_descr.worker_index(input_name))) {
+			supply = m_supply->stock_workers(id_w);
+		} else {
+			throw wexception
+				("_update_planned_workers: bad buildcost '%s'", input_name.c_str());
+		}
+
+		if (supply >= planned_workers.amount * cost_it.current->second) {
+			planned_workers.requests[idx]->set_count(0);
+		} else {
+			planned_workers.requests[idx]->set_count
+				(planned_workers.amount * cost_it.current->second - supply);
+		}
+		++idx;
+	}
+
+	while (planned_workers.requests.size() > idx) {
+		delete planned_workers.requests.back();
+		planned_workers.requests.pop_back();
+	}
+}
+
+StorageHandler::StockedWorkerAtr* StorageHandler::store_worker_atr(Worker& w)
+{
+	if (upcast(Soldier, s, &w)) {
+		if
+			(!s->get_attack_level()
+			&& !s->get_defense_level()
+			&& !s->get_evade_level()
+			&& !s->get_hp_level())
+		{
+			return nullptr;
+		}
+		StockedWorkerAtr* atr = new StockedWorkerAtr();
+		atr->atck_lvl = s->get_attack_level();
+		atr->defense_lvl = s->get_defense_level();
+		atr->evade_lvl = s->get_evade_level();
+		atr->exp_or_hp_lvl = s->get_hp_level();
+		atr->index = w.descr().worker_index();
+		atr->descr = &w.descr();
+		return atr;
+	}
+	// Normal worker - only exp
+	if (w.get_current_experience() <= 0) {
+		return nullptr;
+	}
+	StockedWorkerAtr* atr = new StockedWorkerAtr();
+	atr->exp_or_hp_lvl = w.get_current_experience();
+	atr->index = w.descr().worker_index();
+	atr->descr = &w.descr();
+	return atr;
+}
+
+Worker* StorageHandler::create_with_atr(Game& game, StockedWorkerAtr atr)
+{
+	Worker* w = &atr.descr->create(game, owner(), &m_building, m_building.get_position());
+	if (upcast(Soldier, s, w)) {
+		s->set_attack_level(atr.atck_lvl);
+		s->set_defense_level(atr.defense_lvl);
+		s->set_evade_level(atr.evade_lvl);
+		s->set_hp_level(atr.exp_or_hp_lvl);
+		return w;
+	}
+	w->set_experience(atr.exp_or_hp_lvl);
+	return w;
+}
+
+
+void StorageHandler::PlannedWorkers::cleanup()
+{
+	while (!requests.empty()) {
+		delete requests.back();
+		requests.pop_back();
+	}
+}
+
+void StorageHandler::planned_worker_callback
+	(Game& game, Request&, const Ware_Index ware, Worker* const w, PlayerImmovable& target)
+{
+	upcast(StorageOwner, owner, &target);
+	upcast(StorageHandler, sh, owner->get_storage());
+	if (w) {
+		w->schedule_incorporate(game);
+	} else {
+		sh->m_supply->add_wares(ware, 1);
+
+		// This ware may be used to build planned workers,
+		// so it seems like a good idea to update the associated requests
+		// and use the ware before it is sent away again.
+		sh->update_all_planned_workers(game);
+	}
+}
+
+/**
+ * Try to bring the given \ref PlannedWorkers up to date with our game data.
+ * Return \c false if \p pw cannot be salvaged.
+ */
+bool StorageHandler::load_finish_planned_workers(PlannedWorkers & pw)
+{
+	if (!pw.index || !(pw.index < m_supply->get_workers().get_nrwareids()))
+		return false;
+
+	const Worker_Descr * w_desc = owner().tribe().get_worker_descr(pw.index);
+	if (!w_desc || !w_desc->is_buildable())
+		return false;
+
+	const Worker_Descr::Buildcost & cost = w_desc->buildcost();
+	uint32_t idx = 0;
+
+	for
+		(Worker_Descr::Buildcost::const_iterator cost_it = cost.begin();
+		 cost_it != cost.end(); ++cost_it, ++idx)
+	{
+		WareWorker type;
+		Ware_Index ware;
+
+		if ((ware = owner().tribe().ware_index(cost_it->first)))
+			type = wwWARE;
+		else if ((ware = owner().tribe().worker_index(cost_it->first)))
+			type = wwWORKER;
+		else
+			return false;
+
+		if (idx < pw.requests.size()) {
+			if
+				(pw.requests[idx]->get_type() == type &&
+				 pw.requests[idx]->get_index() == ware)
+				continue;
+
+			std::vector<Request *>::iterator req_it =
+				pw.requests.begin() + idx + 1;
+			while (req_it != pw.requests.end()) {
+				if ((*req_it)->get_type() == type && (*req_it)->get_index() == ware)
+					break;
+				++req_it;
+			}
+
+			if (req_it != pw.requests.end()) {
+				std::swap(*req_it, pw.requests[idx]);
+				continue;
+			}
+		}
+
+		log
+			("_load_finish_planned_worker: old savegame: "
+			 "need to create new request for '%s'\n",
+			 cost_it->first.c_str());
+		pw.requests.insert
+			(pw.requests.begin() + idx,
+			 new Request(m_building, ware, &StorageHandler::planned_worker_callback, type));
+	}
+
+	while (pw.requests.size() > idx) {
+		log
+			("_load_finish_planned_worker: old savegame: "
+			 "removing outdated request.\n");
+		delete pw.requests.back();
+		pw.requests.pop_back();
+	}
+
+	return true;
+}
+
+
+// *************************************************************
+//
+// Class StorageSupply
+//
+// *************************************************************
+
+StorageSupply::StorageSupply(StorageHandler* handler)
+:  m_handler(*handler),
+	m_economy(nullptr)
+{
+}
+
+StorageSupply::~StorageSupply()
+{
+	if (m_economy) {
+		log
+			("StorageSupply::~StorageSupply: %s %u still belongs to "
+			 "an economy", m_handler.get_building().descname().c_str(),
+			 m_handler.get_building().serial());
+		set_economy(nullptr);
+	}
+
+	// We're removed from the Economy. Therefore, the wares can simply
+	// be cleared out. The global inventory will be okay.
+	m_wares  .clear();
+	m_workers.clear();
+}
+
+void StorageSupply::set_economy(Economy* const e)
+{
+	if (e == m_economy)
+		return;
+
+	if (m_economy) {
+		m_economy->remove_supply(*this);
+		for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
+			if (m_wares.stock(i))
+				m_economy->remove_wares(i, m_wares.stock(i));
+		for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
+			if (m_workers.stock(i))
+				m_economy->remove_workers(i, m_workers.stock(i));
+	}
+
+	m_economy = e;
+
+	if (m_economy) {
+		for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
+			if (m_wares.stock(i))
+				m_economy->add_wares(i, m_wares.stock(i));
+		for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
+			if (m_workers.stock(i))
+				m_economy->add_workers(i, m_workers.stock(i));
+		m_economy->add_supply(*this);
+	}
+}
+
+void StorageSupply::set_nrwares(Ware_Index i)
+{
+	assert(Ware_Index::First() == m_wares.get_nrwareids());
+	m_wares.set_nrwares(i);
+}
+void StorageSupply::set_nrworkers(Ware_Index i)
+{
+	assert(Ware_Index::First() == m_workers.get_nrwareids());
+	m_workers.set_nrwares(i);
+}
+
+void StorageSupply::add_wares(Ware_Index id, uint32_t count)
+{
+	if (!count)
+		return;
+
+	if (m_economy) // No economies in the editor
+		m_economy->add_wares(id, count);
+	m_wares.add(id, count);
+}
+void StorageSupply::remove_wares(Ware_Index id, uint32_t count)
+{
+	if (!count)
+		return;
+
+	m_wares.remove(id, count);
+	if (m_economy) // No economies in the editor
+		m_economy->remove_wares(id, count);
+}
+void StorageSupply::add_workers(Ware_Index id, uint32_t count)
+{
+	if (!count)
+		return;
+
+	if (m_economy) // No economies in the editor
+		m_economy->add_workers(id, count);
+	m_workers.add(id, count);
+}
+void StorageSupply::remove_workers(Ware_Index id, uint32_t count)
+{
+	if (!count)
+		return;
+
+	m_workers.remove(id, count);
+	if (m_economy) // No economies in the editor
+		m_economy->remove_workers(id, count);
+}
+
+PlayerImmovable* StorageSupply::get_position(Game&)
+{
+	return &m_handler.get_building();
+}
+
+bool StorageSupply::is_active() const throw ()
+{
+	return false;
+}
+
+bool StorageSupply::has_storage() const throw ()
+{
+	return true;
+}
+
+void StorageSupply::get_ware_type(WareWorker&, Ware_Index&) const
+{
+	throw wexception
+		("StorageSupply::get_ware_type: calling this is nonsensical");
+}
+
+void StorageSupply::send_to_storage(Game&, StorageOwner*)
+{
+	throw wexception("StorageSupply::send_to_storage: should never be called");
+}
+
+uint32_t StorageSupply::nr_supplies(const Game&, const Request& req) const
+{
+	// out count_worker method create a worker instance, so we need non-const game
+	Game& non_const_game = ref_cast<Game, Editor_Game_Base>
+		(m_handler.get_building().get_owner()->egbase());
+	if (req.get_type() == wwWORKER)
+		return
+			m_handler.count_workers
+				(non_const_game, req.get_index(), req.get_requirements());
+
+	//  Calculate how many wares can be sent out - it might be that we need them
+	// ourselves. E.g. for hiring new soldiers.
+	int32_t const x = m_wares.stock(req.get_index());
+	// only mark an item of that type as available, if the priority of the
+	// request + number of that wares in warehouse is > priority of request
+	// of *this* warehouse + 1 (+1 is important, as else the ware would directly
+	// be taken back to the warehouse as the request of the warehouse would be
+	// highered and would have the same value as the original request)
+	int32_t const y =
+		x + (req.get_priority(0) / 100)
+		- (m_handler.get_building().get_priority(wwWARE, req.get_index()) / 100) - 1;
+	// But the number should never be higher than the number of wares available
+	if (y > x)
+		return x;
+	return (x > 0) ? x : 0;
+}
+
+WareInstance& StorageSupply::launch_item(Game& game, const Request& req)
+{
+	if (req.get_type() != wwWARE)
+		throw wexception("WarehouseSupply::launch_item: called for non-ware request");
+	if (!m_wares.stock(req.get_index()))
+		throw wexception("WarehouseSupply::launch_item: called for non-existing ware");
+
+	return m_handler.launch_ware(game, req.get_index());
+}
+
+Worker& StorageSupply::launch_worker(Game& game, const Request& req)
+{
+	return m_handler.launch_worker(game, req.get_index(), req.get_requirements());
+}
+
+}

=== added file 'src/logic/storagehandler.h'
--- src/logic/storagehandler.h	1970-01-01 00:00:00 +0000
+++ src/logic/storagehandler.h	2013-08-06 10:09:46 +0000
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef STORAGEHANDLER_H
+#define STORAGEHANDLER_H
+
+#include <memory>
+
+#include "economy/supply.h"
+#include "logic/requirements.h"
+#include "logic/storage.h"
+#include "logic/warelist.h"
+
+#define STORAGE_REMOVAL_INTERVAL 4000
+
+namespace Widelands {
+
+class Worker_Descr;
+
+class Economy;
+class StorageSupply;
+
+class StorageHandler: public Storage {
+friend struct Map_Buildingdata_Data_Packet;
+public:
+	// Spawning. vector is {next_act, interval, stock_max, [counter]}
+	typedef std::map<Ware_Index, std::vector<uint32_t>> SpawnMapType;
+
+	StorageHandler(Building& building);
+	virtual ~StorageHandler();
+	/**
+	 * Must be called once
+	 */
+	void init(Editor_Game_Base &);
+	/**
+	 * To be called after loading
+	 */
+	void load_finish(Editor_Game_Base &);
+	/**
+	 * Cleanup handled objects and requests
+	 */
+	void cleanup(Editor_Game_Base &);
+	/**
+	 * Must be called regularly
+	 * \return the time, from now, where a next act should occur
+	 */
+	uint32_t act(Game &);
+	/**
+	 * Change the economy
+	 */
+	void set_economy(Economy *);
+	/**
+	 * Return the number of workers satisfying the given requirement that this
+	 * storage has in stock
+	 */
+	uint32_t count_workers(Game & game, Ware_Index ware, const Requirements & req = Requirements());
+	/**
+	 * Launch all workers in the storage.
+	 * \param excluded : A WareList with some non-zero value for the
+	 * worker type to exclude
+	 */
+	void launch_all_workers(Game& game, bool exp_only = false, const WareList& excluded = WareList());
+	/**
+	 * Introduce auto spawning of the specified ware
+	 * \param idx The ware to autospawn
+	 * \param interval The interval between spawns. default to 2500
+	 * \param stock_max While the stock is above this value, spawning is disabled. Default to 100.
+	 * 0 for infinite spawning
+	 * \param counter The amount of wares to spawn. default to 0 (infinite).
+	 * \param dont_excdeed if true (default), ware will be removed as well to not exceed stock_max
+	 */
+	void add_ware_spawn
+		(Ware_Index idx, uint32_t interval = 2500, uint32_t stock_max = 100,
+		 uint32_t counter = 0, bool dont_exceed = true);
+	/**
+	 * Disable autospawning of the specified ware
+	 */
+	void remove_ware_spawn(Ware_Index idx);
+	bool is_ware_spawn_set(Ware_Index idx);
+	/**
+	 * Introduce auto spawning of the specified worker
+	 * \param idx The worker to autospawn
+	 * \param interval The interval between spawns. default to 2500 (2,5s)
+	 * \param stock_max While the stock is above this value, spawning is disabled. Default to 100.
+	 * 0 for infinite spawning
+	 * \param counter The amount of workers to spawn. default to 0.
+	 * \param dont_excdeed if true (default), ware will be removed as well to not exceed stock_max
+	 */
+	void add_worker_spawn
+		(Ware_Index idx, uint32_t interval = 2500, uint32_t stock_max = 100,
+		 uint32_t counter = 0,  bool dont_exceed = true);
+	/**
+	 * Remove autospawning of the specified worker
+	 */
+	void remove_worker_spawn(Ware_Index idx);
+	bool is_worker_spawn_set(Ware_Index idx);
+	/**
+	 * «return the building associated with this storage
+	 */
+	Building& get_building() const {return m_building;}
+
+	// Sorage implementation
+	virtual Player & owner() const;
+	virtual const WareList & get_wares() const;
+	virtual const WareList & get_workers() const;
+	virtual void insert_wares  (Ware_Index, uint32_t count);
+	virtual void remove_wares  (Ware_Index, uint32_t count);
+	virtual void insert_workers(Ware_Index, uint32_t count);
+	virtual void remove_workers(Ware_Index, uint32_t count);
+	virtual WareInstance & launch_ware(Game &, Ware_Index);
+	virtual void do_launch_ware(Game &, WareInstance&);
+	virtual void incorporate_ware(Editor_Game_Base &, WareInstance &);
+	virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements());
+	virtual void incorporate_worker(Editor_Game_Base &, Worker &);
+	virtual StockPolicy get_ware_policy(Ware_Index ware) const;
+	virtual StockPolicy get_worker_policy(Ware_Index ware) const;
+	virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const;
+	virtual void set_ware_policy(Ware_Index ware, StockPolicy policy);
+	virtual void set_worker_policy(Ware_Index ware, StockPolicy policy);
+	virtual bool can_create_worker(Game& game, Ware_Index worker_idx);
+	virtual void create_worker(Game& game, Ware_Index worker_idx);
+	virtual uint32_t get_planned_workers(Game &, Ware_Index index) const;
+	virtual void plan_workers(Game &, Ware_Index index, uint32_t amount);
+	virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const;
+private:
+	/**
+	 * Plan to produce a certain worker type in this warehouse. This means
+	 * requesting all the necessary wares, if multiple different wares types are
+	 * needed.
+	 */
+	struct PlannedWorkers {
+		/// Index of the worker type we plan to create
+		Ware_Index index;
+		/// How many workers of this type are we supposed to create?
+		uint32_t amount;
+		/// Requests to obtain the required build costs
+		std::vector<Request *> requests;
+		void cleanup();
+	};
+	/**
+	 * Store attributes of stocked worker so they can be removed from the game
+	 * without loosing experience & co informations
+	 */
+	struct StockedWorkerAtr {
+		Ware_Index index;
+		const Worker_Descr* descr;
+		uint32_t atck_lvl;
+		uint32_t evade_lvl;
+		uint32_t defense_lvl;
+		uint32_t exp_or_hp_lvl; // experience or hp level for soldiers
+	};
+
+	// return time for next act
+	uint32_t update_spawns(Game& game, uint32_t gametime);
+	// return time for next act
+	uint32_t update_removals(Game & game, uint32_t gametime);
+	void update_all_planned_workers(Game& game);
+	void update_planned_workers(Game& game, PlannedWorkers& planned_workers);
+	StockedWorkerAtr* store_worker_atr(Worker& w);
+	Worker* create_with_atr(Game& game, StockedWorkerAtr atr);
+	static void planned_worker_callback
+		(Game            &       game,
+		Request         &,
+		Ware_Index        const ware,
+		Worker          * const w,
+		PlayerImmovable &       target);
+	bool load_finish_planned_workers(PlannedWorkers & pw);
+
+	//fields
+	Building & m_building;
+	std::unique_ptr<StorageSupply> m_supply;
+	// policies
+	std::vector<StockPolicy> m_ware_policy;
+	std::vector<StockPolicy> m_worker_policy;
+	// Spawning
+	SpawnMapType m_spawn_wares;
+	SpawnMapType m_spawn_workers;
+	// ware removal
+	uint32_t m_removal_next_act;
+	// planned workers
+	std::vector<PlannedWorkers> m_planned_workers;
+	// Attributes of stocked workers
+	std::vector<StockedWorkerAtr> m_stocked_workers_atr;
+};
+
+/**
+ * A supply implementation for storages
+ */
+class StorageSupply : public Supply {
+public:
+	StorageSupply(StorageHandler* handler);
+	virtual ~StorageSupply();
+
+	void set_economy(Economy *);
+
+	void set_nrwares  (Ware_Index);
+	void set_nrworkers(Ware_Index);
+
+	const WareList & get_wares  () const {return m_wares;}
+	const WareList & get_workers() const {return m_workers;}
+	uint32_t stock_wares  (Ware_Index const i) const {
+		return m_wares  .stock(i);
+	}
+	uint32_t stock_workers(Ware_Index const i) const {
+		return m_workers.stock(i);
+	}
+	void add_wares     (Ware_Index, uint32_t count);
+	void remove_wares  (Ware_Index, uint32_t count);
+	void add_workers   (Ware_Index, uint32_t count);
+	void remove_workers(Ware_Index, uint32_t count);
+
+	// Supply implementation
+	virtual PlayerImmovable * get_position(Game &);
+	virtual bool is_active() const throw ();
+	virtual bool has_storage() const throw ();
+	virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
+
+	virtual void send_to_storage(Game &, StorageOwner * storage_owner);
+	virtual uint32_t nr_supplies(const Game &, const Request &) const;
+	virtual WareInstance & launch_item(Game &, const Request &);
+	virtual Worker & launch_worker(Game &, const Request &);
+private:
+	StorageHandler & m_handler;
+	Economy   * m_economy;
+	WareList    m_wares;
+	WareList    m_workers; //  we use this to keep the soldiers
+};
+
+}
+
+#endif

=== modified file 'src/logic/trainingsite.cc'
--- src/logic/trainingsite.cc	2013-07-26 20:19:36 +0000
+++ src/logic/trainingsite.cc	2013-08-06 10:09:46 +0000
@@ -20,12 +20,14 @@
 #include "logic/trainingsite.h"
 
 #include <cstdio>
+#include <memory>
 
 #include "economy/request.h"
 #include "helper.h"
 #include "i18n.h"
 #include "logic/editor_game_base.h"
 #include "logic/game.h"
+#include "logic/garrisonhandler.h"
 #include "logic/player.h"
 #include "logic/production_program.h"
 #include "logic/soldier.h"
@@ -157,9 +159,6 @@
 
 TrainingSite::TrainingSite(const TrainingSite_Descr & d) :
 ProductionSite   (d),
-m_soldier_request(0),
-m_capacity       (descr().get_max_number_of_soldiers()),
-m_build_heroes    (false),
 m_result         (Failed)
 {
 	// Initialize this in the constructor so that loading code may
@@ -178,7 +177,13 @@
 		init_kick_state(atrDefense, d);
 	if (d.get_train_evade())
 		init_kick_state(atrEvade, d);
+	GarrisonHandler * ga = new GarrisonHandler
+		(*this, 0, descr().get_max_number_of_soldiers(),
+		 descr().get_conquers(), 0, Garrison::SoldierPref::Rookies, true);
+		// FIXME put soldierpref in desc
+	m_garrison.reset(ga);
 }
+
 void
 TrainingSite::init_kick_state(const tAttribute & art, const TrainingSite_Descr & d)
 {
@@ -203,31 +208,26 @@
 void TrainingSite::init(Editor_Game_Base & egbase)
 {
 	ProductionSite::init(egbase);
-
-	upcast(Game, game, &egbase);
-
-	container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
-		(*i.current)->set_location_initially(*this);
-		assert(not (*i.current)->get_state()); //  Should be newly created.
-
-		if (game)
-			(*i.current)->start_task_idle(*game, 0, -1);
+	m_garrison->init(egbase);
+	const std::vector<Worker*>& ws = get_workers();
+	container_iterate_const(std::vector<Worker *>, ws, i) {
+		if (upcast(Soldier, soldier, *i.current)) {
+			soldier->set_location_initially(*this);
+			m_garrison->incorporateSoldier(egbase, *soldier);
+		}
 	}
-	update_soldier_request();
 }
 
 /**
  * Change the economy this site belongs to.
- * \par e  The new economy. Can be 0 (unconnected buildings have no economy).
+ * \par e The new economy. Can be 0 (unconnected buildings have no economy).
  * \note the worker (but not the soldiers) is dealt with in the
  * PlayerImmovable code.
  */
 void TrainingSite::set_economy(Economy * e)
 {
 	ProductionSite::set_economy(e);
-
-	if (m_soldier_request)
-		m_soldier_request->set_economy(e);
+	m_garrison->set_economy(e);
 }
 
 /**
@@ -237,212 +237,63 @@
  */
 void TrainingSite::cleanup(Editor_Game_Base & egbase)
 {
-	delete m_soldier_request;
-	m_soldier_request = 0;
-
+	m_garrison->cleanup(egbase);
 	ProductionSite::cleanup(egbase);
+	m_garrison->cleanup_requests(egbase);
 }
 
 
 void TrainingSite::add_worker(Worker & w)
 {
 	ProductionSite::add_worker(w);
-
-	if (upcast(Soldier, soldier, &w)) {
-		// Note that the given Soldier might already be in the array
-		// for loadgames.
-		if
-			(std::find(m_soldiers.begin(), m_soldiers.end(), soldier) ==
-			 m_soldiers.end())
-			m_soldiers.push_back(soldier);
-
-		if (upcast(Game, game, &owner().egbase()))
-			schedule_act(*game, 100);
+	if (upcast(Game, game, &owner().egbase())) {
+		schedule_act(*game, 100);
 	}
 }
 
 void TrainingSite::remove_worker(Worker & w)
 {
-	upcast(Game, game, &owner().egbase());
-
-	if (upcast(Soldier, soldier, &w)) {
-		std::vector<Soldier *>::iterator const it =
-			std::find(m_soldiers.begin(), m_soldiers.end(), soldier);
-		if (it != m_soldiers.end()) {
-			m_soldiers.erase(it);
-
-			if (game)
-				schedule_act(*game, 100);
-		}
-	}
 
 	ProductionSite::remove_worker(w);
-}
-
-
-/**
- * Request soldiers up to capacity, or let go of surplus soldiers.
- */
-void TrainingSite::update_soldier_request() {
-	if (m_soldiers.size() < m_capacity) {
-		if (!m_soldier_request) {
-			m_soldier_request =
-				new Request
-					(*this,
-					 tribe().safe_worker_index("soldier"),
-					 TrainingSite::request_soldier_callback,
-					 wwWORKER);
-
-			RequireOr r;
-
-			// set requirements to match this site
-			if (descr().get_train_attack())
-				r.add
-					(RequireAttribute
-					 	(atrAttack,
-					 	 descr().get_min_level(atrAttack),
-					 	 descr().get_max_level(atrAttack)));
-			if (descr().get_train_defense())
-				r.add
-					(RequireAttribute
-					 	(atrDefense,
-					 	 descr().get_min_level(atrDefense),
-					 	 descr().get_max_level(atrDefense)));
-			if (descr().get_train_evade())
-				r.add
-					(RequireAttribute
-					 	(atrEvade,
-					 	 descr().get_min_level(atrEvade),
-					 	 descr().get_max_level(atrEvade)));
-			if (descr().get_train_hp())
-				r.add
-					(RequireAttribute
-					 	(atrHP,
-					 	 descr().get_min_level(atrHP),
-					 	 descr().get_max_level(atrHP)));
-
-			m_soldier_request->set_requirements(r);
-		}
-
-		m_soldier_request->set_count(m_capacity - m_soldiers.size());
-	} else if (m_soldiers.size() >= m_capacity) {
-		delete m_soldier_request;
-		m_soldier_request = 0;
-
-		while (m_soldiers.size() > m_capacity)
-			dropSoldier(**m_soldiers.rbegin());
-	}
-}
-
-
-/**
- * Soldier callback. Since the soldier was already added via add_worker,
- * we only need to update the request structure.
- */
-void TrainingSite::request_soldier_callback
-	(Game            &       game,
-#ifndef NDEBUG
-	 Request         &       rq,
-#else
-	 Request         &,
-#endif
-	 Ware_Index,
-	 Worker          * const w,
-	 PlayerImmovable &       target)
-{
-	TrainingSite & tsite = ref_cast<TrainingSite, PlayerImmovable>(target);
-	Soldier      & s     = ref_cast<Soldier,      Worker>         (*w);
-
-	assert(s.get_location(game) == &tsite);
-	assert(tsite.m_soldier_request == &rq);
-
-	tsite.incorporateSoldier(game, s);
-}
-
-/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int TrainingSite::incorporateSoldier(Editor_Game_Base & egbase, Soldier & s) {
-	if (s.get_location(egbase) != this) {
-		if (stationedSoldiers().size() + 1 > descr().get_max_number_of_soldiers())
-			return -1;
-
-		s.set_location(this);
-	}
-
-	// Bind the worker into this house, hide him on the map
-	if (upcast(Game, game, &egbase))
-		s.start_task_idle(*game, 0, -1);
-
-	// Make sure the request count is reduced or the request is deleted.
-	update_soldier_request();
-
-	return 0;
-}
-
-
-std::vector<Soldier *> TrainingSite::presentSoldiers() const
-{
-	return m_soldiers;
-}
-
-std::vector<Soldier *> TrainingSite::stationedSoldiers() const
-{
-	return m_soldiers;
-}
-
-uint32_t TrainingSite::minSoldierCapacity() const throw () {
-	return 0;
-}
-uint32_t TrainingSite::maxSoldierCapacity() const throw () {
-	return descr().get_max_number_of_soldiers();
-}
-uint32_t TrainingSite::soldierCapacity() const
-{
-	return m_capacity;
-}
-
-void TrainingSite::setSoldierCapacity(uint32_t const capacity) {
-	assert(minSoldierCapacity() <= capacity);
-	assert                        (capacity <= maxSoldierCapacity());
-	assert(m_capacity != capacity);
-	m_capacity = capacity;
-	update_soldier_request();
-}
-
-/**
- * Drop a given soldier.
- *
- * 'Dropping' means releasing the soldier from the site. The soldier then
- * becomes available to the economy.
- *
- * \note This is called from player commands, so we need to verify that the
- * soldier is actually stationed here, without breaking anything if he isn't.
- */
-void TrainingSite::dropSoldier(Soldier & soldier)
-{
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-
-	std::vector<Soldier *>::iterator it =
-		std::find(m_soldiers.begin(), m_soldiers.end(), &soldier);
-	if (it == m_soldiers.end()) {
-		molog("TrainingSite::dropSoldier: soldier not in training site");
-		return;
-	}
-
-	m_soldiers.erase(it);
-
-	soldier.reset_tasks(game);
-	soldier.start_task_leavebuilding(game, true);
-
-	// Schedule, so that we can call new soldiers on next act()
-	schedule_act(game, 100);
-}
-
+	if (upcast(Game, game, &owner().egbase())) {
+		schedule_act(*game, 100);
+	}
+}
+
+void TrainingSite::update_requirements()
+{
+	RequireOr r;
+	// set requirements to match this site
+	if (descr().get_train_attack()) {
+		r.add
+			(RequireAttribute
+				(atrAttack,
+					descr().get_min_level(atrAttack),
+					descr().get_max_level(atrAttack)));
+	}
+	if (descr().get_train_defense()) {
+		r.add
+			(RequireAttribute
+				(atrDefense,
+					descr().get_min_level(atrDefense),
+					descr().get_max_level(atrDefense)));
+	}
+	if (descr().get_train_evade()) {
+		r.add
+			(RequireAttribute
+				(atrEvade,
+					descr().get_min_level(atrEvade),
+					descr().get_max_level(atrEvade)));
+	}
+	if (descr().get_train_hp()) {
+		r.add
+			(RequireAttribute
+				(atrHP,
+					descr().get_min_level(atrHP),
+					descr().get_max_level(atrHP)));
+	}
+	m_garrison->set_soldier_requirements(r);
+}
 
 /**
  * Drop all the soldiers that can not be upgraded further at this building.
@@ -451,22 +302,24 @@
 {
 	std::vector<Soldier *> droplist;
 
-	for (uint32_t i = 0; i < m_soldiers.size(); ++i) {
+	const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
+
+	for (uint32_t i = 0; i < soldiers.size(); ++i) {
 		std::vector<Upgrade>::iterator it = m_upgrades.begin();
 		for (; it != m_upgrades.end(); ++it) {
-			int32_t level = m_soldiers[i]->get_level(it->attribute);
+			int32_t level = soldiers[i]->get_level(it->attribute);
 			if (level >= it->min && level <= it->max)
 				break;
 		}
 
 		if (it == m_upgrades.end())
-			droplist.push_back(m_soldiers[i]);
+			droplist.push_back(soldiers[i]);
 	}
 
 	// Drop soldiers only now, so that changes in the soldiers array don't
 	// mess things up
 	container_iterate_const(std::vector<Soldier *>, droplist, i)
-		dropSoldier(**i.current);
+		m_garrison->dropSoldier(**i.current);
 }
 
 /**
@@ -477,10 +330,11 @@
 {
 	Soldier * soldier_to_drop = nullptr;
 	uint32_t highest_soldier_level_seen = 0;
+	const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
 
-	for (uint32_t i = 0; i < m_soldiers.size(); ++i)
+	for (uint32_t i = 0; i < soldiers.size(); ++i)
 	{
-		uint32_t this_soldier_level = m_soldiers[i]->get_level(atrTotal);
+		uint32_t this_soldier_level = soldiers[i]->get_level(atrTotal);
 
 		bool this_soldier_is_safe = false;
 		if (this_soldier_level <= highest_soldier_level_seen)
@@ -499,7 +353,7 @@
 				//  - is below maximum, and
 				//  - is not in a stalled state
 				// Check done separately for each art.
-				int32_t level = m_soldiers[i]->get_level(it->attribute);
+				int32_t level = soldiers[i]->get_level(it->attribute);
 
 				 // Below maximum -check
 				if (level > it->max)
@@ -529,7 +383,7 @@
 		if (!this_soldier_is_safe)
 		{
 			// Make this soldier a kick-out candidate
-			soldier_to_drop = m_soldiers[i];
+			soldier_to_drop = soldiers[i];
 			highest_soldier_level_seen = this_soldier_level;
 		}
 	}
@@ -538,7 +392,7 @@
 	if (nullptr != soldier_to_drop)
 		{
 			log("TrainingSite::drop_stalled_soldiers: Kicking somebody out.\n");
-			dropSoldier (*soldier_to_drop);
+			m_garrison->dropSoldier (*soldier_to_drop);
 		}
 }
 
@@ -552,7 +406,7 @@
 {
 	ProductionSite::act(game, data);
 
-	update_soldier_request();
+	m_garrison->act(game);
 }
 
 
@@ -622,7 +476,9 @@
 	int32_t minlevel = upgrade.max;
 	int32_t maxlevel = upgrade.min;
 
-	container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
+	const std::vector<Soldier*> soldiers = m_garrison->stationedSoldiers();
+	container_iterate_const(std::vector<Soldier *>, soldiers, i) {
+		assert((*i.current));
 		int32_t const level = (*i.current)->get_level(upgrade.attribute);
 
 		if (level > upgrade.max || level < upgrade.min)
@@ -787,4 +643,25 @@
 	log(" / %3d\n", max_stall_val);
 }
 
+
+void TrainingSite::garrison_occupied()
+{
+}
+void TrainingSite::garrison_lost(Game&, Player_Number, bool)
+{
+}
+void TrainingSite::reinit_after_conqueral(Game&)
+{
+}
+Garrison* TrainingSite::get_garrison() const
+{
+	return m_garrison.get();
+}
+Building* TrainingSite::get_building()
+{
+	return this;
+}
+
+
+
 }

=== modified file 'src/logic/trainingsite.h'
--- src/logic/trainingsite.h	2013-07-26 20:19:36 +0000
+++ src/logic/trainingsite.h	2013-08-06 10:09:46 +0000
@@ -20,14 +20,16 @@
 #ifndef TRAININGSITE_H
 #define TRAININGSITE_H
 
+#include "logic/garrison.h"
 #include "logic/productionsite.h"
-#include "logic/soldiercontrol.h"
 #include "logic/tattribute.h"
 
 struct TrainingSite_Window;
 
 namespace Widelands {
 
+class GarrisonHandler;
+
 struct TrainingSite_Descr : public ProductionSite_Descr {
 	TrainingSite_Descr
 		(char const * name, char const * descname,
@@ -48,7 +50,7 @@
 	int32_t get_max_level(tAttribute) const;
 	int32_t get_max_stall() const;
 private:
-	//  FIXME These variables should be per soldier type. They should be in a
+	//  FIXME These variables should bper soldier type. They should be in a
 	//  FIXME struct and there should be a vector, indexed by Soldier_Index,
 	//  FIXME with that struct structs as element type.
 
@@ -95,7 +97,7 @@
  *        surrounding strongholds, the training site will burn even if it
  *        contains soldiers!
  */
-class TrainingSite : public ProductionSite, public SoldierControl {
+class TrainingSite : public ProductionSite, public GarrisonOwner {
 	friend struct Map_Buildingdata_Data_Packet;
 	MO_DESCR(TrainingSite_Descr);
 	friend struct ::TrainingSite_Window;
@@ -138,17 +140,13 @@
 	}
 
 	virtual void set_economy(Economy * e);
+	// Garrison implementation
+	virtual Garrison* get_garrison() const;
+	virtual Building* get_building();
+	virtual void garrison_occupied();
+	virtual void garrison_lost(Game& game, Player_Number defeating, bool captured);
+	virtual void reinit_after_conqueral(Game& game);
 
-	// Begin implementation of SoldierControl
-	virtual std::vector<Soldier *> presentSoldiers() const;
-	virtual std::vector<Soldier *> stationedSoldiers() const;
-	virtual uint32_t minSoldierCapacity() const throw ();
-	virtual uint32_t maxSoldierCapacity() const throw ();
-	virtual uint32_t soldierCapacity() const;
-	virtual void setSoldierCapacity(uint32_t capacity);
-	virtual void dropSoldier(Soldier &);
-	int incorporateSoldier(Editor_Game_Base &, Soldier &);
-	// End implementation of SoldierControl
 
 	int32_t get_pri(enum tAttribute atr);
 	void set_pri(enum tAttribute atr, int32_t prio);
@@ -165,10 +163,7 @@
 	virtual void program_end(Game &, Program_Result);
 
 private:
-	void update_soldier_request();
-	static void request_soldier_callback
-		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
-
+	void update_requirements();
 	void find_and_start_next_program(Game &);
 	void start_upgrade(Game &, Upgrade &);
 	void add_upgrade(tAttribute, const std::string & prefix);
@@ -179,27 +174,12 @@
 	Upgrade * get_upgrade(tAttribute);
 
 private:
-	/// Open requests for soldiers. The soldiers can be under way or unavailable
-	Request * m_soldier_request;
-
-	/** The soldiers currently at the training site*/
-	std::vector<Soldier *> m_soldiers;
-
-	/** Number of soldiers that should be trained concurrently.
-	 * Equal or less to maximum number of soldiers supported by a training site.
-	 * There is no guarantee there really are m_capacity soldiers in the
-	 * building - some of them might still be under way or even not yet
-	 * available*/
-	uint32_t m_capacity;
-
-	/** True, \b always upgrade already experienced soldiers first, when possible
-	 * False, \b always upgrade inexperienced soldiers first, when possible */
-	bool m_build_heroes;
-
 	std::vector<Upgrade> m_upgrades;
 	Upgrade * m_current_upgrade;
+	bool m_build_heroes;
 
 	Program_Result m_result; /// The result of the last training program.
+	std::unique_ptr<GarrisonHandler> m_garrison;
 
 	// These are used for kicking out soldiers prematurely
 	static const uint32_t training_state_multiplier;
@@ -211,8 +191,6 @@
 	TrainFailCount_t training_failure_count;
 	uint32_t max_stall_val;
 	void init_kick_state(const tAttribute&, const TrainingSite_Descr&);
-
-
 };
 
 }

=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc	2013-07-28 08:40:06 +0000
+++ src/logic/warehouse.cc	2013-08-06 10:09:46 +0000
@@ -21,13 +21,15 @@
 
 #include <algorithm>
 
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
 #include "container_iterate.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
 #include "economy/portdock.h"
 #include "economy/request.h"
 #include "economy/ware_instance.h"
-#include "economy/warehousesupply.h"
 #include "economy/wares_queue.h"
 #include "log.h"
 #include "logic/battle.h"
@@ -40,6 +42,7 @@
 #include "logic/player.h"
 #include "logic/requirements.h"
 #include "logic/soldier.h"
+#include "logic/storagehandler.h"
 #include "logic/tribe.h"
 #include "logic/worker.h"
 #include "profile/profile.h"
@@ -48,192 +51,6 @@
 
 namespace Widelands {
 
-static const uint32_t WORKER_WITHOUT_COST_SPAWN_INTERVAL = 2500;
-
-WarehouseSupply::~WarehouseSupply()
-{
-	if (m_economy) {
-		log
-			("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to "
-			 "an economy",
-			 m_warehouse->serial());
-		set_economy(0);
-	}
-
-	// We're removed from the Economy. Therefore, the wares can simply
-	// be cleared out. The global inventory will be okay.
-	m_wares  .clear();
-	m_workers.clear();
-}
-
-/// Inform this supply, how much wares are to be handled
-void WarehouseSupply::set_nrwares(Ware_Index const i) {
-	assert(Ware_Index::First() == m_wares.get_nrwareids());
-
-	m_wares.set_nrwares(i);
-}
-void WarehouseSupply::set_nrworkers(Ware_Index const i) {
-	assert(Ware_Index::First() == m_workers.get_nrwareids());
-
-	m_workers.set_nrwares(i);
-}
-
-
-/// Add and remove our wares and the Supply to the economies as necessary.
-void WarehouseSupply::set_economy(Economy * const e)
-{
-	if (e == m_economy)
-		return;
-
-	if (m_economy) {
-		m_economy->remove_supply(*this);
-		for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
-			if (m_wares.stock(i))
-				m_economy->remove_wares(i, m_wares.stock(i));
-		for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
-			if (m_workers.stock(i))
-				m_economy->remove_workers(i, m_workers.stock(i));
-	}
-
-	m_economy = e;
-
-	if (m_economy) {
-		for (Ware_Index i = Ware_Index::First(); i < m_wares.get_nrwareids(); ++i)
-			if (m_wares.stock(i))
-				m_economy->add_wares(i, m_wares.stock(i));
-		for (Ware_Index i = Ware_Index::First(); i < m_workers.get_nrwareids(); ++i)
-			if (m_workers.stock(i))
-				m_economy->add_workers(i, m_workers.stock(i));
-		m_economy->add_supply(*this);
-	}
-}
-
-
-/// Add wares and update the economy.
-void WarehouseSupply::add_wares     (Ware_Index const id, uint32_t const count)
-{
-	if (!count)
-		return;
-
-	if (m_economy) // No economies in the editor
-		m_economy->add_wares(id, count);
-	m_wares.add(id, count);
-}
-
-
-/// Remove wares and update the economy.
-void WarehouseSupply::remove_wares  (Ware_Index const id, uint32_t const count)
-{
-	if (!count)
-		return;
-
-	m_wares.remove(id, count);
-	if (m_economy) // No economies in the editor
-		m_economy->remove_wares(id, count);
-}
-
-
-/// Add workers and update the economy.
-void WarehouseSupply::add_workers   (Ware_Index const id, uint32_t const count)
-{
-	if (!count)
-		return;
-
-	if (m_economy) // No economies in the editor
-		m_economy->add_workers(id, count);
-	m_workers.add(id, count);
-}
-
-
-/**
- * Remove workers and update the economy.
- * Comments see add_workers
- */
-void WarehouseSupply::remove_workers(Ware_Index const id, uint32_t const count)
-{
-	if (!count)
-		return;
-
-	m_workers.remove(id, count);
-	if (m_economy) // No economies in the editor
-		m_economy->remove_workers(id, count);
-}
-
-/// Return the position of the Supply, i.e. the owning Warehouse.
-PlayerImmovable * WarehouseSupply::get_position(Game &) {return m_warehouse;}
-
-
-/// Warehouse supplies are never active.
-bool WarehouseSupply::is_active() const throw () {return false;}
-
-bool WarehouseSupply::has_storage() const throw ()
-{
-	return true;
-}
-
-void WarehouseSupply::get_ware_type(WareWorker & /* type */, Ware_Index & /* ware */) const
-{
-	throw wexception
-		("WarehouseSupply::get_ware_type: calling this is nonsensical");
-}
-
-void WarehouseSupply::send_to_storage(Game &, Warehouse * /* wh */)
-{
-	throw wexception("WarehouseSupply::send_to_storage: should never be called");
-}
-
-uint32_t WarehouseSupply::nr_supplies
-	(const Game & game, const Request & req) const
-{
-	if (req.get_type() == wwWORKER)
-		return
-			m_warehouse->count_workers
-				(game, req.get_index(), req.get_requirements());
-
-	//  Calculate how many wares can be sent out - it might be that we need them
-	// ourselves. E.g. for hiring new soldiers.
-	int32_t const x = m_wares.stock(req.get_index());
-	// only mark an item of that type as available, if the priority of the
-	// request + number of that wares in warehouse is > priority of request
-	// of *this* warehouse + 1 (+1 is important, as else the ware would directly
-	// be taken back to the warehouse as the request of the warehouse would be
-	// highered and would have the same value as the original request)
-	int32_t const y =
-		x + (req.get_priority(0) / 100)
-		- (m_warehouse->get_priority(wwWARE, req.get_index()) / 100) - 1;
-	// But the number should never be higher than the number of wares available
-	if (y > x)
-		return x;
-	return (x > 0) ? x : 0;
-}
-
-
-/// Launch a ware as item.
-WareInstance & WarehouseSupply::launch_item(Game & game, const Request & req) {
-	if (req.get_type() != wwWARE)
-		throw wexception("WarehouseSupply::launch_item: called for non-ware request");
-	if (!m_wares.stock(req.get_index()))
-		throw wexception("WarehouseSupply::launch_item: called for non-existing ware");
-
-	return m_warehouse->launch_item(game, req.get_index());
-}
-
-/// Launch a ware as worker.
-Worker & WarehouseSupply::launch_worker(Game & game, const Request & req)
-{
-	return
-		m_warehouse->launch_worker
-			(game, req.get_index(), req.get_requirements());
-}
-
-
-/*
-==============================
-Warehouse Building
-==============================
-*/
-
-
 /// Warehouse Descr
 Warehouse_Descr::Warehouse_Descr
 	(char const * const _name, char const * const _descname,
@@ -251,6 +68,11 @@
 		m_workarea_info[m_conquers].insert(descname() + _(" conquer"));
 }
 
+Building& Warehouse_Descr::create_object() const
+{
+	return *new Warehouse(*this);
+}
+
 
 /*
 ==============================
@@ -258,37 +80,16 @@
 ==============================
 */
 
-#define SET_WORKER_WITHOUT_COST_SPAWNS(nr, value)                             \
-   for                                                                        \
-      (wl_index_range<uint32_t *>                                             \
-       i(                                                                     \
-          m_next_worker_without_cost_spawn,                                   \
-          m_next_worker_without_cost_spawn + nr                               \
-		);                                                                      \
-       i;                                                                     \
-       ++i)                                                                   \
-      *i.current = value;                                                     \
-
 Warehouse::Warehouse(const Warehouse_Descr & warehouse_descr) :
 	Building(warehouse_descr),
-	m_supply(new WarehouseSupply(this)),
-	m_next_military_act(0),
 	m_portdock(0)
 {
-	uint8_t nr_worker_types_without_cost =
-		warehouse_descr.tribe().worker_types_without_cost().size();
-	m_next_worker_without_cost_spawn =
-		new uint32_t[nr_worker_types_without_cost];
-	SET_WORKER_WITHOUT_COST_SPAWNS(nr_worker_types_without_cost, Never());
-
-	m_next_stock_remove_act = 0;
+	m_storage.reset(new StorageHandler(*this));
 }
 
 
 Warehouse::~Warehouse()
 {
-	delete m_supply;
-	delete[] m_next_worker_without_cost_spawn;
 	for (uint8_t i = 0; i < m_expedition_wares.size(); ++i) {
 		if (m_expedition_wares.at(i)) {
 			m_expedition_wares.at(i)->cleanup();
@@ -297,186 +98,46 @@
 	}
 }
 
-/**
- * Try to bring the given \ref PlannedWorkers up to date with our game data.
- * Return \c false if \p pw cannot be salvaged.
- */
-bool Warehouse::_load_finish_planned_worker(PlannedWorkers & pw)
-{
-	if (!pw.index || !(pw.index < m_supply->get_workers().get_nrwareids()))
-		return false;
-
-	const Worker_Descr * w_desc = tribe().get_worker_descr(pw.index);
-	if (!w_desc || !w_desc->is_buildable())
-		return false;
-
-	const Worker_Descr::Buildcost & cost = w_desc->buildcost();
-	uint32_t idx = 0;
-
-	for
-		(Worker_Descr::Buildcost::const_iterator cost_it = cost.begin();
-		 cost_it != cost.end(); ++cost_it, ++idx)
-	{
-		WareWorker type;
-		Ware_Index ware;
-
-		if ((ware = tribe().ware_index(cost_it->first)))
-			type = wwWARE;
-		else if ((ware = tribe().worker_index(cost_it->first)))
-			type = wwWORKER;
-		else
-			return false;
-
-		if (idx < pw.requests.size()) {
-			if
-				(pw.requests[idx]->get_type() == type &&
-				 pw.requests[idx]->get_index() == ware)
-				continue;
-
-			std::vector<Request *>::iterator req_it =
-				pw.requests.begin() + idx + 1;
-			while (req_it != pw.requests.end()) {
-				if ((*req_it)->get_type() == type && (*req_it)->get_index() == ware)
-					break;
-				++req_it;
-			}
-
-			if (req_it != pw.requests.end()) {
-				std::swap(*req_it, pw.requests[idx]);
-				continue;
-			}
-		}
-
-		log
-			("_load_finish_planned_worker: old savegame: "
-			 "need to create new request for '%s'\n",
-			 cost_it->first.c_str());
-		pw.requests.insert
-			(pw.requests.begin() + idx,
-			 new Request(*this, ware, &Warehouse::request_cb, type));
-	}
-
-	while (pw.requests.size() > idx) {
-		log
-			("_load_finish_planned_worker: old savegame: "
-			 "removing outdated request.\n");
-		delete pw.requests.back();
-		pw.requests.pop_back();
-	}
-
-	return true;
-}
-
 void Warehouse::load_finish(Editor_Game_Base & egbase) {
 	Building::load_finish(egbase);
-
-	uint32_t next_spawn = Never();
-	const std::vector<Ware_Index> & worker_types_without_cost =
-		tribe().worker_types_without_cost();
-	for (uint8_t i = worker_types_without_cost.size(); i;) {
-		Ware_Index const worker_index = worker_types_without_cost.at(--i);
-		if
-			(owner().is_worker_type_allowed(worker_index) and
-			 m_next_worker_without_cost_spawn[i] == static_cast<uint32_t>(Never()))
-		{
-			if (next_spawn == static_cast<uint32_t>(Never()))
-				next_spawn =
-					schedule_act
-						(ref_cast<Game, Editor_Game_Base>(egbase),
-						 WORKER_WITHOUT_COST_SPAWN_INTERVAL);
-			m_next_worker_without_cost_spawn[i] = next_spawn;
-			log
-				("WARNING: player %u is allowed to create worker type %s but his "
-				 "%s %u at (%i, %i) does not have a next_spawn time set for that "
-				 "worker type; setting it to %u\n",
-				 owner().player_number(),
-				 tribe().get_worker_descr(worker_index)->descname().c_str(),
-				 descname().c_str(), serial(), get_position().x, get_position().y,
-				 next_spawn);
-		}
-	}
-
-	// Ensure consistency of PlannedWorker requests
-	{
-		uint32_t pwidx = 0;
-		while (pwidx < m_planned_workers.size()) {
-			if (!_load_finish_planned_worker(m_planned_workers[pwidx])) {
-				m_planned_workers[pwidx].cleanup();
-				m_planned_workers.erase(m_planned_workers.begin() + pwidx);
-			} else {
-				pwidx++;
-			}
-		}
-	}
+	m_storage->load_finish(egbase);
 }
 
 void Warehouse::init(Editor_Game_Base & egbase)
 {
 	Building::init(egbase);
-
-	Ware_Index const nr_wares   = tribe().get_nrwares  ();
-	Ware_Index const nr_workers = tribe().get_nrworkers();
-	m_supply->set_nrwares  (nr_wares);
-	m_supply->set_nrworkers(nr_workers);
-
-	m_ware_policy.resize(nr_wares.value(), SP_Normal);
-	m_worker_policy.resize(nr_workers.value(), SP_Normal);
-
-	// Even though technically, a warehouse might be completely empty,
-	// we let warehouse see always for simplicity's sake (since there's
-	// almost always going to be a carrier inside, that shouldn't hurt).
+	m_storage->init(egbase);
+
 	Player & player = owner();
 	if (upcast(Game, game, &egbase)) {
+		// Even though technically, a warehouse might be completely empty,
+		// we let warehouse see always for simplicity's sake (since there's
+		// almost always going to be a carrier inside, that shouldn't hurt).
 		player.see_area
 			(Area<FCoords>
 			 (egbase.map().get_fcoords(get_position()), vision_range()));
 
-		{
-			uint32_t const act_time = schedule_act
-					(*game, WORKER_WITHOUT_COST_SPAWN_INTERVAL);
-			const std::vector<Ware_Index> & worker_types_without_cost =
-				tribe().worker_types_without_cost();
-
-			for
-				(wl_index_range<uint32_t> i
-				(0, worker_types_without_cost.size());
-				i; ++i)
-				if
-					(owner().is_worker_type_allowed
-						(worker_types_without_cost.at(i.current)))
-					m_next_worker_without_cost_spawn[i.current] = act_time;
-		}
-		// m_next_military_act is not touched in the loading code. Is only needed
-		// if there warehous is created in the game?  I assume it's for the
-		// conquer_radius thing
-		m_next_military_act =
-			schedule_act
-				(ref_cast<Game, Editor_Game_Base>(egbase), 1000);
-
-		m_next_stock_remove_act =
-			schedule_act
-				(ref_cast<Game, Editor_Game_Base>(egbase), 4000);
-
-	log("Message: adding (wh) (%s) %i \n", type_name(), player.player_number());
-	char message[2048];
-	snprintf
-		(message, sizeof(message),
-		 _("A new %s was added to your economy."),
-		 descname().c_str());
-	send_message
-		(ref_cast<Game, Editor_Game_Base>(egbase),
-		 "warehouse",
-		 descname(),
-		 message);
+		schedule_act(*game, 1000);
+		// Send a message
+		std::string message =
+			(boost::format(_("A new %s was added to your economy.")) % descname().c_str())
+			.str();
+		send_message
+			(ref_cast<Game, Editor_Game_Base>(egbase),
+			"warehouse", descname(), message);
 	}
 
-	if (uint32_t const conquer_radius = get_conquers())
+	// Conquer area
+	if (uint32_t const conquer_radius = get_conquers()) {
 		egbase.conquer_area
 			(Player_Area<Area<FCoords> >
 			 	(player.player_number(),
 			 	 Area<FCoords>
 			 	 	(egbase.map().get_fcoords(get_position()), conquer_radius)));
+	}
 
+	// Init port stuff
+	// FIXME: move in a port class
 	if (descr().get_isport())
 		init_portdock(egbase);
 }
@@ -507,8 +168,10 @@
 	}
 	m_portdock->init(egbase);
 
-	if (get_economy() != 0)
+	if (get_economy() != nullptr) {
 		m_portdock->set_economy(get_economy());
+		m_storage->set_economy(get_economy());
+	}
 }
 
 
@@ -538,25 +201,14 @@
 
 void Warehouse::destroy(Editor_Game_Base & egbase)
 {
-	Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
-
-	const WareList & workers = get_workers();
-
-	for (Ware_Index id = Ware_Index::First(); id < workers.get_nrwareids(); ++id) {
-		const uint32_t stock = workers.stock(id);
-
-		if (stock > 0) {
-			for (uint32_t i = 0; i < stock; ++i) {
-				launch_worker(game, id, Requirements()).start_task_leavebuilding
-					(game, true);
-			}
-		}
+	// Launch all workers in stock
+	if (upcast(Game, game, &egbase)) {
+		m_storage->launch_all_workers(*game);
 	}
 
 	Building::destroy(egbase);
 }
 
-/// Destroy the warehouse.
 void Warehouse::cleanup(Editor_Game_Base & egbase)
 {
 	if (m_portdock) {
@@ -574,32 +226,22 @@
 		}
 	}
 
-	while (!m_planned_workers.empty()) {
-		m_planned_workers.back().cleanup();
-		m_planned_workers.pop_back();
-	}
-
-	//  all cached workers are unbound and freed
-	container_iterate(IncorporatedWorkers, m_incorporated_workers, cpair) {
-		WorkerList & clist = cpair->second;
-		while (!clist.empty()) {
-			Worker * w = clist.back();
-			clist.pop_back();
-
-			if (upcast(Game, game, &egbase))
-				if (game->objects().object_still_available(w))
-					w->reset_tasks(*game);
-		}
-	}
-	m_incorporated_workers.clear();
-
+	// Launch workers with some experience
+	// This happen on dismantle for instance
+	if (upcast(Game, game, &egbase)) {
+		m_storage->launch_all_workers(*game, true);
+	}
+	m_storage->cleanup(egbase);
+
+	// Unconquer area
 	Map & map = egbase.map();
-	if (const uint32_t conquer_radius = get_conquers())
+	if (const uint32_t conquer_radius = get_conquers()) {
 		egbase.unconquer_area
 			(Player_Area<Area<FCoords> >
 			 	(owner().player_number(),
 			 	 Area<FCoords>(map.get_fcoords(get_position()), conquer_radius)),
 			 m_defeating_player);
+	}
 
 	// Unsee the area that we started seeing in init()
 	Player & player = owner();
@@ -619,109 +261,17 @@
 /// at night ;-)
 void Warehouse::act(Game & game, uint32_t const data)
 {
-	uint32_t const gametime = game.get_gametime();
-	{
-		const std::vector<Ware_Index> & worker_types_without_cost =
-			owner().tribe().worker_types_without_cost();
-		for (size_t i = worker_types_without_cost.size(); i;)
-			if (m_next_worker_without_cost_spawn[--i] <= gametime) {
-				Ware_Index const id = worker_types_without_cost.at(i);
-				if (owner().is_worker_type_allowed(id)) {
-					int32_t const stock = m_supply->stock_workers(id);
-					int32_t tdelta = WORKER_WITHOUT_COST_SPAWN_INTERVAL;
-
-					if (stock < 100) {
-						tdelta -= 4 * (100 - stock);
-						insert_workers(id, 1);
-					} else if (stock > 100) {
-						tdelta -= 4 * (stock - 100);
-						if (tdelta < 10)
-							tdelta = 10;
-						remove_workers(id, 1);
-					}
-
-					m_next_worker_without_cost_spawn[i] =
-						schedule_act(game, tdelta);
-				} else
-					m_next_worker_without_cost_spawn[i] = Never();
-			}
-	}
-
-	//  Military stuff: Kill the soldiers that are dead.
-	if (m_next_military_act <= gametime) {
-		Ware_Index const ware = tribe().safe_worker_index("soldier");
-
-		if (m_incorporated_workers.count(ware)) {
-			WorkerList & soldiers = m_incorporated_workers[ware];
-
-			uint32_t total_heal = descr().get_heal_per_second();
-			// Do not use container_iterate, as we plan to erase some
-			// of those guys
-			for
-				(WorkerList::iterator it = soldiers.begin();
-				 it != soldiers.end();
-				 ++it)
-			{
-				// This is a safe cast: we know only soldiers can land in this
-				// slot in the incorporated array
-				Soldier * soldier = static_cast<Soldier *>(*it);
-
-				//  Soldier dead ...
-				if (not soldier or soldier->get_current_hitpoints() == 0) {
-					it = soldiers.erase(it);
-					m_supply->remove_workers(ware, 1);
-					continue;
-				}
-
-				if (soldier->get_current_hitpoints() < soldier->get_max_hitpoints()) {
-					soldier->heal(total_heal);
-					continue;
-				}
-
-			}
-		}
-		m_next_military_act = schedule_act(game, 1000);
-	}
-
-	if (static_cast<int32_t>(m_next_stock_remove_act - gametime) <= 0) {
-		check_remove_stock(game);
-
-		m_next_stock_remove_act = schedule_act(game, 4000);
-	}
-
-	// Update planned workers; this is to update the request amounts and
-	// check because whether we suddenly can produce a requested worker. This
-	// is mostly previously available wares may become unavailable due to
-	// secondary requests.
-	_update_all_planned_workers(game);
-
+	uint32_t act_time = m_storage->act(game);
 	Building::act(game, data);
+	schedule_act(game, act_time);
 }
 
 
 /// Transfer our registration to the new economy.
 void Warehouse::set_economy(Economy * const e)
 {
-	Economy * const old = get_economy();
-
-	if (old == e)
-		return;
-
-	if (old)
-		old->remove_warehouse(*this);
-
-	if (m_portdock)
-		m_portdock->set_economy(e);
-	m_supply->set_economy(e);
-	Building::set_economy(e);
-
-	container_iterate_const
-		(std::vector<PlannedWorkers>, m_planned_workers, pw_it)
-	{
-		container_iterate_const
-			(std::vector<Request *>, pw_it.current->requests, req_it)
-			(*req_it.current)->set_economy(e);
-	}
+	Economy* old = get_economy();
+	m_storage->set_economy(e);
 
 	// Take care about the expeditions WaresQueues
 	for (uint8_t i = 0; i < m_expedition_wares.size(); ++i) {
@@ -730,688 +280,22 @@
 		if (e)
 			m_expedition_wares.at(i)->add_to_economy(*e);
 	}
-
-	if (e)
-		e->add_warehouse(*this);
-}
-
-
-const WareList & Warehouse::get_wares() const
-{
-	return m_supply->get_wares();
-}
-
-
-const WareList & Warehouse::get_workers() const
-{
-	return m_supply->get_workers();
-}
-
-/// Magically create wares in this warehouse. Updates the economy accordingly.
-void Warehouse::insert_wares(Ware_Index const id, uint32_t const count)
-{
-	m_supply->add_wares(id, count);
-}
-
-
-/// Magically destroy wares.
-void Warehouse::remove_wares(Ware_Index const id, uint32_t const count)
-{
-	m_supply->remove_wares(id, count);
-}
-
-
-/// Magically create workers in this warehouse. Updates the economy accordingly.
-void Warehouse::insert_workers(Ware_Index const id, uint32_t const count)
-{
-	m_supply->add_workers(id, count);
-}
-
-
-/// Magically destroy workers.
-void Warehouse::remove_workers(Ware_Index const id, uint32_t const count)
-{
-	m_supply->remove_workers(id, count);
-}
-
-
+	Building::set_economy(e);
+}
 
 /// Launch a carrier to fetch an item from our flag.
 bool Warehouse::fetch_from_flag(Game & game)
 {
 	Ware_Index const carrierid = tribe().safe_worker_index("carrier");
 
-	if (!m_supply->stock_workers(carrierid)) // XXX yep, let's cheat
-		insert_workers(carrierid, 1);
-
-	launch_worker(game, carrierid, Requirements()).start_task_fetchfromflag
-		(game);
-
-	return true;
-}
-
-
-/**
- * \return the number of workers that we can launch satisfying the given
- * requirements.
- */
-uint32_t Warehouse::count_workers
-	(const Game & /* game */, Ware_Index ware, const Requirements & req)
-{
-	uint32_t sum = 0;
-
-	do {
-		sum += m_supply->stock_workers(ware);
-
-		// NOTE: This code lies about the tAttributes of non-instantiated workers.
-		if (m_incorporated_workers.count(ware)) {
-			WorkerList & incorporated_workers = m_incorporated_workers[ware];
-
-			container_iterate_const(WorkerList, incorporated_workers, cworker)
-				if (!req.check(**cworker)) {
-					//  This is one of the workers in our sum.
-					//  But he is too stupid for this job
-					--sum;
-				}
-		}
-
-		ware = tribe().get_worker_descr(ware)->becomes();
-	} while (ware != Ware_Index::Null());
-
-	return sum;
-}
-
-
-/// Start a worker of a given type. The worker will
-/// be assigned a job by the caller.
-Worker & Warehouse::launch_worker
-	(Game & game, Ware_Index ware, const Requirements & req)
-{
-	do {
-		if (m_supply->stock_workers(ware)) {
-			uint32_t unincorporated = m_supply->stock_workers(ware);
-
-			//  look if we got one of those in stock
-			if (m_incorporated_workers.count(ware)) {
-				WorkerList & incorporated_workers = m_incorporated_workers[ware];
-
-				container_iterate (WorkerList, incorporated_workers, i) {
-					Worker * worker = *i.current;
-
-					--unincorporated;
-
-					if (req.check(*worker)) {
-						worker->reset_tasks(game);  //  forget everything you did
-						worker->set_location(this); //  back in a economy
-						incorporated_workers.erase(i.current);
-
-						m_supply->remove_workers(ware, 1);
-						return *worker;
-					}
-				}
-			}
-
-			assert(unincorporated <= m_supply->stock_workers(ware));
-
-			if (unincorporated) {
-				// Create a new one
-				// NOTE: This code lies about the tAttributes of the new worker
-				m_supply->remove_workers(ware, 1);
-				const Worker_Descr & workerdescr = *tribe().get_worker_descr(ware);
-				return workerdescr.create(game, owner(), this, m_position);
-			}
-		}
-
-		if (can_create_worker(game, ware)) {
-			// don't want to use an upgraded worker, so create new one.
-			create_worker(game, ware);
-		} else {
-			ware = tribe().get_worker_descr(ware)->becomes();
-		}
-	} while (ware != Ware_Index::Null());
-
-	throw wexception
-		("Warehouse::launch_worker: worker does not actually exist");
-}
-
-
-/**
- * This is the opposite of launch_worker: destroy the worker and add the
- * appropriate ware to our warelist
- */
-void Warehouse::incorporate_worker(Editor_Game_Base & egbase, Worker & w)
-{
-	assert(w.get_owner() == &owner());
-
-	// Do not add workers, that are in the expedition list
-	bool expedition_worker = false;
-	if (!m_expedition_workers.empty())
-		for (uint8_t i = 0; i < m_expedition_workers.size() && !expedition_worker; ++i)
-			if (m_expedition_workers.at(i)->worker && &w == m_expedition_workers.at(i)->worker)
-				expedition_worker = true;
-
-	if (!expedition_worker) {
-		if (WareInstance * const item = w.fetch_carried_item(egbase))
-			incorporate_item(egbase, *item); //  rescue an item
-
-		Ware_Index worker_index = tribe().worker_index(w.name().c_str());
-		m_supply->add_workers(worker_index, 1);
-
-		//  We remove carriers, but we keep other workers around.
-		//  FIXME Remove all workers that do not have properties such as experience.
-		//  FIXME And even such workers should be removed and only a small record
-		//  FIXME with the experience (and possibly other data that must survive)
-		//  FIXME may be kept.
-		if (dynamic_cast<Carrier const *>(&w)) {
-			w.remove(egbase);
-			return;
-		}
-
-		// Incorporate the worker
-		if (!m_incorporated_workers.count(worker_index))
-			m_incorporated_workers[worker_index] = std::vector<Worker *>();
-		m_incorporated_workers[worker_index].push_back(&w);
-	}
-	w.set_location(0); //  no longer in an economy
-
-	if (upcast(Game, game, &egbase)) {
-		//  Bind the worker into this house, hide him on the map.
-		w.reset_tasks(*game);
-		w.start_task_idle(*game, 0, -1);
-	}
-}
-
-/// Create an instance of a ware and make sure it gets
-/// carried out of the warehouse.
-WareInstance & Warehouse::launch_item(Game & game, Ware_Index const ware) {
-	// Create the item
-	WareInstance & item = *new WareInstance(ware, tribe().get_ware_descr(ware));
-	item.init(game);
-	do_launch_item(game, item);
-
-	m_supply->remove_wares(ware, 1);
-
-	return item;
-}
-
-
-/// Get a carrier to actually move this item out of the warehouse.
-void Warehouse::do_launch_item(Game & game, WareInstance & item)
-{
-	// Create a carrier
-	Ware_Index const carrierid = tribe().worker_index("carrier");
-	const Worker_Descr & workerdescr = *tribe().get_worker_descr(carrierid);
-
-	Worker & worker = workerdescr.create(game, owner(), this, m_position);
-
-	// Yup, this is cheating.
-	if (m_supply->stock_workers(carrierid))
-		m_supply->remove_workers(carrierid, 1);
-
-	// Setup the carrier
-	worker.start_task_dropoff(game, item);
-}
-
-
-/// Swallow the item, adding it to out inventory.
-void Warehouse::incorporate_item(Editor_Game_Base & egbase, WareInstance & item)
-{
-	m_supply->add_wares(item.descr_index(), 1);
-	return item.destroy(egbase);
-}
-
-
-/// Called when a transfer for one of the idle Requests completes.
-void Warehouse::request_cb
-	(Game            &       game,
-	 Request         &,
-	 Ware_Index        const ware,
-	 Worker          * const w,
-	 PlayerImmovable &       target)
-{
-	Warehouse & wh = ref_cast<Warehouse, PlayerImmovable>(target);
-
-	if (w) {
-		w->schedule_incorporate(game);
-	} else {
-		wh.m_supply->add_wares(ware, 1);
-
-		// This ware may be used to build planned workers,
-		// so it seems like a good idea to update the associated requests
-		// and use the ware before it is sent away again.
-		wh._update_all_planned_workers(game);
-	}
-}
-
-/**
- * Receive a ware from a transfer that was not associated to a \ref Request.
- */
-void Warehouse::receive_ware(Game & /* game */, Ware_Index ware)
-{
-	m_supply->add_wares(ware, 1);
-}
-
-/**
- * Receive a worker from a transfer that was not associated to a \ref Request.
- */
-void Warehouse::receive_worker(Game & game, Worker & worker)
-{
-	worker.schedule_incorporate(game);
-}
-
-Building & Warehouse_Descr::create_object() const {
-	return *new Warehouse(*this);
-}
-
-
-bool Warehouse::can_create_worker(Game &, Ware_Index const worker) const {
-	if (not (worker < m_supply->get_workers().get_nrwareids()))
-		throw wexception
-			("worker type %d does not exists (max is %d)",
-			 worker.value(), m_supply->get_workers().get_nrwareids().value());
-
-	const Worker_Descr & w_desc = *tribe().get_worker_descr(worker);
-	assert(&w_desc);
-	if (not w_desc.is_buildable())
-		return false;
-
-	//  see if we have the resources
-	const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
-	container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
-		const std::string & input_name = it.current->first;
-		if (Ware_Index id_w = tribe().ware_index(input_name)) {
-			if (m_supply->stock_wares  (id_w) < it.current->second)
-				return false;
-		} else if ((id_w = tribe().worker_index(input_name))) {
-			if (m_supply->stock_workers(id_w) < it.current->second)
-				return false;
-		} else
-			throw wexception
-				("worker type %s needs \"%s\" to be built but that is neither "
-				 "a ware type nor a worker type defined in the tribe %s",
-				 w_desc.descname().c_str(), input_name.c_str(),
-				 tribe().name().c_str());
-	}
-	return true;
-}
-
-
-void Warehouse::create_worker(Game & game, Ware_Index const worker) {
-	assert(can_create_worker (game, worker));
-
-	const Worker_Descr & w_desc = *tribe().get_worker_descr(worker);
-	const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
-	container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
-		const std::string & input = i.current->first;
-		if (Ware_Index const id_ware = tribe().ware_index(input)) {
-			remove_wares  (id_ware,                        i.current->second);
-			//update statistic accordingly
-			owner().ware_consumed(id_ware, i.current->second);
-		} else
-			remove_workers(tribe().safe_worker_index(input), i.current->second);
-	}
-
-	incorporate_worker(game, w_desc.create(game, owner(), this, m_position));
-
-	// Update PlannedWorkers::amount here if appropriate, because this function
-	// may have been called directly by the Economy.
-	// Do not update anything else about PlannedWorkers here, because this
-	// function is called by _update_planned_workers, so avoid recursion
-	container_iterate(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
-		if (pw_it.current->index == worker && pw_it.current->amount)
-			pw_it.current->amount--;
-	}
-}
-
-/**
- * Return the number of workers of the given type that we plan to
- * create in this warehouse.
- */
-uint32_t Warehouse::get_planned_workers(Game & /* game */, Ware_Index index) const
-{
-	container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
-		if (i.current->index == index)
-			return i.current->amount;
-	}
-
-	return 0;
-}
-
-/**
- * Calculate the supply of wares available to this warehouse in each of the
- * buildcost items for the given worker.
- *
- * This is the current stock plus any incoming transfers.
- */
-std::vector<uint32_t> Warehouse::calc_available_for_worker
-	(Game & /* game */, Ware_Index index) const
-{
-	const Worker_Descr & w_desc = *tribe().get_worker_descr(index);
-	const Worker_Descr::Buildcost & cost = w_desc.buildcost();
-	std::vector<uint32_t> available;
-
-	container_iterate_const(Worker_Descr::Buildcost, cost, bc) {
-		const std::string & input_name = bc.current->first;
-		if (Ware_Index id_w = tribe().ware_index(input_name)) {
-			available.push_back(get_wares().stock(id_w));
-		} else if ((id_w = tribe().worker_index(input_name))) {
-			available.push_back(get_workers().stock(id_w));
-		} else
-			throw wexception
-				("Economy::_create_requested_worker: buildcost inconsistency '%s'",
-				 input_name.c_str());
-	}
-
-	container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, i) {
-		if (i.current->index == index) {
-			assert(available.size() == i.current->requests.size());
-
-			for (uint32_t idx = 0; idx < available.size(); ++idx)
-				available[idx] += i.current->requests[idx]->get_num_transfers();
-		}
-	}
-
-	return available;
-}
-
-
-/**
- * Set the amount of workers we plan to create
- * of the given \p index to \p amount.
- */
-void Warehouse::plan_workers(Game & game, Ware_Index index, uint32_t amount)
-{
-	PlannedWorkers * pw = 0;
-
-	container_iterate(std::vector<PlannedWorkers>, m_planned_workers, i) {
-		if (i.current->index == index) {
-			pw = &*i.current;
-			break;
-		}
-	}
-
-	if (!pw) {
-		if (!amount)
-			return;
-
-		m_planned_workers.push_back(PlannedWorkers());
-		pw = &m_planned_workers.back();
-		pw->index = index;
-		pw->amount = 0;
-
-		const Worker_Descr & w_desc = *tribe().get_worker_descr(pw->index);
-		const Worker_Descr::Buildcost & cost = w_desc.buildcost();
-		container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
-			const std::string & input_name = cost_it.current->first;
-
-			if (Ware_Index id_w = tribe().ware_index(input_name)) {
-				pw->requests.push_back
-					(new Request
-					 (*this, id_w, &Warehouse::request_cb, wwWARE));
-			} else if ((id_w = tribe().worker_index(input_name))) {
-				pw->requests.push_back
-					(new Request
-					 (*this, id_w, &Warehouse::request_cb, wwWORKER));
-			} else
-				throw wexception
-					("plan_workers: bad buildcost '%s'", input_name.c_str());
-		}
-	}
-
-	pw->amount = amount;
-	_update_planned_workers(game, *pw);
-}
-
-/**
- * See if we can create the workers of the given plan,
- * and update requests accordingly.
- */
-void Warehouse::_update_planned_workers
-	(Game & game, Warehouse::PlannedWorkers & pw)
-{
-	const Worker_Descr & w_desc = *tribe().get_worker_descr(pw.index);
-	const Worker_Descr::Buildcost & cost = w_desc.buildcost();
-
-	while (pw.amount && can_create_worker(game, pw.index))
-		create_worker(game, pw.index);
-
-	uint32_t idx = 0;
-	container_iterate_const(Worker_Descr::Buildcost, cost, cost_it) {
-		const std::string & input_name = cost_it.current->first;
-		uint32_t supply;
-
-		if (Ware_Index id_w = tribe().ware_index(input_name)) {
-			supply = m_supply->stock_wares(id_w);
-		} else if ((id_w = tribe().worker_index(input_name))) {
-			supply = m_supply->stock_workers(id_w);
-		} else
-			throw wexception
-				("_update_planned_workers: bad buildcost '%s'", input_name.c_str());
-
-		if (supply >= pw.amount * cost_it.current->second)
-			pw.requests[idx]->set_count(0);
-		else
-			pw.requests[idx]->set_count
-				(pw.amount * cost_it.current->second - supply);
-		++idx;
-	}
-
-	while (pw.requests.size() > idx) {
-		delete pw.requests.back();
-		pw.requests.pop_back();
-	}
-}
-
-/**
- * Check all planned worker creations.
- *
- * Needs to be called periodically, because some necessary supplies might arrive
- * due to idle transfers instead of by explicit request.
- */
-void Warehouse::_update_all_planned_workers(Game & game)
-{
-	uint32_t idx = 0;
-	while (idx < m_planned_workers.size()) {
-		_update_planned_workers(game, m_planned_workers[idx]);
-
-		if (!m_planned_workers[idx].amount) {
-			m_planned_workers[idx].cleanup();
-			m_planned_workers.erase(m_planned_workers.begin() + idx);
-		} else {
-			idx++;
-		}
-	}
-}
-
-void Warehouse::enable_spawn
-	(Game & game, uint8_t const worker_types_without_cost_index)
-{
-	assert
-		(m_next_worker_without_cost_spawn[worker_types_without_cost_index]
-		 ==
-		 static_cast<uint32_t>(Never()));
-	m_next_worker_without_cost_spawn[worker_types_without_cost_index] =
-		schedule_act(game, WORKER_WITHOUT_COST_SPAWN_INTERVAL);
-}
-void Warehouse::disable_spawn(uint8_t const worker_types_without_cost_index)
-{
-	assert
-		(m_next_worker_without_cost_spawn[worker_types_without_cost_index]
-		 !=
-		 static_cast<uint32_t>(Never()));
-	m_next_worker_without_cost_spawn[worker_types_without_cost_index] = Never();
-}
-
-
-bool Warehouse::canAttack()
-{
-	return get_conquers() > 0;
-}
-
-void Warehouse::aggressor(Soldier & enemy)
-{
-	if (!get_conquers())
-		return;
-
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-	Map  & map  = game.map();
-	if
-		(enemy.get_owner() == &owner() ||
-		 enemy.getBattle() ||
-		 get_conquers()
-		 <=
-		 map.calc_distance(enemy.get_position(), get_position()))
-		return;
-
-	if
-		(game.map().find_bobs
-		 	(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2),
-		 	 0,
-		 	 FindBobEnemySoldier(&owner())))
-		return;
-
-	Ware_Index const soldier_index = tribe().worker_index("soldier");
-	Requirements noreq;
-
-	if (!count_workers(game, soldier_index, noreq))
-		return;
-
-	Soldier & defender =
-		ref_cast<Soldier, Worker>(launch_worker(game, soldier_index, noreq));
-	defender.start_task_defense(game, false, owner().get_retreat_percentage());
-}
-
-bool Warehouse::attack(Soldier & enemy)
-{
-	Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
-	Ware_Index const soldier_index = tribe().worker_index("soldier");
-	Requirements noreq;
-
-	if (count_workers(game, soldier_index, noreq)) {
-		Soldier & defender =
-			ref_cast<Soldier, Worker>(launch_worker(game, soldier_index, noreq));
-		defender.start_task_defense(game, true, 0);
-		enemy.send_signal(game, "sleep");
-		return true;
-	}
-
-	set_defeating_player(enemy.owner().player_number());
-	schedule_destroy(game);
-	return false;
-}
-
-void Warehouse::PlannedWorkers::cleanup()
-{
-	while (!requests.empty()) {
-		delete requests.back();
-		requests.pop_back();
-	}
-}
-
-Warehouse::StockPolicy Warehouse::get_ware_policy(Ware_Index ware) const
-{
-	assert(ware.value() < m_ware_policy.size());
-	return m_ware_policy[ware.value()];
-}
-
-Warehouse::StockPolicy Warehouse::get_worker_policy(Ware_Index ware) const
-{
-	assert(ware.value() < m_worker_policy.size());
-	return m_worker_policy[ware.value()];
-}
-
-Warehouse::StockPolicy Warehouse::get_stock_policy
-	(WareWorker waretype, Ware_Index wareindex) const
-{
-	if (waretype == wwWORKER)
-		return get_worker_policy(wareindex);
-	else
-		return get_ware_policy(wareindex);
-}
-
-
-void Warehouse::set_ware_policy(Ware_Index ware, Warehouse::StockPolicy policy)
-{
-	assert(ware.value() < m_ware_policy.size());
-	m_ware_policy[ware.value()] = policy;
-}
-
-void Warehouse::set_worker_policy
-	(Ware_Index ware, Warehouse::StockPolicy policy)
-{
-	assert(ware.value() < m_worker_policy.size());
-	m_worker_policy[ware.value()] = policy;
-}
-
-/**
- * Check if there are remaining wares with stock policy \ref SP_Remove,
- * and remove one of them if appropriate.
- */
-void Warehouse::check_remove_stock(Game & game)
-{
-	if (base_flag().current_items() < base_flag().total_capacity() / 2) {
-		for (Ware_Index ware = Ware_Index::First(); ware.value() < m_ware_policy.size(); ++ware) {
-			if (get_ware_policy(ware) != SP_Remove || !get_wares().stock(ware))
-				continue;
-
-			launch_item(game, ware);
-			break;
-		}
-	}
-
-	for (Ware_Index widx = Ware_Index::First(); widx.value() < m_worker_policy.size(); ++widx) {
-		if (get_worker_policy(widx) != SP_Remove || !get_workers().stock(widx))
-			continue;
-
-		Worker & worker = launch_worker(game, widx, Requirements());
-		worker.start_task_leavebuilding(game, true);
-		break;
-	}
-}
-
-/*
- * SoldierControl implementations
- */
-std::vector<Soldier *> Warehouse::presentSoldiers() const
-{
-	std::vector<Soldier *> rv;
-
-	Ware_Index const ware = tribe().safe_worker_index("soldier");
-	IncorporatedWorkers::const_iterator sidx = m_incorporated_workers.find(ware);
-
-	if (sidx != m_incorporated_workers.end()) {
-		const WorkerList & soldiers = sidx->second;
-
-		container_iterate_const(WorkerList, soldiers, i)
-			rv.push_back(static_cast<Soldier *>(*i));
-	}
-
-	return rv;
-}
-int Warehouse::incorporateSoldier(Editor_Game_Base & egbase, Soldier & soldier) {
-	incorporate_worker(egbase, soldier);
-	return 0;
-}
-
-int Warehouse::outcorporateSoldier(Editor_Game_Base & /* egbase */, Soldier & soldier) {
-
-	Ware_Index const ware = tribe().safe_worker_index("soldier");
-	if (m_incorporated_workers.count(ware)) {
-		WorkerList & soldiers = m_incorporated_workers[ware];
-
-		WorkerList::iterator i = std::find
-			(soldiers.begin(), soldiers.end(), &soldier);
-
-		soldiers.erase(i);
-		m_supply->remove_workers(ware, 1);
-	}
-#ifndef NDEBUG
-	else
-		throw wexception("outcorporateSoldier: soldier not in this warehouse!");
-#endif
-
-	return 0;
-}
+	if (!m_storage->count_workers(game, carrierid)) {
+		m_storage->insert_workers(carrierid, 1);
+	}
+	Worker& w = m_storage->launch_worker(game, carrierid);
+	w.start_task_fetchfromflag(game);
+	return true;
+}
+
 
 void Warehouse::log_general_info(const Editor_Game_Base & egbase)
 {
@@ -1421,5 +305,24 @@
 		molog("Port dock: %u\n", m_portdock ? m_portdock->serial() : 0);
 }
 
+void Warehouse::receive_ware(Game&, Ware_Index ware)
+{
+	m_storage->insert_wares(ware, 1);
+}
+
+void Warehouse::receive_worker(Game& game, Worker& worker)
+{
+	m_storage->incorporate_worker(game, worker);
+}
+
+Building* Warehouse::get_building()
+{
+	return this;
+}
+
+Storage* Warehouse::get_storage() const
+{
+	return m_storage.get();
+}
 
 }

=== modified file 'src/logic/warehouse.h'
--- src/logic/warehouse.h	2013-07-28 08:40:06 +0000
+++ src/logic/warehouse.h	2013-08-06 10:09:46 +0000
@@ -20,10 +20,9 @@
 #ifndef WAREHOUSE_H
 #define WAREHOUSE_H
 
-#include "logic/attackable.h"
 #include "logic/building.h"
 #include "economy/request.h"
-#include "logic/soldiercontrol.h"
+#include "logic/storage.h"
 #include "logic/wareworker.h"
 
 struct Interactive_Player;
@@ -31,6 +30,7 @@
 
 namespace Widelands {
 
+class StorageHandler;
 struct Editor_Game_Base;
 struct PortDock;
 struct Request;
@@ -44,7 +44,6 @@
 /*
 Warehouse
 */
-struct WarehouseSupply;
 
 struct Warehouse_Descr : public Building_Descr {
 	Warehouse_Descr
@@ -65,47 +64,12 @@
 };
 
 
-class Warehouse : public Building, public Attackable, public SoldierControl {
+class Warehouse : public Building, public StorageOwner {
 	friend struct PortDock;
 	friend struct Map_Buildingdata_Data_Packet;
 
 	MO_DESCR(Warehouse_Descr);
-
 public:
-	/**
-	 * Each ware and worker type has an associated per-warehouse
-	 * stock policy that defines whether it will be stocked by this
-	 * warehouse.
-	 *
-	 * \note The values of this enum are written directly into savegames,
-	 * so be careful when changing them.
-	 */
-	enum StockPolicy {
-		/**
-		 * The default policy allows stocking wares without any special priority.
-		 */
-		SP_Normal = 0,
-
-		/**
-		 * As long as there are warehouses with this policy for a ware, all
-		 * available unstocked supplies will be transferred to warehouses
-		 * with this policy.
-		 */
-		SP_Prefer = 1,
-
-		/**
-		 * If a ware has this stock policy, no new items of this ware will enter
-		 * the warehouse.
-		 */
-		SP_DontStock = 2,
-
-		/**
-		 * Like \ref SP_DontStock, but in addition, existing stock of this ware
-		 * will be transported out of the warehouse over time.
-		 */
-		SP_Remove = 3,
-	};
-
 	Warehouse(const Warehouse_Descr &);
 	virtual ~Warehouse();
 
@@ -137,67 +101,14 @@
 
 	virtual void set_economy(Economy *);
 
-	const WareList & get_wares() const;
-	const WareList & get_workers() const;
-
-	void insert_wares  (Ware_Index, uint32_t count);
-	void remove_wares  (Ware_Index, uint32_t count);
-	void insert_workers(Ware_Index, uint32_t count);
-	void remove_workers(Ware_Index, uint32_t count);
-
-	/* SoldierControl implementation */
-	std::vector<Soldier *> presentSoldiers() const;
-	std::vector<Soldier *> stationedSoldiers() const {
-		return presentSoldiers();
-	}
-	uint32_t minSoldierCapacity() const {return 0;}
-	uint32_t maxSoldierCapacity() const {return 4294967295U;}
-	uint32_t soldierCapacity() const {return maxSoldierCapacity();}
-	void setSoldierCapacity(uint32_t /* capacity */) {
-		throw wexception("Not implemented for a Warehouse!");
-	}
-	void dropSoldier(Soldier &) {
-		throw wexception("Not implemented for a Warehouse!");
-	}
-	int incorporateSoldier(Editor_Game_Base &, Soldier &);
-	int outcorporateSoldier(Editor_Game_Base &, Soldier &);
-
 	virtual bool fetch_from_flag(Game &);
 
-	uint32_t count_workers(const Game &, Ware_Index, const Requirements &);
-	Worker & launch_worker(Game &, Ware_Index, const Requirements &);
-	void incorporate_worker(Editor_Game_Base &, Worker &);
-
-	WareInstance & launch_item(Game &, Ware_Index);
-	void do_launch_item(Game &, WareInstance &);
-	void incorporate_item(Editor_Game_Base &, WareInstance &);
-
-	bool can_create_worker(Game &, Ware_Index) const;
-	void     create_worker(Game &, Ware_Index);
-
-	uint32_t get_planned_workers(Game &, Ware_Index index) const;
-	void plan_workers(Game &, Ware_Index index, uint32_t amount);
-	std::vector<uint32_t> calc_available_for_worker
-		(Game &, Ware_Index index) const;
-
-	void enable_spawn(Game &, uint8_t worker_types_without_cost_index);
-	void disable_spawn(uint8_t worker_types_without_cost_index);
-
-	// Begin Attackable implementation
-	virtual Player & owner() const {return Building::owner();}
-	virtual bool canAttack();
-	virtual void aggressor(Soldier &);
-	virtual bool attack   (Soldier &);
-	// End Attackable implementation
-
 	virtual void receive_ware(Game &, Ware_Index ware);
 	virtual void receive_worker(Game &, Worker & worker);
 
-	StockPolicy get_ware_policy(Ware_Index ware) const;
-	StockPolicy get_worker_policy(Ware_Index ware) const;
-	StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const;
-	void set_ware_policy(Ware_Index ware, StockPolicy policy);
-	void set_worker_policy(Ware_Index ware, StockPolicy policy);
+	// StorageOwner
+	virtual Building* get_building();
+	virtual Storage* get_storage() const;
 
 	// PortDock stuff
 	struct Expedition_Worker {
@@ -231,47 +142,7 @@
 private:
 	void init_portdock(Editor_Game_Base & egbase);
 
-	/**
-	 * Plan to produce a certain worker type in this warehouse. This means
-	 * requesting all the necessary wares, if multiple different wares types are
-	 * needed.
-	 */
-	struct PlannedWorkers {
-		/// Index of the worker type we plan to create
-		Ware_Index index;
-
-		/// How many workers of this type are we supposed to create?
-		uint32_t amount;
-
-		/// Requests to obtain the required build costs
-		std::vector<Request *> requests;
-
-		void cleanup();
-	};
-
-	static void request_cb
-		(Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
-	void check_remove_stock(Game &);
-
-	bool _load_finish_planned_worker(PlannedWorkers & pw);
-	void _update_planned_workers(Game &, PlannedWorkers & pw);
-	void _update_all_planned_workers(Game &);
-
-	WarehouseSupply       * m_supply;
-
-	std::vector<StockPolicy> m_ware_policy;
-	std::vector<StockPolicy> m_worker_policy;
-
-	// Workers who live here at the moment
-	typedef std::vector<Worker *> WorkerList;
-	typedef std::map<Ware_Index, WorkerList> IncorporatedWorkers;
-	IncorporatedWorkers        m_incorporated_workers;
-	uint32_t                 * m_next_worker_without_cost_spawn;
-	uint32_t                   m_next_military_act;
-	uint32_t m_next_stock_remove_act;
-
-	std::vector<PlannedWorkers> m_planned_workers;
-
+	std::unique_ptr<StorageHandler> m_storage;
 	// PortDock stuff
 	PortDock * m_portdock;
 	std::vector<WaresQueue *> m_expedition_wares;

=== modified file 'src/logic/worker.cc'
--- src/logic/worker.cc	2013-08-01 08:33:15 +0000
+++ src/logic/worker.cc	2013-08-06 10:09:46 +0000
@@ -1089,7 +1089,7 @@
 
 /**
  * Change the location. This should be called in the following situations:
- * \li worker creation (usually, location is a warehouse)
+ * \li worker creation (usually, location is a storage)
  * \li worker moves along a route (location is a road and finally building)
  * \li current location is destroyed (building burnt down etc...)
  */
@@ -1200,7 +1200,7 @@
 
 	// We are destroyed, but we were maybe idling
 	// or doing something else. Get Location might
-	// init a gowarehouse task or something and this results
+	// init a gostorage task or something and this results
 	// in a dirty stack. Nono, we do not want to end like this
 	if (upcast(Game, game, &egbase))
 		reset_tasks(*game);
@@ -1251,7 +1251,7 @@
 
 /**
  * Schedule an immediate CMD_INCORPORATE, which will integrate this worker into
- * the warehouse he is standing on.
+ * the storage he is standing on.
  */
 void Worker::schedule_incorporate(Game & game)
 {
@@ -1261,13 +1261,13 @@
 
 
 /**
- * Incorporate the worker into the warehouse it's standing on immediately.
+ * Incorporate the worker into the storage it's standing on immediately.
  * This will delete the worker.
  */
 void Worker::incorporate(Game & game)
 {
-	if (upcast(Warehouse, wh, get_location(game))) {
-		wh->incorporate_worker(game, *this);
+	if (upcast(StorageOwner, storage_owner, get_location(game))) {
+		storage_owner->get_storage()->incorporate_worker(game, *this);
 		return;
 	}
 
@@ -1353,7 +1353,7 @@
 void Worker::init_auto_task(Game & game) {
 	if (PlayerImmovable * location = get_location(game)) {
 		if
-			(get_economy()->warehouses().size() ||
+			(get_economy()->storages().size() ||
 			 location->get_type() == BUILDING)
 			return start_task_gowarehouse(game);
 
@@ -2008,7 +2008,7 @@
 		}
 	}
 
-	if (dynamic_cast<Warehouse const *>(location)) {
+	if (dynamic_cast<StorageOwner const *>(location)) {
 		delete m_supply;
 		m_supply = 0;
 
@@ -2032,7 +2032,7 @@
 	if (location->get_type() == BUILDING)
 		return start_task_leavebuilding(game, true);
 
-	if (!get_economy()->warehouses().size()) {
+	if (!get_economy()->storages().size()) {
 		molog("[gowarehouse]: No warehouse left in Economy\n");
 		return pop_task(game);
 	}
@@ -2158,7 +2158,7 @@
 		throw wexception
 			("MO(%u): [dropoff]: not on building on return", serial());
 
-	if (dynamic_cast<Warehouse const *>(location)) {
+	if (dynamic_cast<StorageOwner const *>(location)) {
 		schedule_incorporate(game);
 		return;
 	}
@@ -2285,7 +2285,7 @@
 	}
 
 	// We're back!
-	if (dynamic_cast<Warehouse const *>(location)) {
+	if (dynamic_cast<StorageOwner const *>(location)) {
 		schedule_incorporate(game);
 		return;
 	}
@@ -2511,12 +2511,12 @@
 		game.get_gametime() + 120000 + 200 * (game.logic_rand() % 600);
 }
 
-struct FindFlagWithPlayersWarehouse {
-	FindFlagWithPlayersWarehouse(const Player & owner) : m_owner(owner) {}
+struct FindFlagWithPlayersStorage {
+	FindFlagWithPlayersStorage(const Player & owner) : m_owner(owner) {}
 	bool accept(const BaseImmovable & imm) const {
 		if (upcast(Flag const, flag, &imm))
 			if (&flag->owner() == &m_owner)
-				if (flag->economy().warehouses().size())
+				if (flag->economy().storages().size())
 					return true;
 		return false;
 	}
@@ -2537,7 +2537,7 @@
 	if (location && &location->owner() == &owner()) {
 		molog("[fugitive]: we are on location\n");
 
-		if (dynamic_cast<Warehouse const *>(location))
+		if (dynamic_cast<StorageOwner const *>(location))
 			return schedule_incorporate(game);
 
 		set_location(0);
@@ -2546,7 +2546,7 @@
 
 	// check whether we're on a flag and it's time to return home
 	if (upcast(Flag, flag, map[get_position()].get_immovable())) {
-		if (&flag->owner() == &owner() and flag->economy().warehouses().size()) {
+		if (&flag->owner() == &owner() and flag->economy().storages().size()) {
 			set_location(flag);
 			return pop_task(game);
 		}
@@ -2562,12 +2562,12 @@
 	if
 		(map.find_immovables
 		 	(Area<FCoords>(map.get_fcoords(get_position()), maxdist),
-		 	 &flags, FindFlagWithPlayersWarehouse(*get_owner())))
+		 	 &flags, FindFlagWithPlayersStorage(*get_owner())))
 	{
 		int32_t bestdist = -1;
 		Flag *  best     =  0;
 
-		molog("[fugitive]: found a flag connected to warehouse(s)\n");
+		molog("[fugitive]: found a flag connected to storage(s)\n");
 
 		container_iterate_const(std::vector<ImmovableFound>, flags, i) {
 			Flag & flag = ref_cast<Flag, BaseImmovable>(*i.current->object);
@@ -2593,7 +2593,7 @@
 		if (best) {
 			molog("[fugitive]: try to move to flag\n");
 
-			// Warehouse could be on a different island, so check for failure
+			// Storage could be on a different island, so check for failure
 			// Also, move only a few number of steps in the right direction,
 			// so that we could theoretically lose the flag again, but also
 			// perhaps find a closer flag.

=== modified file 'src/logic/worker.h'
--- src/logic/worker.h	2013-07-26 20:19:36 +0000
+++ src/logic/worker.h	2013-08-06 10:09:46 +0000
@@ -145,6 +145,9 @@
 	/// request a new worker of his old type. Otherwise Ware_Index::Null is
 	/// returned.
 	Ware_Index gain_experience   (Game &);
+	void set_experience(int32_t exp) {
+		m_current_exp = exp;
+	}
 
 	void create_needed_experience(Game &);
 	Ware_Index level             (Game &);

=== modified file 'src/map_io/widelands_map_buildingdata_data_packet.cc'
--- src/map_io/widelands_map_buildingdata_data_packet.cc	2013-08-01 03:23:11 +0000
+++ src/map_io/widelands_map_buildingdata_data_packet.cc	2013-08-06 10:09:46 +0000
@@ -26,7 +26,6 @@
 #include "economy/flag.h"
 #include "economy/portdock.h"
 #include "economy/request.h"
-#include "economy/warehousesupply.h"
 #include "economy/wares_queue.h"
 #include "logic/constructionsite.h"
 #include "logic/dismantlesite.h"
@@ -44,25 +43,32 @@
 #include "logic/widelands_fileread.h"
 #include "logic/widelands_filewrite.h"
 #include "logic/worker.h"
+#include <logic/storagehandler.h>
 #include "map_io/widelands_map_map_object_loader.h"
 #include "map_io/widelands_map_map_object_saver.h"
 #include "upcast.h"
+#include <scripting/pdep/llimits.h>
 
 namespace Widelands {
 
 // Versions
-// Since V3: m_old_buildings vector
+// V3 (b18): m_old_buildings vector
 #define CURRENT_PACKET_VERSION 3
 
 // Subversions
 #define CURRENT_DISMANTLESITE_PACKET_VERSION    1
-// Since V3: m_prev_building not written
+// CSITE: V3 (b18) m_prev_building not written
 #define CURRENT_CONSTRUCTIONSITE_PACKET_VERSION 3
 #define CURRENT_PARTIALLYFB_PACKET_VERSION      1
-#define CURRENT_WAREHOUSE_PACKET_VERSION        6
+// WAREHOUSE: V7 (b18) splitted storage
+#define CURRENT_WAREHOUSE_PACKET_VERSION        7
+// MILITARYSITE: V4 (b18) splitted garrison
 #define CURRENT_MILITARYSITE_PACKET_VERSION     4
 #define CURRENT_PRODUCTIONSITE_PACKET_VERSION   5
+// TRAININGSITE: V4 (b18) splitted garrison/upgrade request
 #define CURRENT_TRAININGSITE_PACKET_VERSION     4
+#define CURRENT_GARRISON_PACKET_VERSION         1
+#define CURRENT_STORAGE_PACKET_VERSION          1
 
 
 void Map_Buildingdata_Data_Packet::Read
@@ -478,54 +484,60 @@
 {
 	try {
 		uint16_t const packet_version = fr.Unsigned16();
-		if
-			(1 <= packet_version and
-			 packet_version <= CURRENT_WAREHOUSE_PACKET_VERSION)
-		{
+		if (packet_version < 1 || packet_version > CURRENT_WAREHOUSE_PACKET_VERSION) {
+			throw game_data_error
+				(_("unknown/unhandled version %u"), packet_version);
+		}
+		if (packet_version >= 7) {
+			read_storage(*warehouse.get_storage(), fr, game, mol);
+		} else {
+			// init supply
+			upcast(StorageHandler, sh, warehouse.get_storage());
+			StorageSupply* ss = sh->m_supply.get();
 			Ware_Index const nr_wares   = warehouse.tribe().get_nrwares  ();
 			Ware_Index const nr_tribe_workers = warehouse.tribe().get_nrworkers();
-			warehouse.m_supply->set_nrwares  (nr_wares);
-			warehouse.m_supply->set_nrworkers(nr_tribe_workers);
-			warehouse.m_ware_policy.resize(nr_wares.value(), Warehouse::SP_Normal);
-			warehouse.m_worker_policy.resize
-				(nr_tribe_workers.value(), Warehouse::SP_Normal);
-			//log("Reading warehouse stuff for %p\n", &warehouse);
-			//  supply
+			ss->set_nrwares  (nr_wares);
+			ss->set_nrworkers(nr_tribe_workers);
+			sh->m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+			sh->m_worker_policy.resize
+				(nr_tribe_workers.value(),Storage::StockPolicy::Normal);
+			// ware supplies
 			const Tribe_Descr & tribe = warehouse.tribe();
 			while (fr.Unsigned8()) {
-				Ware_Index const id = tribe.ware_index(fr.CString());
+				const char* ware_name = fr.CString();
+				Ware_Index const id = tribe.ware_index(ware_name);
+				Storage::StockPolicy policy = Storage::StockPolicy::Normal;
+				uint32_t amount = 0;
 				if (packet_version >= 5) {
-					uint32_t amount = fr.Unsigned32();
-					Warehouse::StockPolicy policy =
-						static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
-
-					if (id) {
-						warehouse.insert_wares(id, amount);
-						warehouse.set_ware_policy(id, policy);
-					}
-				} else {
-					uint16_t amount = fr.Unsigned16();
-
-					if (id)
-						warehouse.insert_wares(id, amount);
+					amount = fr.Unsigned32();
+					policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+				} else {
+					amount = static_cast<uint32_t>(fr.Unsigned16());
+				}
+				if (id) {
+					ss->add_wares(id, amount);
+					sh->set_ware_policy(id, policy);
+				} else {
+					throw  game_data_error(_("warehouse: Unknown ware %s (id %d)\n"), ware_name, id.value());
 				}
 			}
+			// worker supplies
 			while (fr.Unsigned8()) {
-				Ware_Index const id = tribe.worker_index(fr.CString());
+				const char* name = fr.CString();
+				Ware_Index const id = tribe.worker_index(name);
+				Storage::StockPolicy policy = Storage::StockPolicy::Normal;
+				uint32_t amount = 0;
 				if (packet_version >= 5) {
-					uint32_t amount = fr.Unsigned32();
-					Warehouse::StockPolicy policy =
-						static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
-
-					if (id) {
-						warehouse.insert_workers(id, amount);
-						warehouse.set_worker_policy(id, policy);
-					}
-				} else {
-					uint16_t amount = fr.Unsigned16();
-
-					if (id)
-						warehouse.insert_workers(id, amount);
+					amount = fr.Unsigned32();
+					policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+				} else {
+					amount = static_cast<uint32_t>(fr.Unsigned16());
+				}
+				if (id) {
+					ss->add_workers(id, amount);
+					sh->set_worker_policy(id, policy);
+				} else {
+					throw  game_data_error(_("storage: Unknown worker %s (id %d)\n"), name, id.value());
 				}
 			}
 
@@ -535,145 +547,104 @@
 				while (nrrequests--) {
 					std::unique_ptr<Request> req
 						(new Request
-						 	(warehouse,
-						 	 Ware_Index::First(),
-						 	 &Warehouse::request_cb,
-						 	 wwWORKER));
+							(warehouse,
+								Ware_Index::First(),
+								&StorageHandler::planned_worker_callback,
+								wwWORKER));
 					req->Read(fr, game, mol);
 				}
 			}
 
-			assert(warehouse.m_incorporated_workers.empty());
-			{
-				uint16_t const nr_workers = fr.Unsigned16();
-				for (uint16_t i = 0; i < nr_workers; ++i) {
-					uint32_t const worker_serial = fr.Unsigned32();
-
-					try {
-						Worker & worker = mol.get<Worker>(worker_serial);
-						if (1 == packet_version) {
-							char const * const name = fr.CString();
-							if (name != worker.name())
-								throw game_data_error
-									(_("expected %s but found \"%s\""),
-									 worker.name().c_str(), name);
+			// Incorporated workers
+			uint16_t const nr_workers = fr.Unsigned16();
+			for (uint16_t i = 0; i < nr_workers; ++i) {
+				uint32_t const worker_serial = fr.Unsigned32();
+				try {
+					Worker & worker = mol.get<Worker>(worker_serial);
+					if (1 == packet_version) {
+						char const * const name = fr.CString();
+						if (name != worker.name()) {
+							throw game_data_error
+								(_("incorporated worker name : expected %s but found \"%s\""),
+									worker.name().c_str(), name);
 						}
-						Ware_Index worker_index = tribe.worker_index(worker.name().c_str());
-						if (!warehouse.m_incorporated_workers.count(worker_index))
-							warehouse.m_incorporated_workers[worker_index] = std::vector<Worker *>();
-						warehouse.m_incorporated_workers[worker_index].push_back(&worker);
-					} catch (const _wexception & e) {
-						throw game_data_error
-							("incorporated worker #%u (%u): %s",
-							 i, worker_serial, e.what());
-					}
+					}
+					StorageHandler::StockedWorkerAtr* atr = sh->store_worker_atr(worker);
+					if (atr != nullptr) {
+						sh->m_stocked_workers_atr.push_back(*atr);
+					}
+					mol.schedule_destroy(worker);
+				} catch (const _wexception & e) {
+					throw game_data_error
+						("incorporated worker #%u (%u): %s",
+							i, worker_serial, e.what());
 				}
 			}
-
+			// Auto spawning
 			const std::vector<Ware_Index> & worker_types_without_cost =
 				tribe.worker_types_without_cost();
 
 			if (1 == packet_version) { //  a single next_spawn time for "carrier"
 				uint32_t const next_spawn = fr.Unsigned32();
-				Ware_Index const worker_index =
-					tribe.safe_worker_index("carrier");
+				Ware_Index const worker_index = tribe.safe_worker_index("carrier");
 				if (not worker_index) {
 					log
 						("WARNING: %s %u has a next_spawn time for nonexistent "
-						 "worker type \"%s\" set to %u, ignoring\n",
-						 warehouse.descname().c_str(), warehouse.serial(),
-						 "carrier", next_spawn);
-				} else if
-					(tribe.get_worker_descr(worker_index)->buildcost().size())
-				{
+							"worker type \"%s\" set to %u, ignoring\n",
+							warehouse.descname().c_str(), warehouse.serial(),
+							"carrier", next_spawn);
+				} else if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
 					log
 						("WARNING: %s %u has a next_spawn time for worker type "
-						 "\"%s\", that costs something to build, set to %u, "
-						 "ignoring\n",
-						 warehouse.descname().c_str(), warehouse.serial(),
-						 "carrier", next_spawn);
-				} else
-					for (uint8_t i = 0;; ++i) {
-						assert(i < worker_types_without_cost.size());
-						if (worker_types_without_cost.at(i) == worker_index) {
-							if
-								(warehouse.m_next_worker_without_cost_spawn[i]
-								 !=
-								 static_cast<uint32_t>(Never()))
-							{
-								warehouse.molog
-									("read_warehouse: "
-									 "m_next_worker_without_cost_spawn[%u] = %u\n",
-									 i, warehouse.m_next_worker_without_cost_spawn[i]);
-							}
-							assert
-								(warehouse.m_next_worker_without_cost_spawn[i]
-								 ==
-								 static_cast<uint32_t>(Never()));
-							warehouse.m_next_worker_without_cost_spawn[i] =
-								next_spawn;
-							break;
-						}
-					}
-			} else
+							"\"%s\", that costs something to build, set to %u, "
+							"ignoring\n",
+							warehouse.descname().c_str(), warehouse.serial(),
+							"carrier", next_spawn);
+				} else {
+					sh->add_worker_spawn(worker_index);
+					uint32_t* next_act = &sh->m_spawn_wares.at(worker_index).at(0);
+					*next_act = next_spawn;
+				}
+			} else {
 				for (;;) {
 					char const * const worker_typename = fr.CString   ();
-					if (not *worker_typename) //  encountered the terminator ("")
+					if (not *worker_typename) { //  encountered the terminator ("")
 						break;
-					uint32_t     const next_spawn      = fr.Unsigned32();
-					Ware_Index   const worker_index    =
-						tribe.safe_worker_index(worker_typename);
+					}
+					uint32_t const next_spawn = fr.Unsigned32();
+					Ware_Index const worker_index = tribe.safe_worker_index(worker_typename);
 					if (not worker_index) {
 						log
 							("WARNING: %s %u has a next_spawn time for nonexistent "
-							 "worker type \"%s\" set to %u, ignoring\n",
-							 warehouse.descname().c_str(), warehouse.serial(),
-							 worker_typename, next_spawn);
+								"worker type \"%s\" set to %u, ignoring\n",
+								warehouse.descname().c_str(), warehouse.serial(),
+								worker_typename, next_spawn);
 						continue;
 					}
 					if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
 						log
 							("WARNING: %s %u has a next_spawn time for worker type "
-							 "\"%s\", that costs something to build, set to %u, "
-							 "ignoring\n",
-							 warehouse.descname().c_str(), warehouse.serial(),
-							 worker_typename, next_spawn);
+								"\"%s\", that costs something to build, set to %u, "
+								"ignoring\n",
+								warehouse.descname().c_str(), warehouse.serial(),
+								worker_typename, next_spawn);
 						continue;
 					}
-					for (uint8_t i = 0;; ++i) {
-						assert(i < worker_types_without_cost.size());
-						if (worker_types_without_cost.at(i) == worker_index) {
-							if
-								(warehouse.m_next_worker_without_cost_spawn[i]
-								 !=
-								 static_cast<uint32_t>(Never()))
-								throw game_data_error
-									(_
-									 	("%s %u has a next_spawn time for worker type "
-									 	 "\"%s\" set to %u, but it was previously set "
-									 	 "to %u\n"),
-									 warehouse.descname().c_str(), warehouse.serial(),
-									 worker_typename, next_spawn,
-									 warehouse.m_next_worker_without_cost_spawn[i]);
-							warehouse.m_next_worker_without_cost_spawn[i] =
-								next_spawn;
-							break;
-						}
-					}
+					sh->add_worker_spawn(worker_index);
+					uint32_t* next_act = &sh->m_spawn_workers.at(worker_index).at(0);
+					*next_act = next_spawn;
 				}
-				//  The checks that the warehouse has a next_spawn time for each
-				//  worker type that the player is allowed to spawn, is in
-				//  Warehouse::load_finish.
+			}
+			//  The checks that the warehouse has a next_spawn time for each
+			//  worker type that the player is allowed to spawn, is in
+			//  Warehouse::load_finish.
 
 			if (packet_version >= 3) {
 				// Read planned worker data
 				// Consistency checks are in Warehouse::load_finish
 				uint32_t nr_planned_workers = fr.Unsigned32();
 				while (nr_planned_workers--) {
-					warehouse.m_planned_workers.push_back
-						(Warehouse::PlannedWorkers());
-					Warehouse::PlannedWorkers & pw =
-						warehouse.m_planned_workers.back();
+					StorageHandler::PlannedWorkers pw;
 					pw.index = tribe.worker_index(fr.CString());
 					pw.amount = fr.Unsigned32();
 
@@ -681,87 +652,82 @@
 					while (nr_requests--) {
 						pw.requests.push_back
 							(new Request
-							 	(warehouse,
-							 	 Ware_Index::First(),
-							 	 &Warehouse::request_cb,
-							 	 wwWORKER));
+								(warehouse,
+									Ware_Index::First(),
+									&StorageHandler::planned_worker_callback,
+									wwWORKER));
 						pw.requests.back()->Read(fr, game, mol);
 					}
+					sh->m_planned_workers.push_back(pw);
 				}
 			}
 
-			if (packet_version >= 5)
-				warehouse.m_next_stock_remove_act = fr.Unsigned32();
-
-			if (packet_version >= 6) {
-				if (warehouse.descr().get_isport()) {
-					if (Serial portdock = fr.Unsigned32()) {
-						warehouse.m_portdock = &mol.get<PortDock>(portdock);
-						warehouse.m_portdock->set_economy(warehouse.get_economy());
-
-						// Expedition specific stuff
-						if (warehouse.m_portdock->expedition_started()) {
-							// Expedition workers
-							uint8_t num_of_workers = fr.Unsigned8();
-							for (uint8_t i = 0; i < num_of_workers; ++i) {
-								warehouse.get_expedition_workers().push_back(new Warehouse::Expedition_Worker);
-								if (fr.Unsigned8() == 1) {
-									warehouse.get_expedition_workers().back()->worker_request =
-										new Request
-											(warehouse,
-											Ware_Index::First(),
-											Warehouse::request_expedition_worker_callback,
-											wwWORKER);
-									warehouse.get_expedition_workers().back()->worker_request->Read(fr, game, mol);
-								} else {
-									warehouse.get_expedition_workers().back()->worker =
-										&mol.get<Worker>(fr.Unsigned32());
-								}
+			if (packet_version >= 5) {
+				sh->m_removal_next_act = fr.Unsigned32();
+			}
+		}
+		// Port stuff
+		if (packet_version >= 6) {
+			if (warehouse.descr().get_isport()) {
+				if (Serial portdock = fr.Unsigned32()) {
+					warehouse.m_portdock = &mol.get<PortDock>(portdock);
+					warehouse.m_portdock->set_economy(warehouse.get_economy());
+
+					// Expedition specific stuff
+					if (warehouse.m_portdock->expedition_started()) {
+						// Expedition workers
+						uint8_t num_of_workers = fr.Unsigned8();
+						for (uint8_t i = 0; i < num_of_workers; ++i) {
+							warehouse.get_expedition_workers().push_back(new Warehouse::Expedition_Worker);
+							if (fr.Unsigned8() == 1) {
+								warehouse.get_expedition_workers().back()->worker_request =
+									new Request
+										(warehouse,
+										Ware_Index::First(),
+										Warehouse::request_expedition_worker_callback,
+										wwWORKER);
+								warehouse.get_expedition_workers().back()->worker_request->Read(fr, game, mol);
+							} else {
+								warehouse.get_expedition_workers().back()->worker =
+									&mol.get<Worker>(fr.Unsigned32());
 							}
-
-							// Expedition WaresQueues
-							uint8_t nr_queues = fr.Unsigned8();
-							assert(warehouse.get_wares_queue_vector().empty());
-							for (uint8_t i = 0; i < nr_queues; ++i) {
-								WaresQueue * wq = new WaresQueue(warehouse, Ware_Index::Null(), 0);
-								wq->Read(fr, game, mol);
-								wq->set_callback(PortDock::expedition_wares_queue_callback, warehouse.m_portdock);
-
-								if (!wq->get_ware()) {
-									delete wq;
-								} else {
-									warehouse.get_wares_queue_vector().push_back(wq);
-								}
+						}
+
+						// Expedition WaresQueues
+						uint8_t nr_queues = fr.Unsigned8();
+						assert(warehouse.get_wares_queue_vector().empty());
+						for (uint8_t i = 0; i < nr_queues; ++i) {
+							WaresQueue * wq = new WaresQueue(warehouse, Ware_Index::Null(), 0);
+							wq->Read(fr, game, mol);
+							wq->set_callback(PortDock::expedition_wares_queue_callback, warehouse.m_portdock);
+
+							if (!wq->get_ware()) {
+								delete wq;
+							} else {
+								warehouse.get_wares_queue_vector().push_back(wq);
 							}
 						}
 					}
 				}
 			}
-
-			if (uint32_t const conquer_radius = warehouse.get_conquers()) {
-				//  Add to map of military influence.
-				const Map & map = game.map();
-				Area<FCoords> a
-					(map.get_fcoords(warehouse.get_position()), conquer_radius);
-				const Field & first_map_field = map[0];
-				Player::Field * const player_fields =
-					warehouse.owner().m_fields;
-				MapRegion<Area<FCoords> > mr(map, a);
-				do
-					player_fields[mr.location().field - &first_map_field]
-					.military_influence
-						+= map.calc_influence(mr.location(), Area<>(a, a.radius));
-				while (mr.advance(map));
-			}
-			warehouse.owner().see_area
-				(Area<FCoords>
-				 (game.map().get_fcoords(warehouse.get_position()),
-				  warehouse.vision_range()));
-			warehouse.m_next_military_act = game.get_gametime();
-			//log("Read warehouse stuff for %p\n", &warehouse);
-		} else
-			throw game_data_error
-				(_("unknown/unhandled version %u"), packet_version);
+		}
+		// TODO move in warehouse loadfinished?
+		if (uint32_t const conquer_radius = warehouse.get_conquers()) {
+			//  Add to map of military influence.
+			const Map & map = game.map();
+			Area<FCoords> a (map.get_fcoords(warehouse.get_position()), conquer_radius);
+			const Field & first_map_field = map[0];
+			Player::Field * const player_fields = warehouse.owner().m_fields;
+			MapRegion<Area<FCoords> > mr(map, a);
+			do {
+				player_fields[mr.location().field - &first_map_field].military_influence
+					+= map.calc_influence(mr.location(), Area<>(a, a.radius));
+			} while (mr.advance(map));
+		}
+		warehouse.owner().see_area
+			(Area<FCoords>
+				(game.map().get_fcoords(warehouse.get_position()),
+				warehouse.vision_range()));
 	} catch (const _wexception & e) {
 		throw game_data_error(_("warehouse: %s"), e.what());
 	}
@@ -777,114 +743,61 @@
 	try {
 		uint16_t const packet_version = fr.Unsigned16();
 		bool rel17comp = false;
-		if (3 == packet_version and 4 == CURRENT_MILITARYSITE_PACKET_VERSION)
+		if (3 == packet_version and 4 == CURRENT_MILITARYSITE_PACKET_VERSION) {
 			rel17comp = true;
-		if (packet_version == CURRENT_MILITARYSITE_PACKET_VERSION or rel17comp)
-		{
+		}
+		if (CURRENT_MILITARYSITE_PACKET_VERSION == 4 || rel17comp) {
 			read_productionsite(militarysite, fr, game, mol);
-
-			militarysite.m_normal_soldier_request.reset();
-
-			if (fr.Unsigned8()) {
-				militarysite.m_normal_soldier_request.reset
-					(new Request
-						(militarysite,
-						 Ware_Index::First(),
-						 MilitarySite::request_soldier_callback,
-						 wwWORKER));
-				militarysite.m_normal_soldier_request->Read(fr, game, mol);
-			}
-			else
-				militarysite.m_normal_soldier_request.reset();
-
-			if (rel17comp) // compatibility with release 17 savegames
-				militarysite.m_upgrade_soldier_request.reset();
-			else
-			if (fr.Unsigned8())
-			{
-				militarysite.m_upgrade_soldier_request.reset
-					(new Request
-						(militarysite,
-						 (!militarysite.m_normal_soldier_request) ? Ware_Index::First()
-						: militarysite.descr().tribe().safe_worker_index("soldier"),
-						MilitarySite::request_soldier_callback,
-						wwWORKER));
-				militarysite.m_upgrade_soldier_request->Read(fr, game, mol);
-			}
-			else
-				militarysite.m_upgrade_soldier_request.reset();
-
-
-			if ((militarysite.m_didconquer = fr.Unsigned8())) {
-				//  Add to map of military influence.
-				const Map & map = game.map();
-				Area<FCoords> a
-					(map.get_fcoords(militarysite.get_position()),
-					 militarysite.get_conquers());
-				const Field & first_map_field = map[0];
-				Player::Field * const player_fields =
-					militarysite.owner().m_fields;
-				MapRegion<Area<FCoords> > mr(map, a);
-				do
-					player_fields[mr.location().field - &first_map_field]
-					.military_influence
-						+= map.calc_influence(mr.location(), Area<>(a, a.radius));
-				while (mr.advance(map));
-			}
-
-			//  capacity (modified by user)
-			militarysite.m_capacity = fr.Unsigned8();
-			militarysite.m_nexthealtime = fr.Signed32();
-			if (not (rel17comp)) // compatibility with release 17 savegames
-			{
-
-				uint16_t reqmin = fr.Unsigned16();
-				uint16_t reqmax = fr.Unsigned16();
-				militarysite.m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
-				militarysite.m_soldier_preference = static_cast<MilitarySite::SoldierPreference>(fr.Unsigned8());
-				militarysite.m_next_swap_soldiers_time = fr.Signed32();
-				militarysite.m_soldier_upgrade_try = 0 != fr.Unsigned8() ? true : false;
-				militarysite.m_doing_upgrade_request = 0 != fr.Unsigned8() ? true : false;
-			}
-			else // Release 17 compatibility branch. Some safe values.
-			{
-				militarysite.m_soldier_preference = MilitarySite::kPrefersRookies;
-				if (2 < militarysite.m_capacity)
-					militarysite.m_soldier_preference = MilitarySite::kPrefersHeroes;
-				militarysite.m_next_swap_soldiers_time = militarysite.m_nexthealtime;
-				militarysite.m_soldier_upgrade_try = false;
-				militarysite.m_doing_upgrade_request = false;
-			}
-
-		} else
+			upcast(GarrisonHandler, gh, militarysite.get_garrison());
+
+			if (packet_version == CURRENT_MILITARYSITE_PACKET_VERSION) {
+				read_garrison(*gh, fr, game, mol);
+			} else if (rel17comp) {
+				gh->m_normal_soldier_request.reset();
+				if (fr.Unsigned8()) {
+					gh->m_normal_soldier_request.reset
+						(new Request
+							(militarysite,
+								Ware_Index::First(),
+								GarrisonHandler::request_soldier_callback,
+								wwWORKER));
+					gh->m_normal_soldier_request->Read(fr, game, mol);
+				}
+
+				gh->m_upgrade_soldier_request.reset();
+
+				if ((gh->m_didconquer = fr.Unsigned8())) {
+					//  Add to map of military influence.
+					const Map & map = game.map();
+					Area<FCoords> a
+						(map.get_fcoords(militarysite.get_position()),
+							militarysite.get_conquers());
+					const Field & first_map_field = map[0];
+					Player::Field * const player_fields =
+						militarysite.owner().m_fields;
+					MapRegion<Area<FCoords> > mr(map, a);
+					do
+						player_fields[mr.location().field - &first_map_field]
+						.military_influence
+							+= map.calc_influence(mr.location(), Area<>(a, a.radius));
+					while (mr.advance(map));
+				}
+
+				//  capacity (modified by user)
+				gh->m_capacity = fr.Unsigned8();
+				gh->m_last_heal_time = fr.Signed32() - 1000;
+				// Release 17 compatibility branch. Some safe values.
+				gh->m_soldier_preference = Garrison::SoldierPref::Rookies;
+				if (2 < gh->m_capacity) {
+					gh->m_soldier_preference = Garrison::SoldierPref::Heroes;
+				}
+				gh->m_last_swap_soldiers_time = gh->m_last_heal_time;
+				gh->m_try_soldier_upgrade = false;
+				gh->m_doing_upgrade_request = false;
+			}
+		} else {
 			throw game_data_error
 				(_("unknown/unhandled version %u"), packet_version);
-
-		//  If the site's capacity is outside the allowed range (can happen if
-		//  the site's type's definition has changed), set the variable to the
-		//  nearest valid value.
-		//
-		//  This does not drop excessive soldiers, since they are not loaded into
-		//  the site yet. To do that we would have to do this change by adding a
-		//  Cmd_ChangeSoldierCapacity to the beginning of the game's command
-		//  queue. But that would not work because the command queue is not read
-		//  yet and will be cleared before it is read.
-		if        (militarysite.m_capacity < militarysite.minSoldierCapacity()) {
-			log
-				("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
-				 "set to %u but it must be at least %u. Changing to that value.\n",
-				 militarysite.serial(), militarysite.owner().player_number(),
-				 militarysite.get_position().x, militarysite.get_position().y,
-				 militarysite.m_capacity, militarysite.minSoldierCapacity());
-			militarysite.m_capacity = militarysite.minSoldierCapacity();
-		} else if (militarysite.maxSoldierCapacity() < militarysite.m_capacity) {
-			log
-				("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
-				 "set to %u but it can be at most %u. Changing to that value.\n",
-				 militarysite.serial(), militarysite.owner().player_number(),
-				 militarysite.get_position().x, militarysite.get_position().y,
-				 militarysite.m_capacity, militarysite.maxSoldierCapacity());
-			militarysite.m_capacity = militarysite.maxSoldierCapacity();
 		}
 	} catch (const _wexception & e) {
 		throw game_data_error(_("militarysite: %s"), e.what());
@@ -1176,28 +1089,30 @@
 		uint16_t const trainingsite_packet_version = fr.Unsigned16();
 
 		bool rel17comp = false; // compatibility with release 17
-		if (4 == CURRENT_TRAININGSITE_PACKET_VERSION && 3 == trainingsite_packet_version)
+		if (4 == CURRENT_TRAININGSITE_PACKET_VERSION && 3 == trainingsite_packet_version) {
 			rel17comp = true;
+		}
+		upcast(GarrisonHandler, gh, trainingsite.get_garrison());
 
-		if (trainingsite_packet_version == CURRENT_TRAININGSITE_PACKET_VERSION or rel17comp)
-		{
+		if (trainingsite_packet_version == CURRENT_TRAININGSITE_PACKET_VERSION || rel17comp) {
 			read_productionsite(trainingsite, fr, game, mol);
-
-			delete trainingsite.m_soldier_request;
-			trainingsite.m_soldier_request = 0;
-			if (fr.Unsigned8()) {
-				trainingsite.m_soldier_request =
-					new Request
-						(trainingsite,
-						 Ware_Index::First(),
-						 TrainingSite::request_soldier_callback,
-						 wwWORKER);
-				trainingsite.m_soldier_request->Read(fr, game, mol);
+			if (!rel17comp) {
+				read_garrison(*gh, fr, game, mol);
+			} else {
+				gh->m_normal_soldier_request.reset();
+				if (fr.Unsigned8()) {
+					Request* r = new Request
+							(trainingsite,
+							Ware_Index::First(),
+							GarrisonHandler::request_soldier_callback,
+							wwWORKER);
+					gh->m_normal_soldier_request.reset(r);
+					gh->m_normal_soldier_request->Read(fr, game, mol);
+				}
+				gh->m_capacity = fr.Unsigned8();
 			}
-
-			trainingsite.m_capacity = fr.Unsigned8();
 			trainingsite.m_build_heroes = fr.Unsigned8();
-
+			// UPgrades
 			uint8_t const nr_upgrades = fr.Unsigned8();
 			for (uint8_t i = 0; i < nr_upgrades; ++i) {
 				tAttribute attribute = static_cast<tAttribute>(fr.Unsigned8());
@@ -1216,9 +1131,8 @@
 					fr.Signed32();
 				}
 			}
-			// load premature kick-out state, was not in release 17..
-			if (not rel17comp)
-			{
+			if (!rel17comp) {
+				// load premature kick-out state, was not in release 17..
 				uint16_t mapsize = fr.Unsigned16();
 				while (mapsize)
 				{
@@ -1231,41 +1145,216 @@
 					trainingsite.training_failure_count[std::make_pair(traintype, trainlevel)] = t;
 				}
 			}
-		} else
+
+			if (rel17comp) {
+				// Check capacities
+				if        (gh->m_capacity < gh->minSoldierCapacity()) {
+					log
+						("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
+						"set to %u but it must be at least %u. Changing to that value.\n",
+						trainingsite.serial(), trainingsite.owner().player_number(),
+						trainingsite.get_position().x, trainingsite.get_position().y,
+						gh->m_capacity, gh->minSoldierCapacity());
+					gh->m_capacity = gh->minSoldierCapacity();
+				} else if (gh->maxSoldierCapacity() < gh->m_capacity) {
+					log
+						("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
+						"set to %u but it can be at most %u. Changing to that value.\n",
+						trainingsite.serial(), trainingsite.owner().player_number(),
+						trainingsite.get_position().x, trainingsite.get_position().y,
+						gh->m_capacity, gh->maxSoldierCapacity());
+					gh->m_capacity = gh->maxSoldierCapacity();
+				}
+			}
+		} else {
 			throw game_data_error
 				(_("unknown/unhandled version %u"), trainingsite_packet_version);
-
-		//  If the site's capacity is outside the allowed range (can happen if
-		//  the site's type's definition has changed), set the variable to the
-		//  nearest valid value.
-		//
-		//  This does not drop excessive soldiers, since they are not loaded into
-		//  the site yet. To do that we would have to do this change by adding a
-		//  Cmd_ChangeSoldierCapacity to the beginning of the game's command
-		//  queue. But that would not work because the command queue is not read
-		//  yet and will be cleared before it is read.
-		if        (trainingsite.m_capacity < trainingsite.minSoldierCapacity()) {
-			log
-				("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
-				 "set to %u but it must be at least %u. Changing to that value.\n",
-				 trainingsite.serial(), trainingsite.owner().player_number(),
-				 trainingsite.get_position().x, trainingsite.get_position().y,
-				 trainingsite.m_capacity, trainingsite.minSoldierCapacity());
-			trainingsite.m_capacity = trainingsite.minSoldierCapacity();
-		} else if (trainingsite.maxSoldierCapacity() < trainingsite.m_capacity) {
-			log
-				("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
-				 "set to %u but it can be at most %u. Changing to that value.\n",
-				 trainingsite.serial(), trainingsite.owner().player_number(),
-				 trainingsite.get_position().x, trainingsite.get_position().y,
-				 trainingsite.m_capacity, trainingsite.maxSoldierCapacity());
-			trainingsite.m_capacity = trainingsite.maxSoldierCapacity();
 		}
 	} catch (const _wexception & e) {
 		throw game_data_error(_("trainingsite: %s"), e.what());
 	}
 }
 
+void Map_Buildingdata_Data_Packet::read_garrison(Garrison& g, FileRead& fr, Game& game, Map_Map_Object_Loader& mor)
+{
+	try {
+		GarrisonHandler& gh = ref_cast<GarrisonHandler, Garrison>(g);
+		uint16_t paquet_version = fr.Unsigned16();
+		gh.m_min_capacity = fr.Unsigned32();
+		gh.m_max_capacity = fr.Unsigned32();
+		gh.m_capacity = fr.Unsigned32();
+		// FIXME CGH ensuire soldiers are added later
+		gh.m_passive = fr.Unsigned8() > 0;
+		gh.m_heal_per_second = fr.Unsigned32();
+		gh.m_last_heal_time = fr.Unsigned32();
+		gh.m_soldier_requirements.Read(fr, game, mor);
+		gh.m_soldier_upgrade_requirements = RequireAttribute
+			(atrTotal, fr.Unsigned32(), fr.Unsigned32());
+		if (fr.Unsigned8()) {
+			gh.m_normal_soldier_request.reset(new Request
+				(gh.m_building, Ware_Index::First(),
+					GarrisonHandler::request_soldier_callback,
+					wwWORKER));
+			gh.m_normal_soldier_request->Read(fr, game, mor);
+		}
+		if (fr.Unsigned8()) {
+			gh.m_upgrade_soldier_request.reset(new Request
+				(gh.m_building,
+					(!gh.m_normal_soldier_request) ? Ware_Index::First()
+						: gh.m_building.descr().tribe().safe_worker_index("soldier"),
+					GarrisonHandler::request_soldier_callback,
+					wwWORKER, GarrisonHandler::request_soldier_transfer_callback));
+			gh.m_upgrade_soldier_request->Read(fr, game, mor);
+		}
+		gh.m_conquer_radius = fr.Unsigned32();
+		gh.m_didconquer = fr.Unsigned8() > 0;
+		gh.m_soldier_preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
+		gh.m_last_swap_soldiers_time = fr.Unsigned32();
+		gh.m_try_soldier_upgrade = fr.Unsigned8() > 0;
+		gh.m_doing_upgrade_request = fr.Unsigned8() > 0;
+
+		// Ensure capacity range
+		//  If the site's capacity is outside the allowed range (can happen if
+		//  the site's type's definition has changed), set the variable to the
+		//  nearest valid value.
+		//
+		//  This does not drop excessive soldiers, since they are not loaded into
+		//  the site yet. To do that we would have to do this change by adding a
+		//  Cmd_ChangeSoldierCapacity to the beginning of the game's command
+		//  queue. But that would not work because the command queue is not read
+		//  yet and will be cleared before it is read.
+		if (gh.m_capacity < gh.m_min_capacity) {
+			log
+				("WARNING: garrison %u of player %u at (%i, %i) has capacity "
+					"set to %u but it must be at least %u. Changing to that value.\n",
+					gh.m_building.serial(), gh.owner().player_number(),
+					gh.m_building.get_position().x, gh.m_building.get_position().y,
+					gh.m_capacity, gh.minSoldierCapacity());
+			gh.m_capacity = gh.minSoldierCapacity();
+		} else if (gh.maxSoldierCapacity() < gh.m_capacity) {
+			log
+				("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
+					"set to %u but it can be at most %u. Changing to that value.\n",
+					gh.m_building.serial(), gh.owner().player_number(),
+					gh.m_building.get_position().x, gh.m_building.get_position().y,
+					gh.m_capacity, gh.maxSoldierCapacity());
+			gh.m_capacity = gh.maxSoldierCapacity();
+		}
+		// Update map of military influence
+		if (gh.m_didconquer) {
+			const Map & map = game.map();
+			Area<FCoords> a
+				(map.get_fcoords(gh.m_building.get_position()), gh.m_conquer_radius);
+			const Field & first_map_field = map[0];
+			Player::Field * const player_fields = gh.owner().m_fields;
+			MapRegion<Area<FCoords> > mr(map, a);
+			do
+				player_fields[mr.location().field - &first_map_field]
+				.military_influence
+					+= map.calc_influence(mr.location(), Area<>(a, a.radius));
+			while (mr.advance(map));
+		}
+	} catch (const _wexception e) {
+		throw game_data_error(_("garrison: %s"), e.what());
+	}
+}
+
+void Map_Buildingdata_Data_Packet::read_storage
+	(Storage& storage, FileRead& fr, Game& game, Map_Map_Object_Loader& mol)
+{
+	try {
+		StorageHandler & sh = ref_cast<StorageHandler, Storage>(storage);
+		uint16_t packet_version = fr.Unsigned16();
+		if (packet_version != CURRENT_STORAGE_PACKET_VERSION) {
+			throw game_data_error(_("storage: Unkhandled packet version %d"), packet_version);
+		}
+		// basics
+		sh.m_removal_next_act = fr.Unsigned32();
+		// ware supplies
+		StorageSupply* ss = sh.m_supply.get();
+		const Tribe_Descr& tribe = sh.owner().tribe();
+		Ware_Index const nr_wares = tribe.get_nrwares();
+		ss->set_nrwares(nr_wares);
+		sh.m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
+		while (fr.Unsigned8()) {
+			const char* ware_name = fr.CString();
+			Ware_Index const id = tribe.ware_index(ware_name);
+			uint32_t amount = fr.Unsigned32();
+			Storage::StockPolicy policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+			if (id) {
+				ss->add_wares(id, amount);
+				sh.set_ware_policy(id, policy);
+			} else {
+				throw  game_data_error(_("storage: Unknown ware %s (id %d)\n"), ware_name, id.value());
+			}
+			if (fr.Unsigned8()) {
+				std::vector<uint32_t> spawn_values =
+					{fr.Unsigned32(), fr.Unsigned32(), fr.Unsigned32()};
+					if (fr.Unsigned8()) {
+						spawn_values.push_back(fr.Unsigned32());
+					}
+				sh.m_spawn_wares.insert(std::make_pair(id, spawn_values));
+			}
+		}
+		// worker supplies
+		Ware_Index const nr_workers = tribe.get_nrworkers();
+		ss->set_nrworkers(nr_workers);
+		sh.m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
+		while (fr.Unsigned8()) {
+			const char* worker_name = fr.CString();
+			Ware_Index const id = tribe.ware_index(worker_name);
+			uint32_t amount = fr.Unsigned32();
+			Storage::StockPolicy policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
+			if (id) {
+				ss->add_workers(id, amount);
+				sh.set_worker_policy(id, policy);
+			} else {
+				throw  game_data_error(_("storage: Unknown worker %s (id %d)\n"), worker_name, id.value());
+			}
+			if (fr.Unsigned8()) {
+				std::vector<uint32_t> spawn_values =
+					{fr.Unsigned32(), fr.Unsigned32(), fr.Unsigned32()};
+				if (fr.Unsigned8()) {
+					spawn_values.push_back(fr.Unsigned32());
+				}
+				sh.m_spawn_workers.insert(std::make_pair(id, spawn_values));
+			}
+		}
+		// planned workers
+		uint32_t planned_amount = fr.Unsigned32();
+		while (planned_amount--) {
+			StorageHandler::PlannedWorkers pw;
+			pw.index = tribe.worker_index(fr.CString());
+			pw.amount = fr.Unsigned32();
+			uint32_t nr_requests = fr.Unsigned32();
+			while (nr_requests--) {
+				Request* r = new Request
+					(sh.get_building(),
+						Ware_Index::First(),
+						&StorageHandler::planned_worker_callback,
+						wwWORKER);
+				r->Read(fr, game, mol);
+				pw.requests.push_back(r);
+			}
+			sh.m_planned_workers.push_back(pw);
+		}
+		// stocked attributes
+		uint32_t stocked_amount = fr.Unsigned32();
+		while (stocked_amount--) {
+			StorageHandler::StockedWorkerAtr stocked_atr;
+			stocked_atr.index = tribe.worker_index(fr.CString());;
+			stocked_atr.descr = tribe.get_worker_descr(stocked_atr.index);
+			stocked_atr.atck_lvl = fr.Unsigned32();
+			stocked_atr.evade_lvl = fr.Unsigned32();
+			stocked_atr.defense_lvl = fr.Unsigned32();
+			stocked_atr.exp_or_hp_lvl = fr.Unsigned32();
+			sh.m_stocked_workers_atr.push_back(stocked_atr);
+		}
+	} catch (const _wexception e) {
+		throw game_data_error(_("storage: %s"), e.what());
+	}
+}
+
 
 void Map_Buildingdata_Data_Packet::Write
 	(FileSystem & fs, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
@@ -1453,82 +1542,9 @@
 {
 	fw.Unsigned16(CURRENT_WAREHOUSE_PACKET_VERSION);
 
-	//  supply
-	const Tribe_Descr & tribe = warehouse.tribe();
-	const WareList & wares = warehouse.m_supply->get_wares();
-	for (Ware_Index i = Ware_Index::First(); i < wares.get_nrwareids  (); ++i) {
-		fw.Unsigned8(1);
-		fw.String(tribe.get_ware_descr(i)->name());
-		fw.Unsigned32(wares.stock(i));
-		fw.Unsigned8(warehouse.get_ware_policy(i));
-	}
-	fw.Unsigned8(0);
-	const WareList & workers = warehouse.m_supply->get_workers();
-	for (Ware_Index i = Ware_Index::First(); i < workers.get_nrwareids(); ++i) {
-		fw.Unsigned8(1);
-		fw.String(tribe.get_worker_descr(i)->name());
-		fw.Unsigned32(workers.stock(i));
-		fw.Unsigned8(warehouse.get_worker_policy(i));
-	}
-	fw.Unsigned8(0);
-
-	//  Incorporated workers, write sorted after file-serial.
-	uint32_t nworkers = 0;
-	container_iterate_const(Warehouse::IncorporatedWorkers, warehouse.m_incorporated_workers, cwt)
-		nworkers += cwt->second.size();
-
-	fw.Unsigned16(nworkers);
-	typedef std::map<uint32_t, const Worker *> TWorkerMap;
-	TWorkerMap workermap;
-	container_iterate_const(Warehouse::IncorporatedWorkers, warehouse.m_incorporated_workers, cwt) {
-		container_iterate_const(Warehouse::WorkerList, cwt->second, i) {
-			const Worker & w = *(*i);
-			assert(mos.is_object_known(w));
-			workermap.insert
-				(std::pair<uint32_t, const Worker *>
-				 (mos.get_object_file_index(w), &w));
-		}
-	}
-
-	container_iterate_const(TWorkerMap, workermap, i)
-	{
-		const Worker & obj = *i.current->second;
-		assert(mos.is_object_known(obj));
-		fw.Unsigned32(mos.get_object_file_index(obj));
-	}
-
-	{
-		const std::vector<Ware_Index> & worker_types_without_cost =
-			tribe.worker_types_without_cost();
-		for (uint8_t i = worker_types_without_cost.size(); i;) {
-			uint32_t const next_spawn =
-				warehouse.m_next_worker_without_cost_spawn[--i];
-			if (next_spawn != static_cast<uint32_t>(Never())) {
-				fw.String
-					(tribe.get_worker_descr(tribe.worker_types_without_cost().at(i))
-					 ->name());
-				fw.Unsigned32(next_spawn);
-			}
-		}
-	}
-	fw.Unsigned8(0); //  terminator for spawn times
-
-	fw.Unsigned32(warehouse.m_planned_workers.size());
-	container_iterate_const
-		(std::vector<Warehouse::PlannedWorkers>,
-		 warehouse.m_planned_workers, pw_it)
-	{
-		fw.CString(tribe.get_worker_descr(pw_it.current->index)->name());
-		fw.Unsigned32(pw_it.current->amount);
-
-		fw.Unsigned32(pw_it.current->requests.size());
-		container_iterate_const
-			(std::vector<Request *>, pw_it.current->requests, req_it)
-			(*req_it.current)->Write(fw, game, mos);
-	}
-
-	fw.Unsigned32(warehouse.m_next_stock_remove_act);
-
+	// Storage
+	write_storage(*warehouse.get_storage(), fw, game, mos);
+	// port stuff
 	if (warehouse.descr().get_isport()) {
 		fw.Unsigned32(mos.get_object_file_index_or_zero(warehouse.m_portdock));
 
@@ -1569,42 +1585,7 @@
 {
 	fw.Unsigned16(CURRENT_MILITARYSITE_PACKET_VERSION);
 	write_productionsite(militarysite, fw, game, mos);
-
-	if (militarysite.m_normal_soldier_request) {
-		fw.Unsigned8(1);
-		militarysite.m_normal_soldier_request->Write(fw, game, mos);
-	} else {
-		fw.Unsigned8(0);
-	}
-
-	if (militarysite.m_upgrade_soldier_request)
-	{
-		fw.Unsigned8(1);
-		militarysite.m_upgrade_soldier_request->Write(fw, game, mos);
-	}
-	else
-		fw.Unsigned8(0);
-
-
-	fw.Unsigned8(militarysite.m_didconquer);
-	fw.Unsigned8(militarysite.m_capacity);
-	fw.Signed32(militarysite.m_nexthealtime);
-
-	if (militarysite.m_normal_soldier_request)
-	{
-		if (militarysite.m_upgrade_soldier_request)
-			{
-				throw game_data_error
-				("Internal error in a MilitarySite -- cannot continue. Use previous autosave.");
-			}
-	}
-	fw.Unsigned16(militarysite.m_soldier_upgrade_requirements.getMin());
-	fw.Unsigned16(militarysite.m_soldier_upgrade_requirements.getMax());
-	fw.Unsigned8(militarysite.m_soldier_preference);
-	fw.Signed32(militarysite.m_next_swap_soldiers_time);
-	fw.Unsigned8(militarysite.m_soldier_upgrade_try ? 1 : 0);
-	fw.Unsigned8(militarysite.m_doing_upgrade_request ? 1 : 0);
-
+	write_garrison(*militarysite.get_garrison(), fw, game, mos);
 }
 
 
@@ -1696,17 +1677,8 @@
 	fw.Unsigned16(CURRENT_TRAININGSITE_PACKET_VERSION);
 
 	write_productionsite(trainingsite, fw, game, mos);
-
-	//  requests
-
-	if (trainingsite.m_soldier_request) {
-		fw.Unsigned8(1);
-		trainingsite.m_soldier_request->Write(fw, game, mos);
-	} else {
-		fw.Unsigned8(0);
-	}
-
-	fw.Unsigned8(trainingsite.m_capacity);
+	write_garrison(*trainingsite.get_garrison(), fw, game, mos);
+
 	fw.Unsigned8(trainingsite.m_build_heroes);
 
 	// upgrades
@@ -1736,4 +1708,138 @@
 
 	// DONE
 }
+
+void Map_Buildingdata_Data_Packet::write_garrison(const Garrison& gar, FileWrite& fw, Game& g, Map_Map_Object_Saver& mos)
+{
+	const GarrisonHandler& gh = ref_cast<const GarrisonHandler, const Garrison>(gar);
+	fw.Unsigned16(CURRENT_GARRISON_PACKET_VERSION);
+
+	fw.Unsigned32(gh.m_min_capacity);
+	fw.Unsigned32(gh.m_max_capacity);
+	fw.Unsigned32(gh.m_capacity);
+	// Soldiers
+	// FIXME CGH ensure it is not needed
+	fw.Unsigned8(gh.m_passive ? 1 : 0);
+	fw.Unsigned32(gh.m_heal_per_second);
+	fw.Unsigned32(gh.m_last_heal_time);
+	// requirements-requests
+	gh.m_soldier_requirements.Write(fw, g, mos);
+	fw.Unsigned32(gh.m_soldier_upgrade_requirements.getMin());
+	fw.Unsigned32(gh.m_soldier_upgrade_requirements.getMax());
+	if (gh.m_normal_soldier_request && gh.m_upgrade_soldier_request) {
+		throw game_data_error
+			("Internal error in a garrison -- cannot continue. Use previous autosave.");
+
+	}
+	if (gh.m_normal_soldier_request) {
+		fw.Unsigned8(1);
+		gh.m_normal_soldier_request->Write(fw, g, mos);
+	} else {
+		fw.Unsigned8(0);
+	}
+	if (gh.m_upgrade_soldier_request) {
+		fw.Unsigned8(1);
+		gh.m_upgrade_soldier_request->Write(fw, g, mos);
+	} else {
+		fw.Unsigned8(0);
+	}
+	//
+	fw.Unsigned32(gh.m_conquer_radius);
+	fw.Unsigned8(gh.m_didconquer ? 1 : 0);
+	// Jobs will be done by soldiers (i guess) //FIXME CGH
+	fw.Unsigned8(static_cast<uint8_t>(gh.m_soldier_preference));
+	fw.Unsigned32(gh.m_last_swap_soldiers_time);
+	fw.Unsigned8(gh.m_try_soldier_upgrade ? 1 : 0);
+	fw.Unsigned8(gh.m_doing_upgrade_request ? 1 : 0);
+}
+
+void Map_Buildingdata_Data_Packet::write_storage
+	(const Storage& storage, FileWrite& fw, Game& game, Map_Map_Object_Saver& mos)
+{
+	const StorageHandler& sh = ref_cast<const StorageHandler, const Storage>(storage);
+	fw.Unsigned16(CURRENT_STORAGE_PACKET_VERSION);
+	// basics
+	fw.Unsigned32(sh.m_removal_next_act);
+	// Ware supplies
+	StorageSupply* ss = sh.m_supply.get();
+	const Tribe_Descr& tribe = sh.owner().tribe();
+	const WareList & wares = ss->get_wares();
+	log("WriteStorage : %d wares, %d ware policies\n", wares.get_nrwareids().value(), sh.m_ware_policy.size());
+	for (Ware_Index i = Ware_Index::First(); i < wares.get_nrwareids  (); ++i) {
+		fw.Unsigned8(1);
+		fw.String(tribe.get_ware_descr(i)->name());
+		fw.Unsigned32(wares.stock(i));
+		fw.Unsigned8(static_cast<uint8_t>(sh.get_ware_policy(i)));
+		if (sh.m_spawn_wares.count(i)) {
+			std::vector<uint32_t> values = sh.m_spawn_wares.at(i);
+			// Spawning
+			fw.Unsigned8(1);
+			fw.Unsigned32(values[0]);
+			fw.Unsigned32(values[1]);
+			fw.Unsigned32(values[2]);
+			if (values.size() > 3) {
+				fw.Unsigned8(1);
+				fw.Signed32(values[3]);
+			} else {
+				fw.Unsigned8(0);
+			}
+		} else {
+			fw.Unsigned8(0);
+		}
+	}
+	fw.Unsigned8(0);
+	// Worker supplies
+	const WareList & workers = ss->get_workers();
+	for (Ware_Index i = Ware_Index::First(); i < workers.get_nrwareids  (); ++i) {
+		fw.Unsigned8(1);
+		fw.String(tribe.get_ware_descr(i)->name());
+		fw.Unsigned32(workers.stock(i));
+		fw.Unsigned8(static_cast<uint8_t>(sh.get_worker_policy(i)));
+		if (sh.m_spawn_workers.count(i)) {
+			std::vector<uint32_t> values = sh.m_spawn_workers.at(i);
+			// Spawning
+			fw.Unsigned8(1);
+			fw.Unsigned32(values[0]);
+			fw.Unsigned32(values[1]);
+			fw.Unsigned32(values[2]);
+			if (values.size() > 3) {
+				fw.Unsigned8(1);
+				fw.Signed32(values[3]);
+			} else {
+				fw.Unsigned8(0);
+			}
+		} else {
+			fw.Unsigned8(0);
+		}
+	}
+	fw.Unsigned8(0);
+	// Planned workers
+	fw.Unsigned32(sh.m_planned_workers.size());
+	container_iterate_const
+		(std::vector<StorageHandler::PlannedWorkers>,
+		 sh.m_planned_workers, pw_it)
+	{
+		fw.CString(tribe.get_worker_descr(pw_it.current->index)->name());
+		fw.Unsigned32(pw_it.current->amount);
+
+		fw.Unsigned32(pw_it.current->requests.size());
+		container_iterate_const
+			(std::vector<Request *>, pw_it.current->requests, req_it)
+			(*req_it.current)->Write(fw, game, mos);
+	}
+	// Stocked atributes
+	fw.Unsigned32(sh.m_stocked_workers_atr.size());
+	container_iterate_const
+		(std::vector<StorageHandler::StockedWorkerAtr>,
+		 sh.m_stocked_workers_atr, workers_atr_it)
+	{
+		StorageHandler::StockedWorkerAtr entry = *workers_atr_it.current;
+		fw.CString(tribe.get_worker_descr(entry.index)->name());
+		fw.Unsigned32(entry.atck_lvl);
+		fw.Unsigned32(entry.evade_lvl);
+		fw.Unsigned32(entry.defense_lvl);
+		fw.Unsigned32(entry.exp_or_hp_lvl);
+	}
+}
+
 }

=== modified file 'src/map_io/widelands_map_buildingdata_data_packet.h'
--- src/map_io/widelands_map_buildingdata_data_packet.h	2013-07-26 20:19:36 +0000
+++ src/map_io/widelands_map_buildingdata_data_packet.h	2013-08-06 10:09:46 +0000
@@ -26,6 +26,12 @@
 
 namespace Widelands {
 
+class Storage;
+
+class Garrison;
+
+class Garrison;
+
 class ConstructionSite;
 class Partially_Finished_Building;
 class DismantleSite;
@@ -65,6 +71,10 @@
 		(ProductionSite         &, FileRead  &, Game &, Map_Map_Object_Loader &);
 	virtual void read_formerbuildings_v2
 		(Building               &, FileRead  &, Game &, Map_Map_Object_Loader &);
+	virtual void read_garrison
+		(Garrison        &, FileRead  &, Game &, Map_Map_Object_Loader &);
+	virtual void read_storage
+		(Storage         &, FileRead  &, Game &, Map_Map_Object_Loader &);
 
 	virtual void write_constructionsite
 		(const ConstructionSite &, FileWrite &, Game &, Map_Map_Object_Saver  &);
@@ -80,6 +90,10 @@
 		(const TrainingSite     &, FileWrite &, Game &, Map_Map_Object_Saver  &);
 	virtual void write_productionsite
 		(const ProductionSite   &, FileWrite &, Game &, Map_Map_Object_Saver  &);
+	virtual void write_garrison
+	   (const Garrison   &, FileWrite &, Game &, Map_Map_Object_Saver  &);
+	virtual void write_storage
+	   (const Storage   &, FileWrite &, Game &, Map_Map_Object_Saver  &);
 };
 
 }

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2013-07-26 20:19:36 +0000
+++ src/scripting/lua_game.cc	2013-08-06 10:09:46 +0000
@@ -30,6 +30,7 @@
 #include "logic/path.h"
 #include "logic/player.h"
 #include "logic/tribe.h"
+#include <logic/storagehandler.h>
 #include "scripting/c_utils.h"
 #include "scripting/lua_map.h"
 #include "scripting/scripting.h"
@@ -179,16 +180,16 @@
 */
 int L_Player::get_defeated(lua_State * L) {
 	Player & p = get(L, get_egbase(L));
-	bool have_warehouses = false;
+	bool have_storages = false;
 
 	for (uint32_t economy_nr = 0; economy_nr < p.get_nr_economies(); economy_nr++) {
-		if (!p.get_economy_by_number(economy_nr)->warehouses().empty()) {
-		  have_warehouses = true;
+		if (!p.get_economy_by_number(economy_nr)->storages().empty()) {
+		  have_storages = true;
 		  break;
 		}
 	}
 
-	lua_pushboolean(L, !have_warehouses);
+	lua_pushboolean(L, !have_storages);
 	return 1;
 }
 
@@ -869,23 +870,14 @@
 
 		if (worker_descr.buildcost().empty()) {
 			//  Workers of this type can be spawned in warehouses. Start it.
-			uint8_t worker_types_without_cost_index = 0;
-			for (;; ++worker_types_without_cost_index) {
-				assert
-					(worker_types_without_cost_index
-					 <
-					 worker_types_without_cost.size());
-				if
-					(worker_types_without_cost.at
-						(worker_types_without_cost_index) == i)
-					break;
-			}
 			for (uint32_t j = player.get_nr_economies(); j;) {
 				Economy & economy = *player.get_economy_by_number(--j);
 				container_iterate_const
-					(std::vector<Warehouse *>, economy.warehouses(), k)
-					(*k.current)->enable_spawn
-						(game, worker_types_without_cost_index);
+					(std::vector<Storage *>, economy.storages(), k) {
+						if (upcast(StorageHandler, sh, *k.current)) {
+							sh->add_worker_spawn(worker_descr.worker_index());
+						}
+					}
 			}
 		}
 	}

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2013-07-26 20:19:36 +0000
+++ src/scripting/lua_map.cc	2013-08-06 10:09:46 +0000
@@ -34,6 +34,7 @@
 #include "logic/soldier.h"
 #include "logic/warelist.h"
 #include "logic/widelands_geometry.h"
+#include "logic/storagehandler.h"
 #include "scripting/c_utils.h"
 #include "scripting/lua_game.h"
 #include "wui/mapviewpixelfunctions.h"
@@ -245,12 +246,12 @@
  * _SoldierEmployer
  */
 int _SoldierEmployer::get_max_soldiers(lua_State * L) {
-	lua_pushuint32(L, get_sc(L, get_egbase(L))->maxSoldierCapacity());
+	lua_pushuint32(L, get_garrison(L, get_egbase(L))->maxSoldierCapacity());
 	return 1;
 }
 int _SoldierEmployer::get_soldiers(lua_State * L) {
 	Editor_Game_Base & egbase = get_egbase(L);
-	SoldierControl * sc = get_sc(L, egbase);
+	Garrison * sc = get_garrison(L, egbase);
 	const Tribe_Descr & tribe = get(L, egbase)->owner().tribe();
 
 	const Soldier_Descr & soldier_descr =  //  soldiers
@@ -266,7 +267,7 @@
 }
 int _SoldierEmployer::set_soldiers(lua_State * L) {
 	Editor_Game_Base & egbase = get_egbase(L);
-	SoldierControl * sc = get_sc(L, egbase);
+	Garrison * garrison = get_garrison(L, egbase);
 	Building * building = get(L, egbase);
 	const Tribe_Descr & tribe = building->owner().tribe();
 
@@ -277,7 +278,7 @@
 	SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
 
 	// Get information about current soldiers
-	std::vector<Soldier *> curs = sc->stationedSoldiers();
+	std::vector<Soldier *> curs = garrison->stationedSoldiers();
 	SoldiersMap hist;
 	container_iterate (std::vector<Soldier * >, curs, s) {
 		SoldierDescr sd
@@ -305,7 +306,7 @@
 		int d = sp->second - cur;
 		if (d < 0) {
 			while (d) {
-				std::vector<Soldier *> stationed_soldiers = sc->stationedSoldiers();
+				std::vector<Soldier *> stationed_soldiers = garrison->stationedSoldiers();
 				container_iterate_const(std::vector<Soldier *>, stationed_soldiers, s)
 				{
 					SoldierDescr is
@@ -315,7 +316,7 @@
 						 (*s.current)->get_evade_level());
 
 					if (is == sp->first) {
-						sc->outcorporateSoldier(egbase, **s);
+						garrison->outcorporateSoldier(egbase, **s);
 						(*s.current)->remove(egbase);
 						++d;
 						break;
@@ -333,7 +334,7 @@
 					(sp.current->first.hp, sp.current->first.at,
 					 sp.current->first.de, sp.current->first.ev);
 
-				if (sc->incorporateSoldier(egbase, soldier)) {
+				if (garrison->incorporateSoldier(egbase, soldier)) {
 					soldier.remove(egbase);
 					return report_error(L, "No space left for soldier!");
 				}
@@ -343,6 +344,174 @@
 	return 0;
 }
 
+//TODO CGH implement
+int _StorageOwner::get_ware_policy(lua_State* L)
+{
+	return 0;
+}
+int _StorageOwner::get_worker_policy(lua_State* L)
+{
+	return 0;
+}
+int _StorageOwner::set_ware_policy(lua_State* L)
+{
+	return 0;
+}
+int _StorageOwner::set_worker_policy(lua_State* L)
+{
+	return 0;
+}
+
+int _StorageOwner::get_wares(lua_State* L)
+{
+	Storage * storage = get_storage(L, get_egbase(L));
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	bool return_number = false;
+	WaresSet wares_set = m_parse_get_wares_arguments(L, tribe, &return_number);
+
+	if (not return_number)
+		lua_newtable(L);
+
+	container_iterate_const(WaresSet, wares_set, w) {
+		uint32_t count = storage->get_wares().stock(*w);
+		if (return_number) {
+			lua_pushuint32(L, count);
+			break;
+		} else {
+		   lua_pushstring(L, tribe.get_ware_descr(*w)->name());
+			lua_pushuint32(L, count);
+			lua_rawset(L, -3);
+		}
+	}
+	return 1;
+}
+
+int _StorageOwner::set_wares(lua_State* L)
+{
+	Storage * storage = get_storage(L, get_egbase(L));
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	WaresMap setpoints = m_parse_set_wares_arguments(L, tribe);
+
+	container_iterate_const(WaresMap, setpoints, i) {
+		storage->insert_wares(i->first, i->second);
+	}
+	return 0;
+}
+
+int _StorageOwner::get_workers(lua_State* L)
+{
+	Storage * storage = get_storage(L, get_egbase(L));
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	bool return_number = false;
+	WorkersSet workers_set = m_parse_get_workers_arguments(L, tribe, &return_number);
+
+	if (not return_number)
+		lua_newtable(L);
+
+	container_iterate_const(WorkersSet, workers_set, w) {
+		uint32_t count = storage->get_workers().stock(*w);
+		if (return_number) {
+			lua_pushuint32(L, count);
+			break;
+		} else {
+		   lua_pushstring(L, tribe.get_ware_descr(*w)->name());
+			lua_pushuint32(L, count);
+			lua_rawset(L, -3);
+		}
+	}
+	return 1;
+}
+int _StorageOwner::set_workers(lua_State* L)
+{
+	Storage * storage = get_storage(L, get_egbase(L));
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	WorkersMap setpoints = m_parse_set_workers_arguments(L, tribe);
+
+	container_iterate_const(WorkersMap, setpoints, i) {
+		if (!storage->owner().is_worker_type_allowed(i->first)) {
+			continue;
+		}
+		storage->insert_workers(i->first, i->second);
+	}
+	return 0;
+}
+
+int _StorageOwner::get_soldiers(lua_State* L)
+{
+	Editor_Game_Base & egbase = get_egbase(L);
+	Storage * storage = get_storage(L, egbase);
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	const Soldier_Descr & soldier_descr =  //  soldiers
+			 ref_cast<Soldier_Descr const, Worker_Descr const>
+						(*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+	Game& game = ref_cast<Game, Editor_Game_Base>(egbase);
+	SoldiersList current_soldiers;
+	while (storage->can_create_worker(game, soldier_descr.worker_index())) {
+		Worker& w = storage->launch_worker(game, soldier_descr.worker_index());
+		upcast(Soldier, s, &w);
+		current_soldiers.push_back(s);
+	}
+	return m_handle_get_soldiers(L, soldier_descr, current_soldiers);
+}
+
+int _StorageOwner::set_soldiers(lua_State* L)
+{
+	Editor_Game_Base & egbase = get_egbase(L);
+	Storage * storage = get_storage(L, egbase);
+	const Tribe_Descr & tribe = storage->owner().tribe();
+
+	const Soldier_Descr & soldier_descr =  //  soldiers
+		ref_cast<Soldier_Descr const, Worker_Descr const>
+			(*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+	SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
+
+	// Now add them
+	Game& game = ref_cast<Game, Editor_Game_Base>(egbase);
+	container_iterate_const(SoldiersMap, setpoints, sp) {
+		int d = sp->second;
+		if (d < 0) {
+			while (d) {
+				RequireAttribute hp_req(tAttribute::atrHP, sp->first.hp, sp->first.hp);
+				RequireAttribute at_req(tAttribute::atrAttack, sp->first.at, sp->first.at);
+				RequireAttribute de_req(tAttribute::atrDefense, sp->first.de, sp->first.de);
+				RequireAttribute ev_req(tAttribute::atrEvade, sp->first.ev, sp->first.ev);
+				RequireAnd req;
+				req.add(hp_req);
+				req.add(at_req);
+				req.add(de_req);
+				req.add(ev_req);
+				Worker& w = storage->launch_worker(game, soldier_descr.worker_index(), req);
+				w.remove(game);
+				++d;
+			}
+		} else if (d > 0) {
+			upcast(StorageHandler, sh, storage);
+			for (; d; --d) {
+				Soldier & soldier =
+					ref_cast<Soldier, Worker>
+					(soldier_descr.create
+					 (egbase, storage->owner(), 0,sh->get_building().get_position()));
+
+				soldier.set_level
+					(sp.current->first.hp, sp.current->first.at,
+					 sp.current->first.de, sp.current->first.ev);
+				storage->incorporate_worker(game, soldier);
+			}
+		}
+	}
+	return 0;
+}
+
+
+
+
 
 
 /*
@@ -774,6 +943,17 @@
 	}
 	return 1;
 }
+/* RST
+HasStorage
+------------
+
+.. class:: HasStorage
+
+	Simple wrapper aroung :class: `HasWares` and `HasWorkers`. This interface also
+	contains methods to get and set the various ware policies.
+
+	Supported by :class: Warehouse
+*/
 
 /* RST
 Module Classes
@@ -1693,8 +1873,12 @@
 	METHOD(L_Warehouse, get_wares),
 	METHOD(L_Warehouse, set_workers),
 	METHOD(L_Warehouse, get_workers),
+	METHOD(L_Warehouse, get_soldiers),
 	METHOD(L_Warehouse, set_soldiers),
-	METHOD(L_Warehouse, get_soldiers),
+	METHOD(L_Warehouse, set_ware_policy),
+	METHOD(L_Warehouse, get_ware_policy),
+	METHOD(L_Warehouse, get_worker_policy),
+	METHOD(L_Warehouse, get_worker_policy),
 	{0, 0},
 };
 const PropertyType<L_Warehouse> L_Warehouse::Properties[] = {
@@ -1729,9 +1913,10 @@
 	return 0; \
 }
 // documented in parent class
-WH_SET(ware, Ware);
+// WH_SET(ware, Ware);
 // documented in parent class
-WH_SET(worker, Worker);
+// WH_SET(worker, Worker);
+// WH_SET(soldier, Soldier);
 #undef WH_SET
 
 #define WH_GET(type, btype) \
@@ -1755,9 +1940,10 @@
 	return 1; \
 }
 // documented in parent class
-WH_GET(ware, Ware);
+// WH_GET(ware, Ware);
 // documented in parent class
-WH_GET(worker, Worker);
+// WH_GET(worker, Worker);
+// WH_GET(soldier, Soldier);
 #undef GET
 
 /*
@@ -1765,8 +1951,117 @@
  C METHODS
  ==========================================================
  */
-
-
+/* FIXME CGH to move to headquarterrs
+int L_Warehouse::get_soldiers(lua_State * L) {
+	Editor_Game_Base & egbase = get_egbase(L);
+	Game & game = get_game(L);
+	const Tribe_Descr & tribe = get(L, egbase)->owner().tribe();
+	Warehouse* wh = get(L, egbase);
+	const WareList& wl = wh->get_workers();
+	Ware_Index ware_idx = tribe.safe_worker_index("soldier");
+	uint16_t amount = wl.stock(ware_idx);
+
+	const Soldier_Descr & soldier_descr =  //  soldiers
+			 ref_cast<Soldier_Descr const, Worker_Descr const>
+						(*tribe.get_worker_descr(ware_idx));
+
+	std::vector<Soldier *> vec;
+	for (uint16_t i = 0 ;  i < amount ; i++) {
+		Worker& w = wh->launch_worker(game, ware_idx, Requirements());
+		upcast(Soldier, s, &w);
+		vec.push_back(s);
+	}
+	SoldiersList current_soldiers;
+	return m_handle_get_soldiers(L, soldier_descr, vec);
+}
+
+int L_Warehouse::set_soldiers(lua_State * L) {
+	Editor_Game_Base & egbase = get_egbase(L);
+	Game & game = get_game(L);
+	Warehouse * wh = get(L, egbase);
+	const Tribe_Descr & tribe = wh->owner().tribe();
+
+	const Soldier_Descr & soldier_descr =  //  soldiers
+		ref_cast<Soldier_Descr const, Worker_Descr const>
+			(*tribe.get_worker_descr(tribe.worker_index("soldier")));
+
+	const WareList& wl = wh->get_workers();
+	Ware_Index ware_idx = tribe.safe_worker_index("soldier");
+	uint16_t amount = wl.stock(ware_idx);
+	SoldiersMap setpoints = m_parse_set_soldiers_arguments(L, soldier_descr);
+
+	std::vector<Soldier *> vec;
+	for (uint16_t i = 0 ;  i < amount ; i++) {
+		Worker& w = wh->launch_worker(game, ware_idx, Requirements());
+		upcast(Soldier, s, &w);
+		vec.push_back(s);
+	}
+
+	// Get information about current soldiers
+	std::vector<Soldier *> curs = vec;
+	SoldiersMap hist;
+	container_iterate (std::vector<Soldier * >, curs, s) {
+		SoldierDescr sd
+			((*s.current)->get_hp_level(),
+			 (*s.current)->get_attack_level(),
+			 (*s.current)->get_defense_level(),
+			 (*s.current)->get_evade_level());
+
+		SoldiersMap::iterator i = hist.find(sd);
+		if (i == hist.end())
+			hist[sd] = 1;
+		else
+			i->second += 1;
+		if (not setpoints.count(sd))
+			setpoints[sd] = 0;
+	}
+
+	// Now adjust them
+	container_iterate_const(SoldiersMap, setpoints, sp) {
+		uint32_t cur = 0;
+		SoldiersMap::iterator i = hist.find(sp->first);
+		if (i != hist.end())
+			cur = i->second;
+
+		int d = sp->second - cur;
+		if (d < 0) {
+			while (d) {
+				std::vector<Soldier *> stationed_soldiers = vec;
+				container_iterate_const(std::vector<Soldier *>, stationed_soldiers, s)
+				{
+					SoldierDescr is
+						((*s.current)->get_hp_level(),
+						 (*s.current)->get_attack_level(),
+						 (*s.current)->get_defense_level(),
+						 (*s.current)->get_evade_level());
+
+					if (is == sp->first) {
+						Soldier* sol = *s.current;
+						sol->start_task_leavebuilding(game, true);
+						(*s.current)->remove(egbase);
+						++d;
+						break;
+					}
+				}
+			}
+		} else if (d > 0) {
+			for (; d; --d) {
+				Soldier & soldier =
+					ref_cast<Soldier, Worker>
+					(soldier_descr.create
+					 (egbase, wh->owner(), 0, wh->get_position()));
+
+				soldier.set_level
+					(sp.current->first.hp, sp.current->first.at,
+					 sp.current->first.de, sp.current->first.ev);
+
+				wh->incorporate_worker(egbase, soldier);
+			}
+		}
+	}
+	return 0;
+}
+*/
 /* RST
 ProductionSite
 --------------

=== modified file 'src/scripting/lua_map.h'
--- src/scripting/lua_map.h	2013-07-26 20:19:36 +0000
+++ src/scripting/lua_map.h	2013-08-06 10:09:46 +0000
@@ -31,6 +31,7 @@
 #include "logic/militarysite.h"
 #include "logic/productionsite.h"
 #include "logic/soldier.h"
+#include "logic/storage.h"
 #include "logic/trainingsite.h"
 #include "logic/warehouse.h"
 #include "logic/worker.h"
@@ -251,6 +252,15 @@
 		(lua_State *, const Widelands::Tribe_Descr &);
 };
 
+struct L_HasStorage: public L_HasWares, L_HasWorkers {
+	virtual ~L_HasStorage() {}
+
+	virtual int get_ware_policy(lua_State * L) = 0;
+	virtual int get_worker_policy(lua_State * L) = 0;
+	virtual int set_ware_policy(lua_State * L) = 0;
+	virtual int set_worker_policy(lua_State * L) = 0;
+};
+
 struct L_HasSoldiers {
 	struct SoldierDescr {
 		SoldierDescr(uint8_t ghp, uint8_t gat, uint8_t gde, uint8_t gev) :
@@ -351,7 +361,23 @@
 
 	virtual Widelands::Building * get
 		(lua_State *, Widelands::Editor_Game_Base &) = 0;
-	virtual Widelands::SoldierControl * get_sc
+	virtual Widelands::Garrison * get_garrison
+		(lua_State *, Widelands::Editor_Game_Base &) = 0;
+};
+
+struct _StorageOwner : public L_HasStorage, L_HasSoldiers {
+	virtual int set_wares(lua_State * L);
+	virtual int get_wares(lua_State * L);
+	virtual int set_workers(lua_State * L);
+	virtual int get_workers(lua_State * L);
+	virtual int get_ware_policy(lua_State * L);
+	virtual int get_worker_policy(lua_State * L);
+	virtual int set_ware_policy(lua_State * L);
+	virtual int set_worker_policy(lua_State * L);
+	virtual int get_soldiers(lua_State * L);
+	virtual int set_soldiers(lua_State * L);
+
+	virtual Widelands::Storage * get_storage
 		(lua_State *, Widelands::Editor_Game_Base &) = 0;
 };
 
@@ -416,8 +442,7 @@
 };
 
 
-class L_Warehouse : public L_Building,
-	public L_HasWares, public L_HasWorkers, public _SoldierEmployer
+class L_Warehouse : public L_Building, public _StorageOwner
 {
 public:
 	LUNA_CLASS_HEAD(L_Warehouse);
@@ -435,19 +460,21 @@
 	/*
 	 * Lua Methods
 	 */
-	int set_wares(lua_State *);
-	int get_wares(lua_State *);
-	int set_workers(lua_State *);
-	int get_workers(lua_State *);
 
 	/*
 	 * C Methods
 	 */
 	CASTED_GET(Warehouse);
-	Widelands::SoldierControl * get_sc
+	// FIXME CGH to be put in headquarters
+// 	Widelands::Garrison * get_sc
+// 		(lua_State * L, Widelands::Editor_Game_Base & g)
+// 	{
+// 		return get(L, g);
+// 	}
+	virtual Widelands::Storage * get_storage
 		(lua_State * L, Widelands::Editor_Game_Base & g)
 	{
-		return get(L, g);
+		return get(L, g)->get_storage();
 	}
 };
 
@@ -508,10 +535,10 @@
 	 * C Methods
 	 */
 	CASTED_GET(MilitarySite);
-	Widelands::SoldierControl * get_sc
+	Widelands::Garrison * get_garrison
 		(lua_State * L, Widelands::Editor_Game_Base & g)
 	{
-		return get(L, g);
+		return get(L, g)->get_garrison();
 	}
 };
 
@@ -538,8 +565,10 @@
 	 * C Methods
 	 */
 	CASTED_GET(TrainingSite);
-	Widelands::SoldierControl * get_sc
-		(lua_State * L, Widelands::Editor_Game_Base & g) {return get(L, g);}
+	Widelands::Garrison * get_garrison
+		(lua_State * L, Widelands::Editor_Game_Base & g) {
+			return get(L, g)->get_garrison();
+		}
 };
 
 class L_Bob : public L_MapObject {

=== modified file 'src/wlapplication.cc'
=== modified file 'src/wui/attack_box.h'
--- src/wui/attack_box.h	2013-07-26 19:16:51 +0000
+++ src/wui/attack_box.h	2013-08-06 10:09:46 +0000
@@ -22,7 +22,6 @@
 
 #include <list>
 
-#include "logic/attackable.h"
 #include "logic/bob.h"
 #include "logic/player.h"
 #include "logic/soldier.h"

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2013-08-05 05:20:07 +0000
+++ src/wui/buildingwindow.cc	2013-08-06 10:09:46 +0000
@@ -427,7 +427,7 @@
 {
 	if (is_a(Widelands::MilitarySite, &m_building))
 		igbase().game().send_player_militarysite_set_soldier_preference
-			(m_building, Widelands::MilitarySite::kPrefersRookies);
+			(m_building, Widelands::Garrison::SoldierPref::Rookies);
 
 	die();
 }
@@ -437,7 +437,7 @@
 {
 	if (is_a(Widelands::MilitarySite, &m_building))
 		igbase().game().send_player_militarysite_set_soldier_preference
-			(m_building, Widelands::MilitarySite::kPrefersHeroes);
+			(m_building, Widelands::Garrison::SoldierPref::Heroes);
 
 	die();
 }

=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc	2013-08-02 18:36:03 +0000
+++ src/wui/fieldaction.cc	2013-08-06 10:09:46 +0000
@@ -24,7 +24,6 @@
 #include "economy/road.h"
 #include "graphic/graphic.h"
 #include "i18n.h"
-#include "logic/attackable.h"
 #include "logic/cmd_queue.h"
 #include "logic/maphollowregion.h"
 #include "logic/militarysite.h"
@@ -480,11 +479,11 @@
 
 	if
 		(upcast
-		 	(Widelands::Attackable, attackable, m_map->get_immovable(m_node)))
+		 	(Widelands::GarrisonOwner, go, m_map->get_immovable(m_node)))
 	{
 		if
-			(m_plr && m_plr->is_hostile(attackable->owner()) &&
-			 attackable->canAttack())
+			(go->get_garrison()->canAttack() && m_plr
+			 && m_plr->is_hostile(go->get_garrison()->owner()))
 		{
 			m_attack_box = new AttackBox(&a_box, m_plr, &m_node, 0, 0);
 			a_box.add(m_attack_box, UI::Box::AlignTop);

=== modified file 'src/wui/military_box.h'
--- src/wui/military_box.h	2013-07-26 19:16:51 +0000
+++ src/wui/military_box.h	2013-08-06 10:09:46 +0000
@@ -22,7 +22,6 @@
 
 #include <list>
 
-#include "logic/attackable.h"
 #include "logic/player.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"

=== modified file 'src/wui/soldiercapacitycontrol.cc'
--- src/wui/soldiercapacitycontrol.cc	2013-07-27 10:35:55 +0000
+++ src/wui/soldiercapacitycontrol.cc	2013-08-06 10:09:46 +0000
@@ -21,12 +21,11 @@
 
 #include "graphic/graphic.h"
 #include "logic/player.h"
-#include "logic/soldiercontrol.h"
 #include "ui_basic/button.h"
 #include "ui_basic/radiobutton.h"
 #include "wui/interactive_gamebase.h"
 
-using Widelands::SoldierControl;
+using Widelands::Garrison;
 
 /**
  * Widget to control the capacity of \ref MilitaryBuilding and \ref TrainingSite
@@ -86,16 +85,16 @@
 
 void SoldierCapacityControl::think()
 {
-	SoldierControl * soldiers = dynamic_cast<SoldierControl *>(&m_building);
-	uint32_t const capacity = soldiers->soldierCapacity();
+	Garrison * garrison = dynamic_cast<Widelands::GarrisonOwner *>(&m_building)->get_garrison();
+	uint32_t const capacity = garrison->soldierCapacity();
 	char buffer[sizeof("4294967295")];
 
 	sprintf(buffer, "%2u", capacity);
 	m_value.set_text(buffer);
 
 	bool const can_act = m_igb.can_act(m_building.owner().player_number());
-	m_decrease.set_enabled(can_act && soldiers->minSoldierCapacity() < capacity);
-	m_increase.set_enabled(can_act && soldiers->maxSoldierCapacity() > capacity);
+	m_decrease.set_enabled(can_act && garrison->minSoldierCapacity() < capacity);
+	m_increase.set_enabled(can_act && garrison->maxSoldierCapacity() > capacity);
 }
 
 void SoldierCapacityControl::change_soldier_capacity(int delta)

=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc	2013-07-27 10:35:55 +0000
+++ src/wui/soldierlist.cc	2013-08-06 10:09:46 +0000
@@ -26,10 +26,10 @@
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "logic/building.h"
+#include "logic/garrison.h"
 #include "logic/militarysite.h"
 #include "logic/player.h"
 #include "logic/soldier.h"
-#include "logic/soldiercontrol.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/table.h"
@@ -39,7 +39,7 @@
 #include "wui/soldiercapacitycontrol.h"
 
 using Widelands::Soldier;
-using Widelands::SoldierControl;
+using Widelands::Garrison;
 
 /**
  * Iconic representation of soldiers, including their levels and current HP.
@@ -83,7 +83,7 @@
 	};
 
 	Widelands::Editor_Game_Base & m_egbase;
-	SoldierControl & m_soldiers;
+	Widelands::Garrison & m_garrison;
 
 	SoldierFn m_mouseover_fn;
 	SoldierFn m_click_fn;
@@ -110,14 +110,14 @@
 :
 Panel(&parent, 0, 0, 0, 0),
 m_egbase(gegbase),
-m_soldiers(*dynamic_cast<SoldierControl *>(&building)),
+m_garrison(*dynamic_cast<Widelands::GarrisonOwner *>(&building)->get_garrison()),
 m_last_animate_time(0)
 {
 	Soldier::calc_info_icon_size(building.tribe(), m_icon_width, m_icon_height);
 	m_icon_width += 2 * IconBorder;
 	m_icon_height += 2 * IconBorder;
 
-	uint32_t maxcapacity = m_soldiers.maxSoldierCapacity();
+	uint32_t maxcapacity = m_garrison.maxSoldierCapacity();
 	if (maxcapacity <= MaxColumns) {
 		m_cols = maxcapacity;
 		m_rows = 1;
@@ -131,7 +131,7 @@
 	set_think(true);
 
 	// Initialize the icons
-	std::vector<Soldier *> soldierlist = m_soldiers.presentSoldiers();
+	std::vector<Soldier *> soldierlist = m_garrison.presentSoldiers();
 	uint32_t row = 0;
 	uint32_t col = 0;
 	container_iterate_const(std::vector<Soldier *>, soldierlist, sit) {
@@ -168,10 +168,10 @@
 void SoldierPanel::think()
 {
 	bool changes = false;
-	uint32_t capacity = m_soldiers.soldierCapacity();
+	uint32_t capacity = m_garrison.soldierCapacity();
 
 	// Update soldier list and target row/col:
-	std::vector<Soldier *> soldierlist = m_soldiers.presentSoldiers();
+	std::vector<Soldier *> soldierlist = m_garrison.presentSoldiers();
 	std::vector<uint32_t> row_occupancy;
 	row_occupancy.resize(m_rows);
 
@@ -277,7 +277,7 @@
 void SoldierPanel::draw(RenderTarget & dst)
 {
 	// Fill a region matching the current site capacity with black
-	uint32_t capacity = m_soldiers.soldierCapacity();
+	uint32_t capacity = m_garrison.soldierCapacity();
 	uint32_t fullrows = capacity / MaxColumns;
 
 	if (fullrows)
@@ -362,7 +362,7 @@
 		 Interactive_GameBase & igb,
 		 Widelands::Building & building);
 
-	SoldierControl & soldiers() const;
+	Garrison & garrison() const;
 
 private:
 	void mouseover(const Soldier * soldier);
@@ -418,7 +418,7 @@
 		}
 
 		m_soldier_preference.set_state(0);
-		if (ms->get_soldier_preference() == Widelands::MilitarySite::kPrefersHeroes) {
+		if (garrison().get_soldier_preference() == Garrison::SoldierPref::Heroes) {
 			m_soldier_preference.set_state(1);
 		}
 		m_soldier_preference.changedto.connect
@@ -432,9 +432,9 @@
 	add(buttons, UI::Box::AlignCenter, true);
 }
 
-SoldierControl & SoldierList::soldiers() const
+Garrison & SoldierList::garrison() const
 {
-	return *dynamic_cast<SoldierControl *>(&m_building);
+	return *dynamic_cast<Widelands::GarrisonOwner *>(&m_building)->get_garrison();
 }
 
 void SoldierList::mouseover(const Soldier * soldier)
@@ -463,9 +463,9 @@
 
 void SoldierList::eject(const Soldier * soldier)
 {
-	uint32_t const capacity_min = soldiers().minSoldierCapacity();
+	uint32_t const capacity_min = garrison().minSoldierCapacity();
 	bool can_act = m_igb.can_act(m_building.owner().player_number());
-	bool over_min = capacity_min < soldiers().presentSoldiers().size();
+	bool over_min = capacity_min < garrison().presentSoldiers().size();
 
 	if (can_act && over_min)
 		m_igb.game().send_player_drop_soldier(m_building, soldier->serial());
@@ -474,8 +474,8 @@
 void SoldierList::set_soldier_preference(int32_t changed_to) {
 	upcast(Widelands::MilitarySite, ms, &m_building);
 	assert(ms);
-	ms->set_soldier_preference
-		(changed_to == 0 ? Widelands::MilitarySite::kPrefersRookies : Widelands::MilitarySite::kPrefersHeroes);
+	garrison().set_soldier_preference
+		(changed_to == 0 ? Garrison::SoldierPref::Rookies : Garrison::SoldierPref::Heroes);
 }
 
 UI::Panel * create_soldier_list

=== modified file 'src/wui/stock_menu.cc'
--- src/wui/stock_menu.cc	2013-07-26 20:19:36 +0000
+++ src/wui/stock_menu.cc	2013-08-06 10:09:46 +0000
@@ -34,15 +34,11 @@
 static const char pic_tab_workers_warehouse[] =
 	 "pics/menu_tab_workers_warehouse.png";
 
-Stock_Menu::Stock_Menu
-	(Interactive_Player & plr, UI::UniqueWindow::Registry & registry)
-:
-UI::UniqueWindow(&plr, "stock_menu", &registry, 480, 640, _("Stock")),
-m_player(plr)
+Stock_Menu::Stock_Menu (Interactive_Player & plr, UI::UniqueWindow::Registry & registry)
+:  UI::UniqueWindow(&plr, "stock_menu", &registry, 480, 640, _("Stock")),
+	m_player(plr)
 {
-	UI::Tab_Panel * tabs =
-		 new UI::Tab_Panel
-			 (this, 0, 0, g_gr->images().get("pics/but1.png"));
+	UI::Tab_Panel * tabs = new UI::Tab_Panel(this, 0, 0, g_gr->images().get("pics/but1.png"));
 	set_center_panel(tabs);
 
 	m_all_wares = new WaresDisplay(tabs, 0, 0, plr.player().tribe(), Widelands::wwWARE, false);
@@ -95,11 +91,12 @@
 	waresdisplay->remove_all_warelists();
 	const Widelands::Player & player = *m_player.get_player();
 	const uint32_t nrecos = player.get_nr_economies();
-	for (uint32_t i = 0; i < nrecos; ++i)
+	for (uint32_t i = 0; i < nrecos; ++i) {
 		waresdisplay->add_warelist
 			(type == Widelands::wwWARE ?
 			 player.get_economy_by_number(i)->get_wares() :
 			 player.get_economy_by_number(i)->get_workers());
+	}
 }
 
 /**
@@ -113,13 +110,13 @@
 	const Widelands::Player & player = *m_player.get_player();
 	const uint32_t nrecos = player.get_nr_economies();
 	for (uint32_t i = 0; i < nrecos; ++i) {
-		const std::vector<Widelands::Warehouse *> & warehouses =
-			player.get_economy_by_number(i)->warehouses();
+		const std::vector<Widelands::Storage *> & storages =
+			player.get_economy_by_number(i)->storages();
 
 		for
-			(std::vector<Widelands::Warehouse *>::const_iterator it =
-			 warehouses.begin();
-			 it != warehouses.end();
+			(std::vector<Widelands::Storage *>::const_iterator it =
+			 storages.begin();
+			 it != storages.end();
 			 ++it)
 		{
 			waresdisplay->add_warelist

=== modified file 'src/wui/trainingsitewindow.cc'
--- src/wui/trainingsitewindow.cc	2013-07-26 20:19:36 +0000
+++ src/wui/trainingsitewindow.cc	2013-08-06 10:09:46 +0000
@@ -36,10 +36,6 @@
 	TrainingSite_Window
 		(Interactive_GameBase & parent, TrainingSite &, UI::Window * & registry);
 
-	TrainingSite & trainingsite() {
-		return ref_cast<TrainingSite, Widelands::Building>(building());
-	}
-
 protected:
 	virtual void create_capsbuttons(UI::Box * buttons);
 };
@@ -54,7 +50,7 @@
 {
 	get_tabs()->add
 		("soldiers", g_gr->images().get(pic_tab_military),
-		 create_soldier_list(*get_tabs(), parent, trainingsite()),
+		 create_soldier_list(*get_tabs(), parent, ts),
 		 _("Soldiers in training"));
 }
 

=== modified file 'src/wui/warehousewindow.cc'
--- src/wui/warehousewindow.cc	2013-08-02 14:20:21 +0000
+++ src/wui/warehousewindow.cc	2013-08-06 10:09:46 +0000
@@ -21,6 +21,7 @@
 #include "graphic/rendertarget.h"
 #include "logic/player.h"
 #include "logic/playercommand.h"
+#include "logic/storage.h"
 #include "logic/warehouse.h"
 #include "ui_basic/tabpanel.h"
 #include "wui/buildingwindow.h"
@@ -63,20 +64,28 @@
 m_warehouse(wh)
 {
 	set_inner_size(width, 0);
-	add_warelist(type == Widelands::wwWORKER ? m_warehouse.get_workers() : m_warehouse.get_wares());
+	add_warelist(type == Widelands::wwWORKER ?
+		m_warehouse.get_storage()->get_workers()
+		: m_warehouse.get_storage()->get_wares());
 }
 
 void WarehouseWaresDisplay::draw_ware(RenderTarget & dst, Widelands::Ware_Index ware)
 {
 	WaresDisplay::draw_ware(dst, ware);
 
-	Warehouse::StockPolicy policy = m_warehouse.get_stock_policy(get_type(), ware);
+	Widelands::Storage::StockPolicy policy = m_warehouse.get_storage()->get_stock_policy(get_type(), ware);
 	const Image* pic;
 
 	switch (policy) {
-	case Warehouse::SP_Prefer: pic = g_gr->images().get(pic_policy_prefer); break;
-	case Warehouse::SP_DontStock: pic = g_gr->images().get(pic_policy_dontstock); break;
-	case Warehouse::SP_Remove: pic = g_gr->images().get(pic_policy_remove); break;
+	case Widelands::Storage::StockPolicy::Prefer:
+		pic = g_gr->images().get(pic_policy_prefer);
+		break;
+	case Widelands::Storage::StockPolicy::DontStock:
+		pic = g_gr->images().get(pic_policy_dontstock);
+		break;
+	case Widelands::Storage::StockPolicy::Remove:
+		pic = g_gr->images().get(pic_policy_remove);
+		break;
 	default:
 		// don't draw anything for the normal policy
 		return;
@@ -93,7 +102,7 @@
 		(UI::Panel * parent, uint32_t width,
 		 Interactive_GameBase &, Warehouse &, Widelands::WareWorker type);
 
-	void set_policy(Warehouse::StockPolicy);
+	void set_policy(Widelands::Storage::StockPolicy);
 private:
 	Interactive_GameBase & m_gb;
 	Warehouse & m_wh;
@@ -127,7 +136,7 @@
 			 g_gr->images().get("pics/stock_policy_button_" #policy ".png"),      \
 			 tooltip),                                                                        \
 		b->sigclicked.connect \
-			(boost::bind(&WarehouseWaresPanel::set_policy, this, Warehouse::SP_##policyname)), \
+		  (boost::bind(&WarehouseWaresPanel::set_policy, this,Widelands::Storage::StockPolicy::policyname)), \
 		buttons->add(b, UI::Box::AlignCenter);
 
 		ADD_POLICY_BUTTON(normal, Normal, _("Normal policy"))
@@ -140,7 +149,7 @@
 /**
  * Add Buttons policy buttons
  */
-void WarehouseWaresPanel::set_policy(Warehouse::StockPolicy newpolicy) {
+void WarehouseWaresPanel::set_policy(Widelands::Storage::StockPolicy newpolicy) {
 	bool is_workers = m_type == Widelands::wwWORKER;
 	Widelands::Ware_Index nritems =
 	                   is_workers ? m_wh.owner().tribe().get_nrworkers() :


Follow ups