From c0de6fd1f0450d961435e150bffadd53d8e94a7b Mon Sep 17 00:00:00 2001
From: cybermind <iddqd_mail@mail.ru>
Date: Fri, 11 May 2012 14:19:30 +0600
Subject: [PATCH] [+] Ability to set specific rules for AI players how to build
 buildings. Use AiBuildingRules in CUnitType for that (same syntax as in
 BuildingRules) [+] Defence forces now can return to base if no more enemy
 units left. [+] Move CUnitType._Storing to stats, it's possible to use
 Storing in upgrades. [*] Don't check the builder in CBuildRestrictionDistance
 [*] Don't restore the saved attack order for dead units. [-] Fixed bug which
 didn't let the defence force to retaliate.

---
 src/action/action_build.cpp              |  2 +-
 src/action/action_upgradeto.cpp          |  2 +-
 src/ai/ai_force.cpp                      | 45 ++++++++++++++++++----
 src/ai/ai_local.h                        |  5 ++-
 src/animation/animation_setplayervar.cpp |  4 +-
 src/editor/editloop.cpp                  |  2 +-
 src/include/unit.h                       |  2 +-
 src/include/unittype.h                   | 12 +++---
 src/include/upgrade_structs.h            |  2 +
 src/stratagus/script_player.cpp          |  2 +-
 src/unit/build.cpp                       | 48 +++++++++++++++++-------
 src/unit/script_unittype.cpp             | 37 +++++++++++++++++-
 src/unit/unit.cpp                        | 22 ++++++-----
 src/unit/unittype.cpp                    | 19 +++++++++-
 src/unit/upgrade.cpp                     | 16 ++++++++
 15 files changed, 173 insertions(+), 47 deletions(-)

diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp
index e1ded867b..786afdc56 100644
--- a/src/action/action_build.cpp
+++ b/src/action/action_build.cpp
@@ -330,7 +330,7 @@ bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop)
 	if (&ontop != &unit) {
 		CBuildRestrictionOnTop *b;
 
-		b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(*build, ontop.Type));
+		b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(unit.Type->BuildingRules, *build, ontop.Type));
 		Assert(b);
 		if (b->ReplaceOnBuild) {
 			build->ResourcesHeld = ontop.ResourcesHeld; // We capture the value of what is beneath.
diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp
index 70f6c1cd8..346a8a396 100644
--- a/src/action/action_upgradeto.cpp
+++ b/src/action/action_upgradeto.cpp
@@ -115,7 +115,7 @@ static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
 	// Change resource limit
 	for (int i = 0; i < MaxCosts; ++i) {
 		if (player.MaxResources[i] != -1) {
-			player.MaxResources[i] += newtype._Storing[i] - oldtype._Storing[i];
+			player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i];
 			player.SetResource(i, player.StoredResources[i], true);
 		}
 	}
diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp
index 2877d49b6..5331c68ad 100644
--- a/src/ai/ai_force.cpp
+++ b/src/ai/ai_force.cpp
@@ -270,6 +270,12 @@ void AiForce::Attack(const Vec2i &pos)
 	Vec2i goalPos(pos);
 	RemoveDeadUnit();
 
+	// Remember the original force position so we can return there after attack
+	if (this->Size() > 0 && (this->Role == AiForceRoleDefend && !this->Attacking)
+		|| (this->Role == AiForceRoleAttack && !this->Attacking && !this->State)) {
+		this->HomePos = this->Units[0]->tilePos;
+	}
+
 	Attacking = false;
 	if (Units.size() == 0) {
 		return;
@@ -295,6 +301,20 @@ void AiForce::Attack(const Vec2i &pos)
 	}
 	//  Send all units in the force to enemy.
 	this->State = AiForceAttackingState_Attacking;
+	for (size_t i = 0; i != this->Units.size(); ++i) {
+		CUnit* const unit = this->Units[i];
+		int delta = 0;
+		if (unit->Container == NULL) {
+			// To avoid lot of CPU consuption, send them with a small time difference.
+			unit->Wait = delta;
+			++delta;
+			if (unit->Type->CanAttack) {
+				CommandAttack(*unit, goalPos,  NULL, FlushCommands);
+			} else {
+				CommandMove(*unit, goalPos, FlushCommands);
+			}
+		}
+	}
 }
 
 AiForceManager::AiForceManager()
@@ -706,13 +726,24 @@ void AiForceManager::Update()
 
 		if (force.Defending) {
 			force.RemoveDeadUnit();
-			//  Look if still enemies in attack range.
-			const CUnit *dummy = NULL;
-			if (!AiForceEnemyFinder<true>(force, &dummy).found()) {
-				DebugPrint("%d:FIXME: not written, should send force #%d home\n"
-						   _C_ AiPlayer->Player->Index _C_ f);
-				force.Defending = false;
-				force.Attacking = false;
+			//  Check if some unit from force reached goal point
+			if (Map.Info.IsPointOnMap(force.GoalPos) &&
+				force.Units[0]->MapDistanceTo(force.GoalPos) <= 5) {
+				//  Look if still enemies in attack range.
+				const CUnit *dummy = NULL;
+				if (!AiForceEnemyFinder<true>(force, &dummy).found()) {
+					if (Map.Info.IsPointOnMap(force.HomePos)) {
+						const Vec2i invalidPos = { -1, -1};
+
+						for (size_t i = 0; i != force.Units.size(); ++i) {
+							CUnit* const unit = force.Units[i];
+							CommandMove(*unit, force.HomePos, FlushCommands);
+						}
+						force.HomePos = invalidPos;
+					}
+					force.Defending = false;
+					force.Attacking = false;
+				}
 			}
 		} else if (force.Attacking) {
 			force.RemoveDeadUnit();
diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h
index b535b7d85..ddc6db80c 100644
--- a/src/ai/ai_local.h
+++ b/src/ai/ai_local.h
@@ -117,7 +117,7 @@ public:
 	AiForce() :
 		Completed(false), Defending(false), Attacking(false),
 		Role(AiForceRoleDefault), State(AiForceAttackingState_Free) {
-		GoalPos.x = GoalPos.y = -1;
+		HomePos.x = HomePos.y = GoalPos.x = GoalPos.y = -1;
 	}
 
 	void Remove(CUnit &unit) {
@@ -141,7 +141,7 @@ public:
 		}
 		Units.for_each(InternalRemoveUnit);
 		Units.clear();
-		GoalPos.x = GoalPos.y = 0;
+		GoalPos.x = GoalPos.y = -1;
 	}
 	inline size_t Size() const { return Units.size(); }
 
@@ -178,6 +178,7 @@ public:
 	// If attacking
 	AiForceAttackingState State; /// Attack state
 	Vec2i GoalPos; /// Attack point tile map position
+	Vec2i HomePos; /// Return after attack tile map position
 };
 
 // forces
diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp
index d06b58786..013659236 100644
--- a/src/animation/animation_setplayervar.cpp
+++ b/src/animation/animation_setplayervar.cpp
@@ -61,15 +61,13 @@ int GetPlayerData(int player, const char *prop, const char *arg)
 	if (!strcmp(prop, "RaceName")) {
 		return Players[player].Race;
 	} else if (!strcmp(prop, "Resources")) {
-
 		const int resId = GetResourceIdByName(arg);
 		if (resId == -1) {
 			fprintf(stderr, "Invalid resource \"%s\"", arg);
 			Exit(1);
 		}
-		return Players[player].Resources[resId];
+		return Players[player].Resources[resId] + Players[player].StoredResources[resId];
 	} else if (!strcmp(prop, "StoredResources")) {
-
 		const int resId = GetResourceIdByName(arg);
 		if (resId == -1) {
 			fprintf(stderr, "Invalid resource \"%s\"", arg);
diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp
index 9244e2174..9436d50d9 100644
--- a/src/editor/editloop.cpp
+++ b/src/editor/editloop.cpp
@@ -329,7 +329,7 @@ static void EditorActionPlaceUnit(const Vec2i &pos, CUnitType &type, CPlayer *pl
 		return;
 	}
 
-	CBuildRestrictionOnTop *b = OnTopDetails(*unit, NULL);
+	CBuildRestrictionOnTop *b = OnTopDetails(unit->Type->BuildingRules, *unit, NULL);
 	if (b && b->ReplaceOnBuild) {
 		CUnitCache &unitCache = Map.Field(pos)->UnitCache;
 		CUnitCache::iterator it = std::find_if(unitCache.begin(), unitCache.end(), HasSameTypeAs(*b->Parent));
diff --git a/src/include/unit.h b/src/include/unit.h
index dae36222a..15517feaa 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -915,7 +915,7 @@ extern void DropOutNearest(CUnit &unit, const Vec2i &goalPos, const CUnit *conta
 extern void DropOutAll(const CUnit &unit);
 
 /// Return the rule used to build this building.
-extern CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent);
+extern CBuildRestrictionOnTop *OnTopDetails(std::vector<CBuildRestriction *> &restr, const CUnit &unit, const CUnitType *parent);
 /// @todo more docu
 extern CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos);
 /// @todo more docu
diff --git a/src/include/unittype.h b/src/include/unittype.h
index 2871d00fe..d4aeae9cd 100644
--- a/src/include/unittype.h
+++ b/src/include/unittype.h
@@ -801,7 +801,7 @@ class CBuildRestriction
 public:
 	virtual ~CBuildRestriction() {}
 	virtual void Init() {};
-	virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const = 0;
+	virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const = 0;
 };
 
 
@@ -822,7 +822,7 @@ public:
 			(*i)->Init();
 		}
 	}
-	virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
+	virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
 
 	void push_back(CBuildRestriction *restriction) { _or_list.push_back(restriction); }
 public:
@@ -846,7 +846,7 @@ public:
 	CBuildRestrictionAddOn() : Parent(NULL) { Offset.x = Offset.y = 0; };
 	virtual ~CBuildRestrictionAddOn() {};
 	virtual void Init() {this->Parent = UnitTypeByIdent(this->ParentName);};
-	virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
+	virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
 
 	Vec2i Offset;         /// offset from the main building to place this
 	std::string ParentName; /// building that is unit is an addon too.
@@ -869,7 +869,7 @@ public:
 	CBuildRestrictionOnTop() : Parent(NULL), ReplaceOnDie(0), ReplaceOnBuild(0) {};
 	virtual ~CBuildRestrictionOnTop() {};
 	virtual void Init() {this->Parent = UnitTypeByIdent(this->ParentName);};
-	virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
+	virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
 
 	std::string ParentName;  /// building that is unit is an addon too.
 	CUnitType *Parent;   /// building that is unit is an addon too.
@@ -883,7 +883,7 @@ public:
 	CBuildRestrictionDistance() : Distance(0), RestrictType(NULL) {};
 	virtual ~CBuildRestrictionDistance() {};
 	virtual void Init() {this->RestrictType = UnitTypeByIdent(this->RestrictTypeName);};
-	virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
+	virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
 
 	int Distance;        /// distance to build (circle)
 	DistanceTypeType DistanceType;
@@ -948,7 +948,6 @@ public:
 
 	CConstruction *Construction;    /// What is shown in construction phase
 
-	int _Storing[MaxCosts];         /// How many resources the unit can store
 	int RepairHP;                   /// Amount of HP per repair
 	int RepairCosts[MaxCosts];      /// How much it costs to repair
 
@@ -1032,6 +1031,7 @@ public:
 	int GivesResource;                  /// The resource this unit gives.
 	ResourceInfo *ResInfo[MaxCosts];    /// Resource information.
 	std::vector<CBuildRestriction *> BuildingRules;   /// Rules list for building a building.
+	std::vector<CBuildRestriction *> AiBuildingRules; /// Rules list for for AI to build a building.
 	SDL_Color NeutralMinimapColorRGB;   /// Minimap Color for Neutral Units.
 
 	CUnitSound Sound;               /// Sounds for events
diff --git a/src/include/upgrade_structs.h b/src/include/upgrade_structs.h
index a139dd387..707f01401 100644
--- a/src/include/upgrade_structs.h
+++ b/src/include/upgrade_structs.h
@@ -140,6 +140,7 @@ class CUnitStats
 public:
 	CUnitStats() : Variables(NULL) {
 		memset(Costs, 0, sizeof(Costs));
+		memset(Storing, 0, sizeof(Storing));
 	}
 	~CUnitStats();
 
@@ -150,6 +151,7 @@ public:
 public:
 	CVariable *Variables;           /// user defined variable.
 	int Costs[MaxCosts];            /// current costs of the unit
+	int Storing[MaxCosts];          /// storage increasing
 };
 
 /**
diff --git a/src/stratagus/script_player.cpp b/src/stratagus/script_player.cpp
index 632f0fb45..2b8b89a71 100644
--- a/src/stratagus/script_player.cpp
+++ b/src/stratagus/script_player.cpp
@@ -718,7 +718,7 @@ static int CclGetPlayerData(lua_State *l)
 
 		const std::string res = LuaToString(l, 3);
 		const int resId = GetResourceIdByName(l, res.c_str());
-		lua_pushnumber(l, p->Resources[resId]);
+		lua_pushnumber(l, p->Resources[resId] + p->StoredResources[resId]);
 		return 1;
 	} else if (!strcmp(data, "StoredResources")) {
 		LuaCheckArgs(l, 3);
diff --git a/src/unit/build.cpp b/src/unit/build.cpp
index 7b8a2e583..db8f403fa 100644
--- a/src/unit/build.cpp
+++ b/src/unit/build.cpp
@@ -55,13 +55,14 @@
 **
 **  @return        the BuildingRestrictionDetails
 */
-CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent)
+CBuildRestrictionOnTop *OnTopDetails(std::vector<CBuildRestriction *> &restr, 
+									 const CUnit &unit, const CUnitType *parent)
 {
 	CBuildRestrictionAnd *andb;
 	CBuildRestrictionOnTop *ontopb;
 
-	for (std::vector<CBuildRestriction *>::iterator i = unit.Type->BuildingRules.begin();
-		 i != unit.Type->BuildingRules.end(); ++i) {
+	for (std::vector<CBuildRestriction *>::const_iterator i = restr.begin();
+		 i != restr.end(); ++i) {
 		if ((ontopb = dynamic_cast<CBuildRestrictionOnTop *>(*i))) {
 			if (!parent) {
 				// Guess this is right
@@ -91,10 +92,10 @@ CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent)
 /**
 **  Check And Restriction
 */
-bool CBuildRestrictionAnd::Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const
+bool CBuildRestrictionAnd::Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const
 {
 	for (std::vector<CBuildRestriction *>::const_iterator i = _or_list.begin(); i != _or_list.end(); ++i) {
-		if (!(*i)->Check(type, pos, ontoptarget)) {
+		if (!(*i)->Check(builder, type, pos, ontoptarget)) {
 			return false;
 		}
 	}
@@ -104,7 +105,7 @@ bool CBuildRestrictionAnd::Check(const CUnitType &type, const Vec2i &pos, CUnit
 /**
 **  Check Distance Restriction
 */
-bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, CUnit *&) const
+bool CBuildRestrictionDistance::Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&) const
 {
 	Vec2i pos1 = {0, 0};
 	Vec2i pos2 = {0, 0};
@@ -133,7 +134,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
 		case GreaterThan :
 		case GreaterThanEqual :
 			for (size_t i = 0; i != table.size(); ++i) {
-				if (this->RestrictType == table[i]->Type &&
+				if (builder != table[i] && this->RestrictType == table[i]->Type &&
 					MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) <= distance) {
 					return false;
 				}
@@ -142,7 +143,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
 		case LessThan :
 		case LessThanEqual :
 			for (size_t i = 0; i != table.size(); ++i) {
-				if (this->RestrictType == table[i]->Type &&
+				if (builder != table[i] && this->RestrictType == table[i]->Type &&
 					MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) <= distance) {
 					return true;
 				}
@@ -150,7 +151,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
 			return false;
 		case Equal :
 			for (size_t i = 0; i != table.size(); ++i) {
-				if (this->RestrictType == table[i]->Type &&
+				if (builder != table[i] && this->RestrictType == table[i]->Type &&
 					MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) == distance) {
 					return true;
 				}
@@ -158,7 +159,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
 			return false;
 		case NotEqual :
 			for (size_t i = 0; i != table.size(); ++i) {
-				if (this->RestrictType == table[i]->Type &&
+				if (builder != table[i] && this->RestrictType == table[i]->Type &&
 					MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) == distance) {
 					return false;
 				}
@@ -176,7 +177,7 @@ inline bool CBuildRestrictionAddOn::functor::operator()(const CUnit *const unit)
 /**
 **  Check AddOn Restriction
 */
-bool CBuildRestrictionAddOn::Check(const CUnitType &, const Vec2i &pos, CUnit *&) const
+bool CBuildRestrictionAddOn::Check(const CUnit *, const CUnitType &, const Vec2i &pos, CUnit *&) const
 {
 	Vec2i pos1 = pos - this->Offset;
 
@@ -218,7 +219,7 @@ private:
 };
 
 
-bool CBuildRestrictionOnTop::Check(const CUnitType &, const Vec2i &pos, CUnit *&ontoptarget) const
+bool CBuildRestrictionOnTop::Check(const CUnit *, const CUnitType &, const Vec2i &pos, CUnit *&ontoptarget) const
 {
 	Assert(Map.Info.IsPointOnMap(pos));
 
@@ -291,7 +292,7 @@ CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos)
 		for (unsigned int i = 0; i < count; ++i) {
 			CBuildRestriction *rule = type.BuildingRules[i];
 			// All checks processed, did we really have success
-			if (rule->Check(type, pos, ontoptarget)) {
+			if (rule->Check(unit, type, pos, ontoptarget)) {
 				// We passed a full ruleset return
 				if (unit == NULL) {
 					return ontoptarget ? ontoptarget : (CUnit *)1;
@@ -302,6 +303,27 @@ CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos)
 		}
 		return NULL;
 	}
+
+	// Check special rules for AI players
+	if (unit->Player->AiEnabled) {
+		size_t count = type.AiBuildingRules.size();
+		if (count > 0) {
+			ontoptarget = NULL;
+			for (unsigned int i = 0; i < count; ++i) {
+				CBuildRestriction *rule = type.AiBuildingRules[i];
+				// All checks processed, did we really have success
+				if (rule->Check(unit, type, pos, ontoptarget)) {
+					// We passed a full ruleset return
+					if (unit == NULL) {
+						return ontoptarget ? ontoptarget : (CUnit *)1;
+					} else {
+						return ontoptarget ? ontoptarget : (CUnit *)unit;
+					}
+				}
+			}
+			return NULL;
+		}
+	}
 	return (unit == NULL) ? (CUnit *)1 : const_cast<CUnit *>(unit);
 }
 
diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp
index 53e90b171..402370797 100644
--- a/src/unit/script_unittype.cpp
+++ b/src/unit/script_unittype.cpp
@@ -489,7 +489,7 @@ static int CclDefineUnitType(lua_State *l)
 				lua_pop(l, 1);
 				++k;
 				lua_rawgeti(l, -1, k + 1);
-				type->_Storing[res] = LuaToNumber(l, -1);
+				type->DefaultStat.Storing[res] = LuaToNumber(l, -1);
 				lua_pop(l, 1);
 			}
 		} else if (!strcmp(value, "ImproveProduction")) {
@@ -745,6 +745,25 @@ static int CclDefineUnitType(lua_State *l)
 				ParseBuildingRules(l, type->BuildingRules);
 				lua_pop(l, 1);
 			}
+		} else if (!strcmp(value, "AiBuildingRules")) {
+			if (!lua_istable(l, -1)) {
+				LuaError(l, "incorrect argument");
+			}
+			subargs = lua_rawlen(l, -1);
+			// Free any old restrictions if they are redefined
+			for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
+				b != type->AiBuildingRules.end(); ++b) {
+					delete *b;
+			}
+			type->AiBuildingRules.clear();
+			for (k = 0; k < subargs; ++k) {
+				lua_rawgeti(l, -1, k + 1);
+				if (!lua_istable(l, -1)) {
+					LuaError(l, "incorrect argument");
+				}
+				ParseBuildingRules(l, type->AiBuildingRules);
+				lua_pop(l, 1);
+			}
 		} else if (!strcmp(value, "BuilderOutside")) {
 			type->BuilderOutside = LuaToBoolean(l, -1);
 		} else if (!strcmp(value, "BuilderLost")) {
@@ -1160,6 +1179,22 @@ static int CclDefineUnitStats(lua_State *l)
 				stats->Costs[resId] = LuaToNumber(l, -1);
 				lua_pop(l, 1);
 			}
+		} else if (!strcmp(value, "storing")) {
+			if (!lua_istable(l, j + 1)) {
+				LuaError(l, "incorrect argument");
+			}
+			const int subargs = lua_rawlen(l, j + 1);
+
+			for (int k = 0; k < subargs; ++k) {
+				lua_rawgeti(l, j + 1, k + 1);
+				value = LuaToString(l, -1);
+				lua_pop(l, 1);
+				++k;
+				const int resId = GetResourceIdByName(l, value);
+				lua_rawgeti(l, j + 1, k + 1);
+				stats->Storing[resId] = LuaToNumber(l, -1);
+				lua_pop(l, 1);
+			}
 		} else {
 			int i = UnitTypeVar.VariableNameLookup[value];// User variables
 			if (i != -1) { // valid index
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 85279b81d..aef5f0d40 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -367,7 +367,11 @@ void CUnit::Init(CUnitType &type)
 */
 bool CUnit::RestoreOrder()
 {
-	if (this->SavedOrder == NULL) {
+	COrder *savedOrder = this->SavedOrder;
+
+	if (savedOrder == NULL 
+		|| (savedOrder->Action == UnitActionAttack 
+		&& (!savedOrder->HasGoal() || savedOrder->GetGoal()->IsAlive()))) {
 		return false;
 	}
 
@@ -380,7 +384,7 @@ bool CUnit::RestoreOrder()
 
 
 	//copy
-	this->Orders.insert(this->Orders.begin() + 1, this->SavedOrder);
+	this->Orders.insert(this->Orders.begin() + 1, savedOrder);
 
 	this->SavedOrder = NULL;
 	return true;
@@ -966,8 +970,8 @@ void UnitLost(CUnit &unit)
 		player.Supply -= type.Supply;
 		// Decrease resource limit
 		for (int i = 0; i < MaxCosts; ++i) {
-			if (player.MaxResources[i] != -1 && type._Storing[i]) {
-				const int newMaxValue = player.MaxResources[i] - type._Storing[i];
+			if (player.MaxResources[i] != -1 && type.Stats[player.Index].Storing[i]) {
+				const int newMaxValue = player.MaxResources[i] - type.Stats[player.Index].Storing[i];
 
 				player.MaxResources[i] = std::max(0, newMaxValue);
 				player.SetResource(i, player.StoredResources[i], true);
@@ -994,7 +998,7 @@ void UnitLost(CUnit &unit)
 	DebugPrint("%d: Lost %s(%d)\n" _C_ player.Index _C_ type.Ident.c_str() _C_ UnitNumber(unit));
 
 	// Destroy resource-platform, must re-make resource patch.
-	if ((b = OnTopDetails(unit, NULL)) != NULL) {
+	if ((b = OnTopDetails(unit.Type->BuildingRules, unit, NULL)) != NULL) {
 		if (b->ReplaceOnDie && (type.GivesResource && unit.ResourcesHeld != 0)) {
 			temp = MakeUnitAndPlace(unit.tilePos, *b->Parent, &Players[PlayerNumNeutral]);
 			if (temp == NoUnitP) {
@@ -1040,8 +1044,8 @@ void UpdateForNewUnit(const CUnit &unit, int upgrade)
 	if (!upgrade) {
 		player.Supply += type.Supply;
 		for (int i = 0; i < MaxCosts; ++i) {
-			if (player.MaxResources[i] != -1 && type._Storing[i]) {
-				player.MaxResources[i] += type._Storing[i];
+			if (player.MaxResources[i] != -1 && type.Stats[player.Index].Storing[i]) {
+				player.MaxResources[i] += type.Stats[player.Index].Storing[i];
 			}
 		}
 	}
@@ -1559,8 +1563,8 @@ void CUnit::ChangeOwner(CPlayer &newplayer)
 	newplayer.Supply += Type->Supply;
 	// Increase resource limit
 	for (int i = 0; i < MaxCosts; ++i) {
-		if (newplayer.MaxResources[i] != -1 && Type->_Storing[i]) {
-			newplayer.MaxResources[i] += Type->_Storing[i];
+		if (newplayer.MaxResources[i] != -1 && Type->Stats[newplayer.Index].Storing[i]) {
+			newplayer.MaxResources[i] += Type->Stats[newplayer.Index].Storing[i];
 		}
 	}
 	if (Type->Building && !Type->Wall) {
diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp
index 11162ce5f..bb7adc314 100644
--- a/src/unit/unittype.cpp
+++ b/src/unit/unittype.cpp
@@ -163,7 +163,6 @@ CUnitType::CUnitType() :
 #ifdef USE_MNG
 	memset(&Portrait, 0, sizeof(Portrait));
 #endif
-	memset(_Storing, 0, sizeof(_Storing));
 	memset(RepairCosts, 0, sizeof(RepairCosts));
 	memset(CanStore, 0, sizeof(CanStore));
 	memset(ResInfo, 0, sizeof(ResInfo));
@@ -184,6 +183,11 @@ CUnitType::~CUnitType()
 		delete *b;
 	}
 	BuildingRules.clear();
+	for (std::vector<CBuildRestriction *>::iterator b = AiBuildingRules.begin();
+		b != AiBuildingRules.end(); ++b) {
+			delete *b;
+	}
+	AiBuildingRules.clear();
 
 	delete[] CanCastSpell;
 	delete[] AutoCastActive;
@@ -378,6 +382,13 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl
 		}
 		file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Costs[i]);
 	}
+	file.printf("\"storing\", {");
+	for (unsigned int i = 0; i < MaxCosts; ++i) {
+		if (i) {
+			file.printf(" ");
+		}
+		file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Storing[i]);
+	}
 	file.printf("})\n");
 	return true;
 }
@@ -538,6 +549,12 @@ void InitUnitTypes(int reset_player_stats)
 			 b < type->BuildingRules.end(); ++b) {
 			(*b)->Init();
 		}
+
+		// Lookup AiBuildingTypes
+		for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
+			b < type->AiBuildingRules.end(); ++b) {
+				(*b)->Init();
+		}
 	}
 
 	// LUDO : called after game is loaded -> don't reset stats !
diff --git a/src/unit/upgrade.cpp b/src/unit/upgrade.cpp
index f3443dd8d..c259e6dcd 100644
--- a/src/unit/upgrade.cpp
+++ b/src/unit/upgrade.cpp
@@ -91,6 +91,7 @@ const CUnitStats &CUnitStats::operator = (const CUnitStats &rhs)
 {
 	for (unsigned int i = 0; i < MaxCosts; ++i) {
 		this->Costs[i] = rhs.Costs[i];
+		this->Storing[i] = rhs.Storing[i];
 	}
 	delete [] this->Variables;
 	const unsigned int size = UnitTypeVar.GetNumberVariable();
@@ -106,6 +107,9 @@ bool CUnitStats::operator == (const CUnitStats &rhs) const
 		if (this->Costs[i] != rhs.Costs[i]) {
 			return false;
 		}
+		if (this->Storing[i] != rhs.Storing[i]) {
+			return false;
+		}
 	}
 	for (unsigned int i = 0; i != UnitTypeVar.GetNumberVariable(); ++i) {
 		if (this->Variables[i] != rhs.Variables[i]) {
@@ -295,6 +299,17 @@ static int CclDefineModifier(lua_State *l)
 			lua_rawgeti(l, j + 1, 2);
 			um->Modifier.Costs[resId] = LuaToNumber(l, -1);
 			lua_pop(l, 1);
+		} else if (!strcmp(key, "storing")) {
+			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
+				LuaError(l, "incorrect argument");
+			}
+			lua_rawgeti(l, j + 1, 1);
+			value = LuaToString(l, -1);
+			lua_pop(l, 1);
+			const int resId = GetResourceIdByName(l, value);
+			lua_rawgeti(l, j + 1, 2);
+			um->Modifier.Storing[resId] = LuaToNumber(l, -1);
+			lua_pop(l, 1);
 		} else if (!strcmp(key, "allow-unit")) {
 			lua_rawgeti(l, j + 1, 2);
 			value = LuaToString(l, -1);
@@ -582,6 +597,7 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
 			// upgrade costs :)
 			for (unsigned int j = 0; j < MaxCosts; ++j) {
 				UnitTypes[z]->Stats[pn].Costs[j] += um->Modifier.Costs[j];
+				UnitTypes[z]->Stats[pn].Storing[j] += um->Modifier.Storing[j];
 			}
 
 			int varModified = 0;