diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7231ec6a8..2e38ae6db 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -90,6 +90,7 @@ set(animation_SRCS
 	src/animation/animation_goto.cpp
 	src/animation/animation_ifvar.cpp
 	src/animation/animation_label.cpp
+	src/animation/animation_luacallback.cpp
 	src/animation/animation_move.cpp
 	src/animation/animation_randomgoto.cpp
 	src/animation/animation_randomrotate.cpp
@@ -475,6 +476,7 @@ set(stratagus_animation_HDRS
 	src/include/animation/animation_goto.h
 	src/include/animation/animation_ifvar.h
 	src/include/animation/animation_label.h
+	src/include/animation/animation_luacallback.h
 	src/include/animation/animation_move.h
 	src/include/animation/animation_randomgoto.h
 	src/include/animation/animation_randomrotate.h
diff --git a/src/action/action_built.cpp b/src/action/action_built.cpp
index eaf101774..465daaa9d 100644
--- a/src/action/action_built.cpp
+++ b/src/action/action_built.cpp
@@ -346,7 +346,7 @@ void COrder_Built::Progress(CUnit &unit, int amount)
 	Boost(unit, amount, HP_INDEX);
 	Boost(unit, amount, SHIELD_INDEX);
 
-	this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
+	this->ProgressCounter += std::max(1, amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR);
 	UpdateConstructionFrame(unit);
 }
 
@@ -354,7 +354,7 @@ void COrder_Built::ProgressHp(CUnit &unit, int amount)
 {
 	Boost(unit, amount, HP_INDEX);
 
-	this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
+	this->ProgressCounter += std::max(1, amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR);
 	UpdateConstructionFrame(unit);
 }
 
@@ -365,7 +365,7 @@ void COrder_Built::Boost(CUnit &building, int amount, int varIndex) const
 
 	const int costs = building.Stats->Costs[TimeCost] * 600;
 	const int progress = this->ProgressCounter;
-	const int newProgress = progress + amount * building.Player->SpeedBuild / SPEEDUP_FACTOR;
+	const int newProgress = progress + std::max(1, amount * building.Player->SpeedBuild / SPEEDUP_FACTOR);
 	const int maxValue = building.Variable[varIndex].Max;
 
 	int &currentValue = building.Variable[varIndex].Value;
diff --git a/src/action/action_follow.cpp b/src/action/action_follow.cpp
index adc9227cf..9614bd342 100644
--- a/src/action/action_follow.cpp
+++ b/src/action/action_follow.cpp
@@ -38,6 +38,7 @@
 #include "action/action_follow.h"
 
 #include "iolib.h"
+#include "missile.h"
 #include "pathfinder.h"
 #include "script.h"
 #include "ui.h"
@@ -168,6 +169,12 @@ enum {
 			return ;
 		}
 
+		// Don't follow after immobile units
+		if (goal && goal->CanMove() == false) {
+			this->Finished = true;
+			return;
+		}
+
 		if (goal->tilePos == this->goalPos) {
 			// Move to the next order
 			if (unit.Orders.size() > 1) {
@@ -204,42 +211,51 @@ enum {
 			// Handle Teleporter Units
 			// FIXME: BAD HACK
 			// goal shouldn't be busy and portal should be alive
-			if (goal->Type->Teleporter && goal->IsIdle() && goal->Goal
-				&& goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) {
-					// Teleport the unit
-					unit.Remove(NULL);
-					unit.tilePos = goal->Goal->tilePos;
-					DropOutOnSide(unit, unit.Direction, NULL);
-#if 0
-					// FIXME: SoundForName() should be called once
-					PlayGameSound(SoundForName("invisibility"), MaxSampleVolume);
-					// FIXME: MissileTypeByIdent() should be called once
-					MakeMissile(MissileTypeByIdent("missile-normal-spell"),
-								unit.GetMapPixelPosCenter(),
-								unit.GetMapPixelPosCenter());
-#endif
-					// FIXME: we must check if the units supports the new order.
-					CUnit &dest = *goal->Goal;
+			if (goal->Type->Teleporter && goal->Goal && goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) {
+				if (!goal->IsIdle()) { // wait
+					unit.Wait = 10;
+					return;
+				}
+				// Check if we have enough mana
+				if (goal->Goal->Type->TeleportCost > goal->Variable[MANA_INDEX].Value) {
+					this->Finished = true;
+					return;
+				} else {
+					goal->Variable[MANA_INDEX].Value -= goal->Goal->Type->TeleportCost;
+				}
+				// Everything is OK, now teleport the unit
+				unit.Remove(NULL);
+				if (goal->Type->TeleportEffect.Missile) {
+					MakeMissile(*goal->Type->TeleportEffect.Missile, unit.GetMapPixelPosCenter(), unit.GetMapPixelPosCenter());
+				}
+				unit.tilePos = goal->Goal->tilePos;
+				DropOutOnSide(unit, unit.Direction, NULL);
 
-					if (dest.NewOrder == NULL
-						|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->Harvester)
-						|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
-						|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
-						this->Finished = true;
-						return ;
-					} else {
-						if (dest.NewOrder->HasGoal()) {
-							if (dest.NewOrder->GetGoal()->Destroyed) {
-								delete dest.NewOrder;
-								dest.NewOrder = NULL;
-								this->Finished = true;
-								return ;
-							}
+				// FIXME: we must check if the units supports the new order.
+				CUnit &dest = *goal->Goal;
+				if (dest.Type->TeleportEffect.Missile) {
+					MakeMissile(*dest.Type->TeleportEffect.Missile, unit.GetMapPixelPosCenter(), unit.GetMapPixelPosCenter());
+				}
+
+				if (dest.NewOrder == NULL
+					|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->Harvester)
+					|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
+					|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
+					this->Finished = true;
+					return ;
+				} else {
+					if (dest.NewOrder->HasGoal()) {
+						if (dest.NewOrder->GetGoal()->Destroyed) {
+							delete dest.NewOrder;
+							dest.NewOrder = NULL;
+							this->Finished = true;
+							return ;
 						}
 						unit.Orders.insert(unit.Orders.begin() + 1, dest.NewOrder->Clone());
 						this->Finished = true;
 						return ;
 					}
+				}
 			}
 			this->goalPos = goal->tilePos;
 			this->State = State_TargetReached;
diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp
index 48561c49a..4c79cbfc3 100644
--- a/src/action/action_research.cpp
+++ b/src/action/action_research.cpp
@@ -131,7 +131,7 @@
 	}
 #endif
 	CPlayer &player = *unit.Player;
-	player.UpgradeTimers.Upgrades[upgrade.ID] += player.SpeedResearch / SPEEDUP_FACTOR;
+	player.UpgradeTimers.Upgrades[upgrade.ID] += std::max(1, player.SpeedResearch / SPEEDUP_FACTOR);
 	if (player.UpgradeTimers.Upgrades[upgrade.ID] >= upgrade.Costs[TimeCost]) {
 		player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), type.Name.c_str());
 		if (&player == ThisPlayer) {
diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp
index 2faa19a5c..b0b221c63 100644
--- a/src/action/action_resource.cpp
+++ b/src/action/action_resource.cpp
@@ -470,7 +470,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
 #endif
 		UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
 		if (resinfo.WaitAtResource) {
-			this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] * SPEEDUP_FACTOR;
+			this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
 		} else {
 			this->TimeToHarvest = 1;
 		}
@@ -538,7 +538,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
 	goal->Resource.Active++;
 
 	if (resinfo.WaitAtResource) {
-		this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] * SPEEDUP_FACTOR;
+		this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
 	} else {
 		this->TimeToHarvest = 1;
 	}
@@ -671,7 +671,7 @@ int COrder_Resource::GatherResource(CUnit &unit)
 	while (!this->DoneHarvesting && this->TimeToHarvest < 0) {
 		//FIXME: rb - how should it look for WaitAtResource == 0
 		if (resinfo.WaitAtResource) {
-			this->TimeToHarvest += resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId];
+			this->TimeToHarvest += std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
 		} else {
 			this->TimeToHarvest += 1;
 		}
@@ -954,7 +954,7 @@ int COrder_Resource::MoveToDepot(CUnit &unit)
 	unit.CurrentResource = 0;
 
 	if (unit.Wait) {
-		unit.Wait /= unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR;
+		unit.Wait /= std::max(1, unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR);
 		if (unit.Wait) {
 			unit.Wait--;
 		}
@@ -1103,6 +1103,9 @@ bool COrder_Resource::ActionResourceInit(CUnit &unit)
 		unit.DeAssignWorkerFromMine(*mine);
 		this->Resource.Mine = NULL;
 	}
+	if (goal && goal->IsAlive() == false) {
+		return false;
+	}
 	if (goal && goal->CurrentAction() != UnitActionBuilt) {
 		unit.AssignWorkerToMine(*goal);
 		this->Resource.Mine = goal;
@@ -1133,6 +1136,7 @@ void COrder_Resource::Execute(CUnit &unit)
 	// Let's start mining.
 	if (this->State == SUB_START_RESOURCE) {
 		if (ActionResourceInit(unit) == false) {
+			ResourceGiveUp(unit);
 			return;
 		}
 	}
diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp
index 28e72a918..2b1484097 100644
--- a/src/action/action_spellcast.cpp
+++ b/src/action/action_spellcast.cpp
@@ -333,7 +333,7 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
 			}
 			// FALL THROUGH
 		case 2:                         // Cast spell on the target.
-			if (!spell.IsCasterOnly()) {
+			if (!spell.IsCasterOnly() || spell.ForceUseAnimation) {
 				AnimateActionSpellCast(unit, *this);
 				if (unit.Anim.Unbreakable) {
 					return ;
diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp
index 2b388b26c..c60169f33 100644
--- a/src/action/action_train.cpp
+++ b/src/action/action_train.cpp
@@ -183,7 +183,7 @@ static void AnimateActionTrain(CUnit &unit)
 	CPlayer &player = *unit.Player;
 	const CUnitType &nType = *this->Type;
 	const int cost = nType.Stats[player.Index].Costs[TimeCost];
-	this->Ticks += player.SpeedTrain / SPEEDUP_FACTOR;
+	this->Ticks += std::max(1, player.SpeedTrain / SPEEDUP_FACTOR);
 
 	if (this->Ticks < cost) {
 		unit.Wait = CYCLES_PER_SECOND / 6;
diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp
index 4a12e9511..39cf2b207 100644
--- a/src/action/action_upgradeto.cpp
+++ b/src/action/action_upgradeto.cpp
@@ -260,7 +260,7 @@ static void AnimateActionUpgradeTo(CUnit &unit)
 	const CUnitType &newtype = *this->Type;
 	const CUnitStats &newstats = newtype.Stats[player.Index];
 
-	this->Ticks += player.SpeedUpgrade / SPEEDUP_FACTOR;
+	this->Ticks += std::max(1, player.SpeedUpgrade / SPEEDUP_FACTOR);
 	if (this->Ticks < newstats.Costs[TimeCost]) {
 		unit.Wait = CYCLES_PER_SECOND / 6;
 		return ;
diff --git a/src/action/command.cpp b/src/action/command.cpp
index db456cdb3..97c963731 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -36,7 +36,10 @@
 #include "stratagus.h"
 
 #include "actions.h"
+#include "action/action_built.h"
+#include "action/action_research.h"
 #include "action/action_train.h"
+#include "action/action_upgradeto.h"
 #include "commands.h"
 #include "map.h"
 #include "pathfinder.h"
@@ -63,8 +66,19 @@ static void ReleaseOrders(CUnit &unit)
 	Assert(unit.Orders.empty() == false);
 
 	// Order 0 must be stopped in the action loop.
-	for (size_t i = 1; i != unit.Orders.size(); ++i) {
-		delete unit.Orders[i];
+	for (size_t i = 0; i != unit.Orders.size(); ++i) {
+		if (unit.Orders[i]->Action == UnitActionBuilt) {
+			(dynamic_cast<COrder_Built *>(unit.Orders[i]))->Cancel(unit);
+		} else if (unit.Orders[i]->Action == UnitActionResearch) {
+			(dynamic_cast<COrder_Research *>(unit.Orders[i]))->Cancel(unit);
+		} else if (unit.Orders[i]->Action == UnitActionTrain) {
+			(dynamic_cast<COrder_Train *>(unit.Orders[i]))->Cancel(unit);
+		} else if (unit.Orders[i]->Action == UnitActionUpgradeTo) {
+			(dynamic_cast<COrder_UpgradeTo *>(unit.Orders[i]))->Cancel(unit);
+		}
+		if (i > 0) {
+			delete unit.Orders[i];
+		}
 	}
 	unit.Orders.resize(1);
 	unit.Orders[0]->Finished = true;
diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp
index 7e6508d2c..f137fa812 100644
--- a/src/ai/ai.cpp
+++ b/src/ai/ai.cpp
@@ -670,7 +670,7 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender)
 		return;
 	}
 	// Summoned unit, don't help
-	if (defender.GroupId == -1) {
+	if (defender.Summoned) {
 		return;
 	}
 
diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp
index 71888d271..6cd69d8ab 100644
--- a/src/ai/ai_force.cpp
+++ b/src/ai/ai_force.cpp
@@ -448,14 +448,14 @@ void AiForce::ReturnToHome()
 
 AiForceManager::AiForceManager()
 {
-	forces.resize(3);
+	forces.resize(AI_MAX_FORCES);
 	memset(script, -1, AI_MAX_FORCES * sizeof(char));
 }
 
-unsigned int AiForceManager::FindFreeForce(AiForceRole role)
+unsigned int AiForceManager::FindFreeForce(AiForceRole role, int begin)
 {
 	/* find free force */
-	unsigned int f = 0;
+	unsigned int f = begin;
 	while (f < forces.size() && (forces[f].State > AiForceAttackingState_Free)) {
 		++f;
 	};
@@ -467,6 +467,30 @@ unsigned int AiForceManager::FindFreeForce(AiForceRole role)
 	return f;
 }
 
+/**
+**  Find unit in force
+**
+**  @param    unit  Unit to search for.
+**
+**  @return   Force number, or -1 if not found
+*/
+
+int AiForceManager::GetForce(const CUnit &unit)
+{
+	for (unsigned int i = 0; i < forces.size(); ++i) {
+		AiForce &force = forces[i];
+		
+		for (unsigned int j = 0; j < force.Units.size(); ++j) {
+			CUnit &aiunit = *force.Units[j];
+
+			if (UnitNumber(unit) == UnitNumber(aiunit)) {
+				return i;
+			}
+		}
+	}
+	return -1;
+}
+
 /**
 **  Cleanup units in forces.
 */
@@ -591,7 +615,7 @@ void AiAttackWithForceAt(unsigned int force, int x, int y)
 {
 	const Vec2i pos(x, y);
 
-	if (!(force < AI_MAX_FORCES)) {
+	if (!(force < AI_MAX_FORCE_INTERNAL)) {
 		DebugPrint("Force out of range: %d" _C_ force);
 		return ;
 	}
@@ -611,7 +635,7 @@ void AiAttackWithForceAt(unsigned int force, int x, int y)
 */
 void AiAttackWithForce(unsigned int force)
 {
-	if (!(force < AI_MAX_FORCES)) {
+	if (!(force < AI_MAX_FORCE_INTERNAL)) {
 		DebugPrint("Force out of range: %d" _C_ force);
 		return ;
 	}
@@ -620,7 +644,7 @@ void AiAttackWithForce(unsigned int force)
 	// the first force, so we can reuse it
 	if (!AiPlayer->Force[force].Defending) {
 		unsigned int top;
-		unsigned int f = AiPlayer->Force.FindFreeForce();
+		unsigned int f = AiPlayer->Force.FindFreeForce(AiForceRoleDefault, AI_MAX_FORCE_INTERNAL);
 		AiPlayer->Force[f].Reset();
 
 		AiPlayer->Force[f].Role = AiPlayer->Force[force].Role;
@@ -658,7 +682,7 @@ void AiAttackWithForces(int *forces)
 	const Vec2i invalidPos(-1, -1);
 	bool found = false;
 	unsigned int top;
-	unsigned int f = AiPlayer->Force.FindFreeForce();
+	unsigned int f = AiPlayer->Force.FindFreeForce(AiForceRoleDefault, AI_MAX_FORCE_INTERNAL);
 
 	AiPlayer->Force[f].Reset();
 
diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h
index 396b29376..ba8e9474f 100644
--- a/src/ai/ai_local.h
+++ b/src/ai/ai_local.h
@@ -159,12 +159,12 @@ public:
 
 	void ReturnToHome();
 	bool NewRallyPoint(const Vec2i &startPos, Vec2i *resultPos);
+	void Insert(CUnit &unit);
 
 private:
 	void CountTypes(unsigned int *counter, const size_t len);
 	bool IsBelongsTo(const CUnitType &type);
-	void Insert(CUnit &unit);
-
+	
 	void Update();
 
 	static void InternalRemoveUnit(CUnit *unit);
@@ -186,7 +186,8 @@ public:
 };
 
 // forces
-#define AI_MAX_FORCES 50                    /// How many forces are supported
+#define AI_MAX_FORCES 50                           /// How many forces are supported
+#define AI_MAX_FORCE_INTERNAL (AI_MAX_FORCES / 2)  /// The forces after AI_MAX_FORCE_INTERNAL are for internal use
 
 /**
 **  AI force manager.
@@ -219,10 +220,11 @@ public:
 		return script[index];
 	}
 
+	int GetForce(const CUnit &unit);
 	void RemoveDeadUnit();
 	bool Assign(CUnit &unit);
 	void Update();
-	unsigned int FindFreeForce(AiForceRole role = AiForceRoleDefault);
+	unsigned int FindFreeForce(AiForceRole role = AiForceRoleDefault, int begin = 0);
 	void CheckUnits(int *counter);
 private:
 	std::vector<AiForce> forces;
diff --git a/src/ai/ai_plan.cpp b/src/ai/ai_plan.cpp
index dc881858c..e76818e55 100644
--- a/src/ai/ai_plan.cpp
+++ b/src/ai/ai_plan.cpp
@@ -116,14 +116,14 @@ class WallFinder
 {
 public:
 	WallFinder(const CUnit &unit, int maxDist, Vec2i *resultPos) :
-		unit(unit),
+//		unit(unit),
 		maxDist(maxDist),
 		movemask(unit.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)),
 		resultPos(resultPos)
 	{}
 	VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
 private:
-	const CUnit &unit;
+//	const CUnit &unit;
 	int maxDist;
 	int movemask;
 	Vec2i *resultPos;
@@ -213,12 +213,12 @@ class ReachableTerrainMarker
 {
 public:
 	ReachableTerrainMarker(const CUnit &unit) :
-		unit(unit),
+//		unit(unit),
 		movemask(unit.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit))
 	{}
 	VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
 private:
-	const CUnit &unit;
+//	const CUnit &unit;
 	int movemask;
 };
 
diff --git a/src/ai/script_ai.cpp b/src/ai/script_ai.cpp
index b6e07d8b9..313eb1d21 100644
--- a/src/ai/script_ai.cpp
+++ b/src/ai/script_ai.cpp
@@ -692,7 +692,7 @@ static int CclAiForce(lua_State *l)
 		resetForce = LuaToBoolean(l, 3);
 	}
 	int force = LuaToNumber(l, 1);
-	if (force < 0 || force >= AI_MAX_FORCES) {
+	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 		LuaError(l, "Force out of range: %d" _C_ force);
 	}
 	AiForce &aiforce = AiPlayer->Force[AiPlayer->Force.getScriptForce(force)];
@@ -762,7 +762,7 @@ static int CclAiForceRole(lua_State *l)
 {
 	LuaCheckArgs(l, 2);
 	int force = LuaToNumber(l, 1);
-	if (force < 0 || force >= AI_MAX_FORCES) {
+	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 		LuaError(l, "Force %i out of range" _C_ force);
 	}
 
@@ -789,7 +789,7 @@ static int CclAiCheckForce(lua_State *l)
 {
 	LuaCheckArgs(l, 1);
 	int force = LuaToNumber(l, 1);
-	if (force < 0 || force >= AI_MAX_FORCES) {
+	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 		lua_pushfstring(l, "Force out of range: %d", force);
 	}
 	if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@@ -809,7 +809,7 @@ static int CclAiWaitForce(lua_State *l)
 {
 	LuaCheckArgs(l, 1);
 	int force = LuaToNumber(l, 1);
-	if (force < 0 || force >= AI_MAX_FORCES) {
+	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 		lua_pushfstring(l, "Force out of range: %d", force);
 	}
 	if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@@ -834,7 +834,7 @@ static int CclAiAttackWithForce(lua_State *l)
 {
 	LuaCheckArgs(l, 1);
 	int force = LuaToNumber(l, 1);
-	if (force < 0 || force >= AI_MAX_FORCES) {
+	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 		LuaError(l, "Force out of range: %d" _C_ force);
 	}
 	AiAttackWithForce(AiPlayer->Force.getScriptForce(force));
@@ -857,7 +857,7 @@ static int CclAiWaitForces(lua_State *l)
 	for (int i = 0; i < args; ++i) {
 		const int force = LuaToNumber(l, 1, i + 1);
 
-		if (force < 0 || force >= AI_MAX_FORCES) {
+		if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 			lua_pushfstring(l, "Force out of range: %d", force);
 		}
 		if (!AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@@ -876,7 +876,7 @@ static int CclAiWaitForces(lua_State *l)
 */
 static int CclAiAttackWithForces(lua_State *l)
 {
-	int Forces[AI_MAX_FORCES + 1];
+	int Forces[AI_MAX_FORCE_INTERNAL + 1];
 
 	LuaCheckArgs(l, 1);
 	if (!lua_istable(l, 1)) {
@@ -886,7 +886,7 @@ static int CclAiAttackWithForces(lua_State *l)
 	for (int i = 0; i < args; ++i) {
 		const int force = LuaToNumber(l, 1, i + 1);
 
-		if (force < 0 || force >= AI_MAX_FORCES) {
+		if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
 			lua_pushfstring(l, "Force out of range: %d", force);
 		}
 		Forces[i] = AiPlayer->Force.getScriptForce(force);
diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp
index fcbcad9c5..5e6175002 100644
--- a/src/animation/animation.cpp
+++ b/src/animation/animation.cpp
@@ -46,6 +46,7 @@
 #include "animation/animation_goto.h"
 #include "animation/animation_ifvar.h"
 #include "animation/animation_label.h"
+#include "animation/animation_luacallback.h"
 #include "animation/animation_move.h"
 #include "animation/animation_randomgoto.h"
 #include "animation/animation_randomrotate.h"
@@ -133,17 +134,17 @@ static int ParseAnimPlayer(const CUnit &unit, const char *parseint)
 **  @return  The parsed value.
 */
 
-int ParseAnimInt(const CUnit *unit, const char *parseint)
+int ParseAnimInt(const CUnit &unit, const char *parseint)
 {
 	char s[100];
-	const CUnit *goal = unit;
+	const CUnit *goal = &unit;
 
 	strcpy(s, parseint);
 	char *cur = &s[2];
-	if ((s[0] == 'v' || s[0] == 't') && unit != NULL) { //unit variable detected
+	if (s[0] == 'v' || s[0] == 't') { //unit variable detected
 		if (s[0] == 't') {
-			if (unit->CurrentOrder()->HasGoal()) {
-				goal = unit->CurrentOrder()->GetGoal();
+			if (unit.CurrentOrder()->HasGoal()) {
+				goal = unit.CurrentOrder()->GetGoal();
 			} else {
 				return 0;
 			}
@@ -151,7 +152,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 		char *next = strchr(cur, '.');
 		if (next == NULL) {
 			fprintf(stderr, "Need also specify the variable '%s' tag \n", cur);
-			Exit(1);
+			ExitFatal(1);
 		} else {
 			*next = '\0';
 		}
@@ -163,7 +164,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 				return goal->Resource.Active;
 			}
 			fprintf(stderr, "Bad variable name '%s'\n", cur);
-			Exit(1);
+			ExitFatal(1);
 		}
 		if (!strcmp(next + 1, "Value")) {
 			return goal->Variable[index].Value;
@@ -177,10 +178,10 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 			return goal->Variable[index].Value * 100 / goal->Variable[index].Max;
 		}
 		return 0;
-	} else if ((s[0] == 'b' || s[0] == 'g') && unit != NULL) { //unit bool flag detected
+	} else if (s[0] == 'b' || s[0] == 'g') { //unit bool flag detected
 		if (s[0] == 'g') {
-			if (unit->CurrentOrder()->HasGoal()) {
-				goal = unit->CurrentOrder()->GetGoal();
+			if (unit.CurrentOrder()->HasGoal()) {
+				goal = unit.CurrentOrder()->GetGoal();
 			} else {
 				return 0;
 			}
@@ -188,11 +189,10 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 		const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags
 		if (index == -1) {
 			fprintf(stderr, "Bad bool-flag name '%s'\n", cur);
-			Exit(1);
-			return 0;
+			ExitFatal(1);
 		}
 		return goal->Type->BoolFlag[index].value;
-	} else if ((s[0] == 's') && unit != NULL) { //spell type detected
+	} else if (s[0] == 's') { //spell type detected
 		Assert(goal->CurrentAction() == UnitActionSpellCast);
 		const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
 		const SpellType &spell = order.GetSpell();
@@ -200,11 +200,11 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 			return 1;
 		}
 		return 0;
-	} else if (s[0] == 'p' && unit != NULL) { //player variable detected
+	} else if (s[0] == 'p') { //player variable detected
 		char *next = strchr(cur, '.');
 		if (next == NULL) {
 			fprintf(stderr, "Need also specify the %s player's property\n", cur);
-			Exit(1);
+			ExitFatal(1);
 		} else {
 			*next = '\0';
 		}
@@ -212,7 +212,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 		if (arg != NULL) {
 			*arg = '\0';
 		}
-		return GetPlayerData(ParseAnimPlayer(*unit, cur), next + 1, arg + 1);
+		return GetPlayerData(ParseAnimPlayer(unit, cur), next + 1, arg + 1);
 	} else if (s[0] == 'r') { //random value
 		char *next = strchr(cur, '.');
 		if (next == NULL) {
@@ -223,12 +223,72 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
 			return min + SyncRand(atoi(next + 1) - min + 1);
 		}
 	} else if (s[0] == 'l') { //player number
-		return ParseAnimPlayer(*unit, cur);
+		return ParseAnimPlayer(unit, cur);
 
 	}
 	return atoi(parseint);
 }
 
+/**
+**  Parse flags list in animation frame.
+**
+**  @param unit       Unit of the animation.
+**  @param parseflag  Flag list to parse.
+**
+**  @return The parsed value.
+*/
+int ParseAnimFlags(const CUnit &unit, const char *parseflag)
+{
+	char s[100];
+	int flags = 0;
+
+	strcpy(s, parseflag);
+	char *cur = s;
+	char *next = s;
+	while (next && *next) {
+		next = strchr(cur, '.');
+		if (next) {
+			*next = '\0';
+			++next;
+		}
+		if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
+			if (!strcmp(cur, "none")) {
+				flags = SM_None;
+				return flags;
+			} else if (!strcmp(cur, "damage")) {
+				flags |= SM_Damage;
+			} else if (!strcmp(cur, "totarget")) {
+				flags |= SM_ToTarget;
+			} else if (!strcmp(cur, "pixel")) {
+				flags |= SM_Pixel;
+			} else if (!strcmp(cur, "reltarget")) {
+				flags |= SM_RelTarget;
+			} else if (!strcmp(cur, "ranged")) {
+				flags |= SM_Ranged;
+			}  else if (!strcmp(cur, "setdirection")) {
+				flags |= SM_SetDirection;
+			} else {
+				fprintf(stderr, "Unknown animation flag: %s\n", cur);
+				ExitFatal(1);
+			}
+		} else if (unit.Anim.Anim->Type == AnimationSpawnUnit) {
+			if (!strcmp(cur, "none")) {
+				flags = SU_None;
+				return flags;
+			} else if (!strcmp(cur, "summoned")) {
+				flags |= SU_Summoned;
+			} else if (!strcmp(cur, "jointoai")) {
+				flags |= SU_JoinToAIForce;
+			} else {
+				fprintf(stderr, "Unknown animation flag: %s\n", cur);
+				ExitFatal(1);
+			}
+		}
+		cur = next;
+	}
+	return flags;
+}
+
 
 /**
 **  Show unit animation.
@@ -479,10 +539,12 @@ static CAnimation *ParseAnimationFrame(lua_State *l, const char *str)
 		anim = new CAnimation_Goto;
 	} else if (op1 == "random-goto") {
 		anim = new CAnimation_RandomGoto;
+	} else if (op1 == "lua-callback") {
+		anim = new CAnimation_LuaCallback;
 	} else {
 		LuaError(l, "Unknown animation: %s" _C_ op1.c_str());
 	}
-	anim->Init(extraArg.c_str());
+	anim->Init(extraArg.c_str(), l);
 	return anim;
 }
 
diff --git a/src/animation/animation_attack.cpp b/src/animation/animation_attack.cpp
index a777ea5aa..bcab1855a 100644
--- a/src/animation/animation_attack.cpp
+++ b/src/animation/animation_attack.cpp
@@ -47,7 +47,7 @@
 }
 
 
-/* virtual */ void CAnimation_Attack::Init(const char *s)
+/* virtual */ void CAnimation_Attack::Init(const char *s, lua_State *)
 {
 }
 
diff --git a/src/animation/animation_die.cpp b/src/animation/animation_die.cpp
index 79515fdc5..2cdfd0cbc 100644
--- a/src/animation/animation_die.cpp
+++ b/src/animation/animation_die.cpp
@@ -54,7 +54,7 @@
 	throw AnimationDie_Exception();
 }
 
-/* virtual */ void CAnimation_Die::Init(const char *s)
+/* virtual */ void CAnimation_Die::Init(const char *s, lua_State *)
 {
 	this->DeathType = s;
 }
diff --git a/src/animation/animation_exactframe.cpp b/src/animation/animation_exactframe.cpp
index 73992924a..f03bf2790 100644
--- a/src/animation/animation_exactframe.cpp
+++ b/src/animation/animation_exactframe.cpp
@@ -45,14 +45,18 @@
 	unit.Frame = ParseAnimInt(&unit);
 }
 
-/* virtual */ void CAnimation_ExactFrame::Init(const char *s)
+/* virtual */ void CAnimation_ExactFrame::Init(const char *s, lua_State *)
 {
 	this->frame = s;
 }
 
 int CAnimation_ExactFrame::ParseAnimInt(const CUnit *unit) const
 {
-	return ::ParseAnimInt(unit, this->frame.c_str());
+	if (unit == NULL) {
+		return atoi(this->frame.c_str());
+	} else {
+		return ::ParseAnimInt(*unit, this->frame.c_str());
+	}
 }
 
 //@}
diff --git a/src/animation/animation_frame.cpp b/src/animation/animation_frame.cpp
index cb512cfb0..57c94ef7e 100644
--- a/src/animation/animation_frame.cpp
+++ b/src/animation/animation_frame.cpp
@@ -46,14 +46,18 @@
 	UnitUpdateHeading(unit);
 }
 
-/* virtual */ void CAnimation_Frame::Init(const char *s)
+/* virtual */ void CAnimation_Frame::Init(const char *s, lua_State *)
 {
 	this->frame = s;
 }
 
 int CAnimation_Frame::ParseAnimInt(const CUnit *unit) const
 {
-	return ::ParseAnimInt(unit, this->frame.c_str());
+	if (unit == NULL) {
+		return atoi(this->frame.c_str());
+	} else {
+		return ::ParseAnimInt(*unit, this->frame.c_str());
+	}
 }
 
 //@}
diff --git a/src/animation/animation_goto.cpp b/src/animation/animation_goto.cpp
index 0f58bc17f..4216d6d3a 100644
--- a/src/animation/animation_goto.cpp
+++ b/src/animation/animation_goto.cpp
@@ -46,7 +46,7 @@
 	unit.Anim.Anim = this->gotoLabel;
 }
 
-/* virtual */ void CAnimation_Goto::Init(const char *s)
+/* virtual */ void CAnimation_Goto::Init(const char *s, lua_State *)
 {
 	FindLabelLater(&this->gotoLabel, s);
 }
diff --git a/src/animation/animation_ifvar.cpp b/src/animation/animation_ifvar.cpp
index 254c8b9c9..7eb6da399 100644
--- a/src/animation/animation_ifvar.cpp
+++ b/src/animation/animation_ifvar.cpp
@@ -61,8 +61,8 @@ static bool returnFalse(int, int) { return false; }
 {
 	Assert(unit.Anim.Anim == this);
 
-	const int lop = ParseAnimInt(&unit, this->leftVar.c_str());
-	const int rop = ParseAnimInt(&unit, this->rightVar.c_str());
+	const int lop = ParseAnimInt(unit, this->leftVar.c_str());
+	const int rop = ParseAnimInt(unit, this->rightVar.c_str());
 	const bool cond = this->binOpFunc(lop, rop);
 
 	if (cond) {
@@ -73,7 +73,7 @@ static bool returnFalse(int, int) { return false; }
 /*
 ** s = "leftOp Op rigthOp gotoLabel"
 */
-/* virtual */ void CAnimation_IfVar::Init(const char *s)
+/* virtual */ void CAnimation_IfVar::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
diff --git a/src/animation/animation_label.cpp b/src/animation/animation_label.cpp
index dfb7264ea..84bf7d371 100644
--- a/src/animation/animation_label.cpp
+++ b/src/animation/animation_label.cpp
@@ -44,7 +44,7 @@
 	Assert(unit.Anim.Anim == this);
 }
 
-/* virtual */ void CAnimation_Label::Init(const char *s)
+/* virtual */ void CAnimation_Label::Init(const char *s, lua_State *)
 {
 }
 
diff --git a/src/animation/animation_luacallback.cpp b/src/animation/animation_luacallback.cpp
new file mode 100644
index 000000000..055498b5c
--- /dev/null
+++ b/src/animation/animation_luacallback.cpp
@@ -0,0 +1,84 @@
+//       _________ __                 __
+//      /   _____//  |_____________ _/  |______     ____  __ __  ______
+//      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
+//      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
+//     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
+//             \/                  \/          \//_____/            \/
+//  ______________________                           ______________________
+//                        T H E   W A R   B E G I N S
+//         Stratagus - A free fantasy real time strategy game engine
+//
+/**@name animation_luacallback.cpp - The animation LuaCallback. */
+//
+//      (c) Copyright 2013 by cybermind
+//
+//      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; only version 2 of the License.
+//
+//      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., 59 Temple Place - Suite 330, Boston, MA
+//      02111-1307, USA.
+//
+
+//@{
+
+/*----------------------------------------------------------------------------
+--  Includes
+----------------------------------------------------------------------------*/
+
+#include "stratagus.h"
+
+#include "animation/animation_luacallback.h"
+
+#include "script.h"
+#include "unit.h"
+
+
+/* virtual */ void CAnimation_LuaCallback::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
+{
+	Assert(unit.Anim.Anim == this);
+	Assert(cb);
+
+	cb->pushPreamble();
+	for (std::vector<std::string>::const_iterator it = cbArgs.begin(); it != cbArgs.end(); ++it) {
+		const std::string str = *it;
+
+		const int arg = ParseAnimInt(unit, str.c_str());
+		cb->pushInteger(arg);
+	}
+	cb->run();
+}
+
+/*
+** s = "cbName cbArg1 [cbArgN ...]"
+*/
+/* virtual */ void CAnimation_LuaCallback::Init(const char *s, lua_State *l)
+{
+	const std::string str(s);
+	const size_t len = str.size();
+
+	size_t begin = 0;
+	size_t end = str.find(' ', begin);
+	this->cbName.assign(str, begin, end - begin);
+
+	lua_getglobal(l, cbName.c_str());
+	cb = new LuaCallback(l, -1);
+	lua_pop(l, 1);
+
+	for (size_t begin = std::min(len, str.find_first_not_of(' ', end));
+		begin != std::string::npos;) {
+			end = std::min(len, str.find(' ', begin));
+
+			this->cbArgs.push_back(str.substr(begin, end - begin));
+			begin = str.find_first_not_of(' ', end);
+	}
+}
+
+//@}
diff --git a/src/animation/animation_move.cpp b/src/animation/animation_move.cpp
index a8e7077f2..88d9c034f 100644
--- a/src/animation/animation_move.cpp
+++ b/src/animation/animation_move.cpp
@@ -44,10 +44,10 @@
 	Assert(unit.Anim.Anim == this);
 	Assert(!move);
 
-	move = ParseAnimInt(&unit, this->moveStr.c_str());
+	move = ParseAnimInt(unit, this->moveStr.c_str());
 }
 
-/* virtual */ void CAnimation_Move::Init(const char *s)
+/* virtual */ void CAnimation_Move::Init(const char *s, lua_State *)
 {
 	this->moveStr = s;
 }
diff --git a/src/animation/animation_randomgoto.cpp b/src/animation/animation_randomgoto.cpp
index 73e51565d..7467e1cb6 100644
--- a/src/animation/animation_randomgoto.cpp
+++ b/src/animation/animation_randomgoto.cpp
@@ -43,7 +43,7 @@
 {
 	Assert(unit.Anim.Anim == this);
 
-	if (SyncRand() % 100 < ParseAnimInt(&unit, this->randomStr.c_str())) {
+	if (SyncRand() % 100 < ParseAnimInt(unit, this->randomStr.c_str())) {
 		unit.Anim.Anim = this->gotoLabel;
 	}
 }
@@ -51,7 +51,7 @@
 /*
 **  s : "percent label"
 */
-/* virtual */ void CAnimation_RandomGoto::Init(const char *s)
+/* virtual */ void CAnimation_RandomGoto::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
diff --git a/src/animation/animation_randomrotate.cpp b/src/animation/animation_randomrotate.cpp
index 4b8efde4f..f6969c90f 100644
--- a/src/animation/animation_randomrotate.cpp
+++ b/src/animation/animation_randomrotate.cpp
@@ -45,13 +45,13 @@
 	Assert(unit.Anim.Anim == this);
 
 	if ((SyncRand() >> 8) & 1) {
-		UnitRotate(unit, -ParseAnimInt(&unit, this->rotateStr.c_str()));
+		UnitRotate(unit, -ParseAnimInt(unit, this->rotateStr.c_str()));
 	} else {
-		UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
+		UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
 	}
 }
 
-/* virtual */ void CAnimation_RandomRotate::Init(const char *s)
+/* virtual */ void CAnimation_RandomRotate::Init(const char *s, lua_State *)
 {
 	this->rotateStr = s;
 }
diff --git a/src/animation/animation_randomsound.cpp b/src/animation/animation_randomsound.cpp
index f7d4f0a5b..f28d658ef 100644
--- a/src/animation/animation_randomsound.cpp
+++ b/src/animation/animation_randomsound.cpp
@@ -54,7 +54,7 @@
 /*
 **  s = "Sound1 [SoundN ...]"
 */
-/* virtual */ void CAnimation_RandomSound::Init(const char *s)
+/* virtual */ void CAnimation_RandomSound::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
diff --git a/src/animation/animation_randomwait.cpp b/src/animation/animation_randomwait.cpp
index a0f705573..341a58c61 100644
--- a/src/animation/animation_randomwait.cpp
+++ b/src/animation/animation_randomwait.cpp
@@ -43,8 +43,8 @@
 {
 	Assert(unit.Anim.Anim == this);
 
-	const int arg1 = ParseAnimInt(&unit, this->minWait.c_str());
-	const int arg2 = ParseAnimInt(&unit, this->maxWait.c_str());
+	const int arg1 = ParseAnimInt(unit, this->minWait.c_str());
+	const int arg2 = ParseAnimInt(unit, this->maxWait.c_str());
 
 	unit.Anim.Wait = arg1 + SyncRand() % (arg2 - arg1 + 1);
 }
@@ -52,7 +52,7 @@
 /*
 ** s = "minWait MaxWait"
 */
-/* virtual */ void CAnimation_RandomWait::Init(const char *s)
+/* virtual */ void CAnimation_RandomWait::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
diff --git a/src/animation/animation_rotate.cpp b/src/animation/animation_rotate.cpp
index b46944840..b15eab44b 100644
--- a/src/animation/animation_rotate.cpp
+++ b/src/animation/animation_rotate.cpp
@@ -66,11 +66,11 @@ void UnitRotate(CUnit &unit, int rotate)
 		const Vec2i pos = target.tilePos + target.Type->GetHalfTileSize() - unit.tilePos;
 		UnitHeadingFromDeltaXY(unit, pos);
 	} else {
-		UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
+		UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
 	}
 }
 
-/* virtual */ void CAnimation_Rotate::Init(const char *s)
+/* virtual */ void CAnimation_Rotate::Init(const char *s, lua_State *)
 {
 	this->rotateStr = s;
 }
diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp
index 7d78a2f85..80981a7c4 100644
--- a/src/animation/animation_setplayervar.cpp
+++ b/src/animation/animation_setplayervar.cpp
@@ -42,13 +42,6 @@
 
 #include <stdio.h>
 
-//Modify types
-#define MOD_ADD 1
-#define MOD_SUB 2
-#define MOD_MUL 3
-#define MOD_DIV 4
-#define MOD_MOD 5
-
 /**
 **  Gets the player data.
 **
@@ -185,34 +178,46 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
 
 	const char *var = this->varStr.c_str();
 	const char *arg = this->argStr.c_str();
-	const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
-	int rop = ParseAnimInt(&unit, this->valueStr.c_str());
+	const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
+	int rop = ParseAnimInt(unit, this->valueStr.c_str());
 	int data = GetPlayerData(playerId, var, arg);
 
 	switch (this->mod) {
-		case MOD_ADD:
+		case modAdd:
 			data += rop;
 			break;
-		case MOD_SUB:
+		case modSub:
 			data -= rop;
 			break;
-		case MOD_MUL:
+		case modMul:
 			data *= rop;
 			break;
-		case MOD_DIV:
+		case modDiv:
 			if (!rop) {
 				fprintf(stderr, "Division by zero in AnimationSetPlayerVar\n");
 				Exit(1);
 			}
 			data /= rop;
 			break;
-		case MOD_MOD:
+		case modMod:
 			if (!rop) {
 				fprintf(stderr, "Division by zero in AnimationSetPlayerVar\n");
 				Exit(1);
 			}
 			data %= rop;
 			break;
+		case modAnd:
+			data &= rop;
+			break;
+		case modOr:
+			data |= rop;
+			break;
+		case modXor:
+			data ^= rop;
+			break;
+		case modNot:
+			data = !data;
+			break;
 		default:
 			data = rop;
 	}
@@ -223,7 +228,7 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
 /*
 **  s = "player var mod value [arg2]"
 */
-/* virtual */ void CAnimation_SetPlayerVar::Init(const char *s)
+/* virtual */ void CAnimation_SetPlayerVar::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
@@ -239,7 +244,29 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
 	begin = std::min(len, str.find_first_not_of(' ', end));
 	end = std::min(len, str.find(' ', begin));
 	const std::string modStr(str, begin, end - begin);
-	this->mod = atoi(modStr.c_str());
+	if (modStr == "=") {
+		this->mod = modSet;
+	} else if (modStr == "+=") {
+		this->mod = modAdd;
+	} else if (modStr == "-=") {
+		this->mod = modSub;
+	} else if (modStr == "*=") {
+		this->mod = modMul;
+	} else if (modStr == "/=") {
+		this->mod = modDiv;
+	} else if (modStr == "%=") {
+		this->mod = modMod;
+	} else if (modStr == "&=") {
+		this->mod = modAnd;
+	} else if (modStr == "|=") {
+		this->mod = modOr;
+	} else if (modStr == "^=") {
+		this->mod = modXor;
+	} else if (modStr == "!") {
+		this->mod = modNot;
+	} else {
+		this->mod = (SetVar_ModifyTypes)(atoi(modStr.c_str()));
+	}
 
 	begin = std::min(len, str.find_first_not_of(' ', end));
 	end = std::min(len, str.find(' ', begin));
diff --git a/src/animation/animation_setvar.cpp b/src/animation/animation_setvar.cpp
index e42fb6312..0f7957170 100644
--- a/src/animation/animation_setvar.cpp
+++ b/src/animation/animation_setvar.cpp
@@ -43,13 +43,6 @@
 
 #include <stdio.h>
 
-//Modify types
-#define MOD_ADD 1
-#define MOD_SUB 2
-#define MOD_MUL 3
-#define MOD_DIV 4
-#define MOD_MOD 5
-
 
 /* virtual */ void CAnimation_SetVar::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
 {
@@ -102,7 +95,7 @@
 		return;
 	}
 
-	const int rop = ParseAnimInt(&unit, this->valueStr.c_str());
+	const int rop = ParseAnimInt(unit, this->valueStr.c_str());
 	int value = 0;
 	if (!strcmp(next + 1, "Value")) {
 		value = goal->Variable[index].Value;
@@ -116,16 +109,16 @@
 		value = goal->Variable[index].Value * 100 / goal->Variable[index].Max;
 	}
 	switch (this->mod) {
-		case MOD_ADD:
+		case modAdd:
 			value += rop;
 			break;
-		case MOD_SUB:
+		case modSub:
 			value -= rop;
 			break;
-		case MOD_MUL:
+		case modMul:
 			value *= rop;
 			break;
-		case MOD_DIV:
+		case modDiv:
 			if (!rop) {
 				fprintf(stderr, "Division by zero in AnimationSetVar\n");
 				Exit(1);
@@ -133,7 +126,7 @@
 			}
 			value /= rop;
 			break;
-		case MOD_MOD:
+		case modMod:
 			if (!rop) {
 				fprintf(stderr, "Division by zero in AnimationSetVar\n");
 				Exit(1);
@@ -141,6 +134,18 @@
 			}
 			value %= rop;
 			break;
+		case modAnd:
+			value &= rop;
+			break;
+		case modOr:
+			value |= rop;
+			break;
+		case modXor:
+			value ^= rop;
+			break;
+		case modNot:
+			value = !value;
+			break;
 		default:
 			value = rop;
 	}
@@ -161,7 +166,7 @@
 /*
 **  s = "var mod value [unitSlot]"
 */
-/* virtual */ void CAnimation_SetVar::Init(const char *s)
+/* virtual */ void CAnimation_SetVar::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
@@ -173,7 +178,30 @@
 	begin = std::min(len, str.find_first_not_of(' ', end));
 	end = std::min(len, str.find(' ', begin));
 	const std::string modStr(str, begin, end - begin);
-	this->mod = atoi(modStr.c_str());
+
+	if (modStr == "=") {
+		this->mod = modSet;
+	} else if (modStr == "+=") {
+		this->mod = modAdd;
+	} else if (modStr == "-=") {
+		this->mod = modSub;
+	} else if (modStr == "*=") {
+		this->mod = modMul;
+	} else if (modStr == "/=") {
+		this->mod = modDiv;
+	} else if (modStr == "%=") {
+		this->mod = modMod;
+	} else if (modStr == "&=") {
+		this->mod = modAnd;
+	} else if (modStr == "|=") {
+		this->mod = modOr;
+	} else if (modStr == "^=") {
+		this->mod = modXor;
+	} else if (modStr == "!") {
+		this->mod = modNot;
+	} else {
+		this->mod = (SetVar_ModifyTypes)(atoi(modStr.c_str()));
+	}
 
 	begin = std::min(len, str.find_first_not_of(' ', end));
 	end = std::min(len, str.find(' ', begin));
diff --git a/src/animation/animation_sound.cpp b/src/animation/animation_sound.cpp
index 355f5e151..16efd5d97 100644
--- a/src/animation/animation_sound.cpp
+++ b/src/animation/animation_sound.cpp
@@ -49,7 +49,7 @@
 	}
 }
 
-/* virtual */ void CAnimation_Sound::Init(const char *s)
+/* virtual */ void CAnimation_Sound::Init(const char *s, lua_State *)
 {
 	this->sound.Name = s;
 }
diff --git a/src/animation/animation_spawnmissile.cpp b/src/animation/animation_spawnmissile.cpp
index ce001db9f..b3e22d49a 100644
--- a/src/animation/animation_spawnmissile.cpp
+++ b/src/animation/animation_spawnmissile.cpp
@@ -46,68 +46,17 @@
 #include "pathfinder.h"
 #include "unit.h"
 
-//SpawnMissile flags
-#define ANIM_SM_DAMAGE 1
-#define ANIM_SM_TOTARGET 2
-#define ANIM_SM_PIXEL 4
-#define ANIM_SM_RELTARGET 8
-#define ANIM_SM_RANGED 16
-#define ANIM_SM_SETDIRECTION 32
-
-/**
-**  Parse flags list in animation frame.
-**
-**  @param unit       Unit of the animation.
-**  @param parseflag  Flag list to parse.
-**
-**  @return The parsed value.
-*/
-static int ParseAnimFlags(CUnit &unit, const char *parseflag)
-{
-	char s[100];
-	int flags = 0;
-
-	strcpy(s, parseflag);
-	char *cur = s;
-	char *next = s;
-	while (next) {
-		next = strchr(cur, '.');
-		if (next) {
-			*next = '\0';
-			++next;
-		}
-		if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
-			if (!strcmp(cur, "damage")) {
-				flags |= ANIM_SM_DAMAGE;
-			} else if (!strcmp(cur, "totarget")) {
-				flags |= ANIM_SM_TOTARGET;
-			} else if (!strcmp(cur, "pixel")) {
-				flags |= ANIM_SM_PIXEL;
-			} else if (!strcmp(cur, "reltarget")) {
-				flags |= ANIM_SM_RELTARGET;
-			} else if (!strcmp(cur, "ranged")) {
-				flags |= ANIM_SM_RANGED;
-			}  else if (!strcmp(cur, "setdirection")) {
-				flags |= ANIM_SM_SETDIRECTION;
-			}
-		}
-		cur = next;
-	}
-	return flags;
-}
-
-
 /* virtual */ void CAnimation_SpawnMissile::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
 {
 	Assert(unit.Anim.Anim == this);
 
-	const int startx = ParseAnimInt(&unit, this->startXStr.c_str());
-	const int starty = ParseAnimInt(&unit, this->startYStr.c_str());
-	const int destx = ParseAnimInt(&unit, this->destXStr.c_str());
-	const int desty = ParseAnimInt(&unit, this->destYStr.c_str());
-	const int flags = ParseAnimFlags(unit, this->flagsStr.c_str());
-	const int offsetnum = ParseAnimInt(&unit, this->offsetNumStr.c_str());
-	const CUnit *goal = flags & ANIM_SM_RELTARGET ? unit.CurrentOrder()->GetGoal() : &unit;
+	const int startx = ParseAnimInt(unit, this->startXStr.c_str());
+	const int starty = ParseAnimInt(unit, this->startYStr.c_str());
+	const int destx = ParseAnimInt(unit, this->destXStr.c_str());
+	const int desty = ParseAnimInt(unit, this->destYStr.c_str());
+	const SpawnMissile_Flags flags = (SpawnMissile_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
+	const int offsetnum = ParseAnimInt(unit, this->offsetNumStr.c_str());
+	const CUnit *goal = flags & SM_RelTarget ? unit.CurrentOrder()->GetGoal() : &unit;
 	const int dir = ((goal->Direction + NextDirection / 2) & 0xFF) / NextDirection;
 	const PixelPos moff = goal->Type->MissileOffsets[dir][!offsetnum ? 0 : offsetnum - 1];
 	PixelPos start;
@@ -120,14 +69,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
 	if (!goal || goal->Destroyed) {
 		return;
 	}
-	if ((flags & ANIM_SM_PIXEL)) {
+	if ((flags & SM_Pixel)) {
 		start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + moff.x + startx;
 		start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + moff.y + starty;
 	} else {
 		start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2 + moff.x;
 		start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2 + moff.y;
 	}
-	if ((flags & ANIM_SM_TOTARGET)) {
+	if ((flags & SM_ToTarget)) {
 		CUnit *target = goal->CurrentOrder()->GetGoal();
 		if (!target || target->Destroyed) {
 			Assert(!mtype->AlwaysFire || mtype->Range);
@@ -143,14 +92,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
 				COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
 				dest = Map.TilePosToMapPixelPos_Center(order.GetGoalPos());
 			}
-			if (flags & ANIM_SM_PIXEL) {
+			if (flags & SM_Pixel) {
 				dest.x += destx;
 				dest.y += desty;
 			} else {
 				dest.x += destx * PixelTileSize.x;
 				dest.y += desty * PixelTileSize.y;
 			}
-		} else if (flags & ANIM_SM_PIXEL) {
+		} else if (flags & SM_Pixel) {
 			dest.x = target->GetMapPixelPosCenter().x + destx;
 			dest.y = target->GetMapPixelPosCenter().y + desty;
 		} else {
@@ -159,7 +108,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
 			dest += target->Type->GetPixelSize() / 2;
 		}
 	} else {
-		if ((flags & ANIM_SM_PIXEL)) {
+		if ((flags & SM_Pixel)) {
 			dest.x = goal->GetMapPixelPosCenter().x + destx;
 			dest.y = goal->GetMapPixelPosCenter().y + desty;
 		} else {
@@ -170,22 +119,22 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
 	}
 	Vec2i destTilePos = Map.MapPixelPosToTilePos(dest);
 	const int dist = goal->MapDistanceTo(destTilePos);
-	if ((flags & ANIM_SM_RANGED) && !(flags & ANIM_SM_PIXEL)
+	if ((flags & SM_Ranged) && !(flags & SM_Pixel)
 		&& dist > goal->Stats->Variables[ATTACKRANGE_INDEX].Max
 		&& dist < goal->Type->MinAttackRange) {
 	} else {
 		Missile *missile = MakeMissile(*mtype, start, dest);
-		if (flags & ANIM_SM_SETDIRECTION) {
+		if (flags & SM_SetDirection) {
 			PixelPos posd;
 			posd.x = Heading2X[goal->Direction / NextDirection];
 			posd.y = Heading2Y[goal->Direction / NextDirection];
 			missile->MissileNewHeadingFromXY(posd);
 		}
-		if (flags & ANIM_SM_DAMAGE) {
+		if (flags & SM_Damage) {
 			missile->SourceUnit = &unit;
 		}
 		CUnit *target = goal->CurrentOrder()->GetGoal();
-		if (flags & ANIM_SM_TOTARGET && target && target->IsAlive()) {
+		if (flags & SM_ToTarget && target && target->IsAlive()) {
 			missile->TargetUnit = target;
 		}
 	}
@@ -194,7 +143,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
 /*
 **  s = "missileType startX startY destX destY [flag1[.flagN]] [missileoffset]"
 */
-/* virtual */ void CAnimation_SpawnMissile::Init(const char *s)
+/* virtual */ void CAnimation_SpawnMissile::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
diff --git a/src/animation/animation_spawnunit.cpp b/src/animation/animation_spawnunit.cpp
index 107333fe4..9f69ba64b 100644
--- a/src/animation/animation_spawnunit.cpp
+++ b/src/animation/animation_spawnunit.cpp
@@ -37,6 +37,9 @@
 
 #include "animation/animation_spawnunit.h"
 
+#include "../ai/ai_local.h"
+
+#include "commands.h"
 #include "map.h"
 #include "unit.h"
 
@@ -104,10 +107,12 @@ found:
 {
 	Assert(unit.Anim.Anim == this);
 
-	const int offX = ParseAnimInt(&unit, this->offXStr.c_str());
-	const int offY = ParseAnimInt(&unit, this->offYStr.c_str());
-	const int range = ParseAnimInt(&unit, this->rangeStr.c_str());
-	const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
+	const int offX = ParseAnimInt(unit, this->offXStr.c_str());
+	const int offY = ParseAnimInt(unit, this->offYStr.c_str());
+	const int range = ParseAnimInt(unit, this->rangeStr.c_str());
+	const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
+	const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
+
 	CPlayer &player = Players[playerId];
 	const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY);
 	CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str());
@@ -120,6 +125,17 @@ found:
 		if (target != NULL) {
 			target->tilePos = resPos;
 			target->Place(resPos);
+			if (flags & SU_Summoned) {
+				target->Summoned = 1;
+			}
+			if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) {
+				int force = unit.Player->Ai->Force.GetForce(unit);
+				if (force != -1) {
+					unit.Player->Ai->Force[force].Insert(*target);
+					target->GroupId = unit.GroupId;
+					CommandDefend(*target, unit, FlushCommands);
+				}
+			}
 			//DropOutOnSide(*target, LookingW, NULL);
 		} else {
 			DebugPrint("Unable to allocate Unit");
@@ -128,9 +144,9 @@ found:
 }
 
 /*
-**  s = "unitType offX offY range player"
+**  s = "unitType offX offY range player [flags]"
 */
-/* virtual */ void CAnimation_SpawnUnit::Init(const char *s)
+/* virtual */ void CAnimation_SpawnUnit::Init(const char *s, lua_State *)
 {
 	const std::string str(s);
 	const size_t len = str.size();
@@ -154,6 +170,12 @@ found:
 	begin = std::min(len, str.find_first_not_of(' ', end));
 	end = std::min(len, str.find(' ', begin));
 	this->playerStr.assign(str, begin, end - begin);
+
+	begin = std::min(len, str.find_first_not_of(' ', end));
+	end = std::min(len, str.find(' ', begin));
+	if (begin != end) {
+		this->flagsStr.assign(str, begin, end - begin);
+	}
 }
 
 //@}
diff --git a/src/animation/animation_unbreakable.cpp b/src/animation/animation_unbreakable.cpp
index 020967c5b..73282d279 100644
--- a/src/animation/animation_unbreakable.cpp
+++ b/src/animation/animation_unbreakable.cpp
@@ -47,7 +47,7 @@
 	unit.Anim.Unbreakable = this->state;
 }
 
-/* virtual */ void CAnimation_Unbreakable::Init(const char *s)
+/* virtual */ void CAnimation_Unbreakable::Init(const char *s, lua_State *)
 {
 	if (!strcmp(s, "begin")) {
 		this->state = 1;
diff --git a/src/animation/animation_wait.cpp b/src/animation/animation_wait.cpp
index 85da3b2d6..f4609c592 100644
--- a/src/animation/animation_wait.cpp
+++ b/src/animation/animation_wait.cpp
@@ -42,7 +42,7 @@
 /* virtual */ void CAnimation_Wait::Action(CUnit &unit, int &/*move*/, int scale) const
 {
 	Assert(unit.Anim.Anim == this);
-	unit.Anim.Wait = ParseAnimInt(&unit, this->wait.c_str()) << scale >> 8;
+	unit.Anim.Wait = ParseAnimInt(unit, this->wait.c_str()) << scale >> 8;
 	if (unit.Variable[SLOW_INDEX].Value) { // unit is slowed down
 		unit.Anim.Wait <<= 1;
 	}
@@ -54,7 +54,7 @@
 	}
 }
 
-/* virtual */ void CAnimation_Wait::Init(const char *s)
+/* virtual */ void CAnimation_Wait::Init(const char *s, lua_State *)
 {
 	this->wait = s;
 }
diff --git a/src/include/animation.h b/src/include/animation.h
index d56577501..bab6db85c 100644
--- a/src/include/animation.h
+++ b/src/include/animation.h
@@ -72,7 +72,22 @@ enum AnimationType {
 	AnimationIfVar,
 	AnimationSetVar,
 	AnimationSetPlayerVar,
-	AnimationDie
+	AnimationDie,
+	AnimationLuaCallback
+};
+
+//Modify types
+enum SetVar_ModifyTypes {
+	modSet = 0,      /// Set value to this
+	modAdd,          /// Addition
+	modSub,          /// Subtraction 
+	modMul,          /// Multiplication
+	modDiv,          /// Division
+	modMod,          /// Modulo
+	modAnd,          /// Bitwise AND
+	modOr,           /// Bitwise OR
+	modXor,          /// Bitwise XOR
+	modNot,          /// Bitwise NOT
 };
 
 class CAnimation
@@ -83,7 +98,7 @@ public:
 	virtual ~CAnimation() {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const = 0;
-	virtual void Init(const char *s) {}
+	virtual void Init(const char *s, lua_State *l = NULL) {}
 
 	const AnimationType Type;
 	CAnimation *Next;
@@ -152,7 +167,8 @@ extern int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scal
 extern int UnitShowAnimation(CUnit &unit, const CAnimation *anim);
 
 
-extern int ParseAnimInt(const CUnit *unit, const char *parseint);
+extern int ParseAnimInt(const CUnit &unit, const char *parseint);
+extern int ParseAnimFlags(const CUnit &unit, const char *parseflag);
 
 extern void FindLabelLater(CAnimation **anim, const std::string &name);
 
diff --git a/src/include/animation/animation_attack.h b/src/include/animation/animation_attack.h
index 67b2374c6..42a49c9e5 100644
--- a/src/include/animation/animation_attack.h
+++ b/src/include/animation/animation_attack.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Attack() : CAnimation(AnimationAttack) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 };
 
diff --git a/src/include/animation/animation_die.h b/src/include/animation/animation_die.h
index 3bd359e99..2a8657338 100644
--- a/src/include/animation/animation_die.h
+++ b/src/include/animation/animation_die.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Die() : CAnimation(AnimationDie) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string DeathType;
diff --git a/src/include/animation/animation_exactframe.h b/src/include/animation/animation_exactframe.h
index 092db73ee..95444d88e 100644
--- a/src/include/animation/animation_exactframe.h
+++ b/src/include/animation/animation_exactframe.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_ExactFrame() : CAnimation(AnimationExactFrame) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 	int ParseAnimInt(const CUnit *unit) const;
 
diff --git a/src/include/animation/animation_frame.h b/src/include/animation/animation_frame.h
index bc89e4458..db44c7e67 100644
--- a/src/include/animation/animation_frame.h
+++ b/src/include/animation/animation_frame.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Frame() : CAnimation(AnimationFrame) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 	int ParseAnimInt(const CUnit *unit) const;
 private:
diff --git a/src/include/animation/animation_goto.h b/src/include/animation/animation_goto.h
index bb5e81a3f..2ee8d7ca1 100644
--- a/src/include/animation/animation_goto.h
+++ b/src/include/animation/animation_goto.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Goto() : CAnimation(AnimationGoto), gotoLabel(NULL) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	CAnimation *gotoLabel;
diff --git a/src/include/animation/animation_ifvar.h b/src/include/animation/animation_ifvar.h
index 73769ac79..a24225691 100644
--- a/src/include/animation/animation_ifvar.h
+++ b/src/include/animation/animation_ifvar.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_IfVar() : CAnimation(AnimationIfVar), binOpFunc(NULL), gotoLabel(NULL) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	typedef bool BinOpFunc(int lhs, int rhs);
diff --git a/src/include/animation/animation_label.h b/src/include/animation/animation_label.h
index e954a7baf..3363905a9 100644
--- a/src/include/animation/animation_label.h
+++ b/src/include/animation/animation_label.h
@@ -40,7 +40,7 @@ public:
 	CAnimation_Label() : CAnimation(AnimationLabel) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 };
 
 //@}
diff --git a/src/include/animation/animation_luacallback.h b/src/include/animation/animation_luacallback.h
new file mode 100644
index 000000000..92f0d7d59
--- /dev/null
+++ b/src/include/animation/animation_luacallback.h
@@ -0,0 +1,57 @@
+//       _________ __                 __
+//      /   _____//  |_____________ _/  |______     ____  __ __  ______
+//      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
+//      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
+//     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
+//             \/                  \/          \//_____/            \/
+//  ______________________                           ______________________
+//                        T H E   W A R   B E G I N S
+//         Stratagus - A free fantasy real time strategy game engine
+//
+/**@name animation_luacallback.h - The animation LuaCallback headerfile. */
+//
+//      (c) Copyright 2013 by cybermind
+//
+//      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; only version 2 of the License.
+//
+//      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., 59 Temple Place - Suite 330, Boston, MA
+//      02111-1307, USA.
+//
+
+#ifndef ANIMATION_LUACALLBACK_H
+#define ANIMATION_LUACALLBACK_H
+
+//@{
+
+#include <string>
+#include "animation.h"
+
+#include "luacallback.h"
+
+class CAnimation_LuaCallback : public CAnimation
+{
+public:
+	CAnimation_LuaCallback() : CAnimation(AnimationLuaCallback), cb(NULL) {}
+	~CAnimation_LuaCallback() { delete cb; }
+
+	virtual void Action(CUnit &unit, int &move, int scale) const;
+	virtual void Init(const char *s, lua_State *l);
+
+private:
+	LuaCallback *cb;
+	std::string cbName;
+	std::vector<std::string> cbArgs;
+};
+
+//@}
+
+#endif // ANIMATION_LUACALLBACK_H
diff --git a/src/include/animation/animation_move.h b/src/include/animation/animation_move.h
index 80cbe65e2..8d3efa2a0 100644
--- a/src/include/animation/animation_move.h
+++ b/src/include/animation/animation_move.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Move() : CAnimation(AnimationMove) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string moveStr;
diff --git a/src/include/animation/animation_randomgoto.h b/src/include/animation/animation_randomgoto.h
index dad4b2c86..1b47b845c 100644
--- a/src/include/animation/animation_randomgoto.h
+++ b/src/include/animation/animation_randomgoto.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_RandomGoto() : CAnimation(AnimationRandomGoto), gotoLabel(NULL) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string randomStr;
diff --git a/src/include/animation/animation_randomrotate.h b/src/include/animation/animation_randomrotate.h
index 777384f4e..77f36aefe 100644
--- a/src/include/animation/animation_randomrotate.h
+++ b/src/include/animation/animation_randomrotate.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_RandomRotate() : CAnimation(AnimationRandomRotate) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string rotateStr;
diff --git a/src/include/animation/animation_randomsound.h b/src/include/animation/animation_randomsound.h
index 75470c5e8..ce73ffbaf 100644
--- a/src/include/animation/animation_randomsound.h
+++ b/src/include/animation/animation_randomsound.h
@@ -43,7 +43,7 @@ public:
 	CAnimation_RandomSound() : CAnimation(AnimationRandomSound) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 	void MapSound();
 private:
diff --git a/src/include/animation/animation_randomwait.h b/src/include/animation/animation_randomwait.h
index 82c1b58a7..e8cfe6a7d 100644
--- a/src/include/animation/animation_randomwait.h
+++ b/src/include/animation/animation_randomwait.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_RandomWait() : CAnimation(AnimationRandomWait) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string minWait;
diff --git a/src/include/animation/animation_rotate.h b/src/include/animation/animation_rotate.h
index f0c99b35d..990023a4c 100644
--- a/src/include/animation/animation_rotate.h
+++ b/src/include/animation/animation_rotate.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Rotate() : CAnimation(AnimationRotate) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string rotateStr;
diff --git a/src/include/animation/animation_setplayervar.h b/src/include/animation/animation_setplayervar.h
index edb0604e8..bb24f37c4 100644
--- a/src/include/animation/animation_setplayervar.h
+++ b/src/include/animation/animation_setplayervar.h
@@ -41,10 +41,10 @@ public:
 	CAnimation_SetPlayerVar() : CAnimation(AnimationSetPlayerVar) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
-	int mod;
+	SetVar_ModifyTypes mod;
 	std::string playerStr;
 	std::string varStr;
 	std::string argStr;
diff --git a/src/include/animation/animation_setvar.h b/src/include/animation/animation_setvar.h
index f231fe0c8..af3906fc0 100644
--- a/src/include/animation/animation_setvar.h
+++ b/src/include/animation/animation_setvar.h
@@ -41,10 +41,10 @@ public:
 	CAnimation_SetVar() : CAnimation(AnimationSetVar) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
-	int mod;
+	SetVar_ModifyTypes mod;
 	std::string varStr;
 	std::string valueStr;
 	std::string unitSlotStr;
diff --git a/src/include/animation/animation_sound.h b/src/include/animation/animation_sound.h
index e669319d6..09cc9a860 100644
--- a/src/include/animation/animation_sound.h
+++ b/src/include/animation/animation_sound.h
@@ -42,7 +42,7 @@ public:
 	CAnimation_Sound() : CAnimation(AnimationSound) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 	void MapSound();
 
diff --git a/src/include/animation/animation_spawnmissile.h b/src/include/animation/animation_spawnmissile.h
index 18425212a..f1e461ec0 100644
--- a/src/include/animation/animation_spawnmissile.h
+++ b/src/include/animation/animation_spawnmissile.h
@@ -35,13 +35,25 @@
 #include <string>
 #include "animation.h"
 
+//SpawnMissile flags
+enum SpawnMissile_Flags {
+	SM_None = 0,           /// Clears all flags
+	SM_Damage = 1,         /// Missile deals damage to units
+	SM_ToTarget = 2,       /// Missile is directed to unit's target
+	SM_Pixel = 4,          /// Missile's offsets are calculated in pixels rather than tiles
+	SM_RelTarget = 8,      /// All calculations are relative to unit's target
+	SM_Ranged = 16,        /// Missile can't be shot if current range between unit and it's target
+	                       /// is bigger than unit's attack range
+	SM_SetDirection = 32   /// Missile takes the same direction as spawner
+};
+
 class CAnimation_SpawnMissile : public CAnimation
 {
 public:
 	CAnimation_SpawnMissile() : CAnimation(AnimationSpawnMissile) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string missileTypeStr;
diff --git a/src/include/animation/animation_spawnunit.h b/src/include/animation/animation_spawnunit.h
index a708bcdb2..7e4e5dd8c 100644
--- a/src/include/animation/animation_spawnunit.h
+++ b/src/include/animation/animation_spawnunit.h
@@ -35,13 +35,20 @@
 #include <string>
 #include "animation.h"
 
+//SpawnUnit flags
+enum SpawnUnit_Flags {
+	SU_None = 0,           /// Clears all flags
+	SU_Summoned = 1,       /// Unit is marked as "summoned"
+	SU_JoinToAIForce = 2   /// Unit is included into spawner's AI force, if available
+};
+
 class CAnimation_SpawnUnit : public CAnimation
 {
 public:
 	CAnimation_SpawnUnit() : CAnimation(AnimationSpawnUnit) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string unitTypeStr;
@@ -49,6 +56,7 @@ private:
 	std::string offYStr;
 	std::string rangeStr;
 	std::string playerStr;
+	std::string flagsStr;
 };
 
 //@}
diff --git a/src/include/animation/animation_unbreakable.h b/src/include/animation/animation_unbreakable.h
index 90c18308a..b3672eb42 100644
--- a/src/include/animation/animation_unbreakable.h
+++ b/src/include/animation/animation_unbreakable.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Unbreakable() : CAnimation(AnimationUnbreakable), state(0) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	int state;
diff --git a/src/include/animation/animation_wait.h b/src/include/animation/animation_wait.h
index 917be6d52..4c72b9184 100644
--- a/src/include/animation/animation_wait.h
+++ b/src/include/animation/animation_wait.h
@@ -41,7 +41,7 @@ public:
 	CAnimation_Wait() : CAnimation(AnimationWait) {}
 
 	virtual void Action(CUnit &unit, int &move, int scale) const;
-	virtual void Init(const char *s);
+	virtual void Init(const char *s, lua_State *l);
 
 private:
 	std::string wait;
diff --git a/src/include/particle.h b/src/include/particle.h
index 9338377fa..cfee2019f 100644
--- a/src/include/particle.h
+++ b/src/include/particle.h
@@ -77,8 +77,8 @@ public:
 class CParticle
 {
 public:
-	CParticle(CPosition position) :
-		pos(position), destroyed(false)
+	CParticle(CPosition position, int drawlevel = 0) :
+		pos(position), destroyed(false), drawLevel(drawlevel)
 	{}
 	virtual ~CParticle() {}
 
@@ -91,16 +91,20 @@ public:
 
 	virtual CParticle *clone() = 0;
 
+	int getDrawLevel() const { return drawLevel; }
+	void setDrawLevel(int value) { drawLevel = value; }
+
 protected:
 	CPosition pos;
 	bool destroyed;
+	int drawLevel;
 };
 
 
 class StaticParticle : public CParticle
 {
 public:
-	StaticParticle(CPosition position, GraphicAnimation *flame);
+	StaticParticle(CPosition position, GraphicAnimation *flame, int drawlevel = 0);
 	virtual ~StaticParticle();
 
 	virtual bool isVisible(const CViewport &vp) const;
@@ -120,13 +124,17 @@ public:
 	CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation,
 				   GraphicAnimation *destroyAnimation,
 				   int minVelocity = 0, int maxVelocity = 400,
-				   int minTrajectoryAngle = 77, int maxTTL = 0);
+				   int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
 	virtual ~CChunkParticle();
 
 	virtual bool isVisible(const CViewport &vp) const;
 	virtual void draw();
 	virtual void update(int ticks);
 	virtual CParticle *clone();
+	int getSmokeDrawLevel() const { return smokeDrawLevel; }
+	int getDestroyDrawLevel() const { return destroyDrawLevel; }
+	void setSmokeDrawLevel(int value) { smokeDrawLevel = value; }
+	void setDestroyDrawLevel(int value) { destroyDrawLevel = value; }
 
 protected:
 	CPosition initialPos;
@@ -140,6 +148,8 @@ protected:
 	int maxVelocity;
 	int minTrajectoryAngle;
 	float height;
+	int smokeDrawLevel;
+	int destroyDrawLevel;
 	GraphicAnimation *debrisAnimation;
 	GraphicAnimation *smokeAnimation;
 	GraphicAnimation *destroyAnimation;
@@ -155,7 +165,7 @@ protected:
 class CSmokeParticle : public CParticle
 {
 public:
-	CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f);
+	CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f, int drawlevel = 0);
 	virtual ~CSmokeParticle();
 
 	virtual bool isVisible(const CViewport &vp) const;
@@ -174,7 +184,7 @@ protected:
 class CRadialParticle : public CParticle
 {
 public:
-	CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed);
+	CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel = 0);
 	virtual ~CRadialParticle();
 
 	virtual bool isVisible(const CViewport &vp) const;
@@ -199,7 +209,9 @@ public:
 	static void init();
 	static void exit();
 
-	void draw(const CViewport &vp);
+	void prepareToDraw(const CViewport &vp, std::vector<CParticle *> &table);
+	void endDraw();
+
 	void update();
 
 	void add(CParticle *particle);
diff --git a/src/include/spell/spell_capture.h b/src/include/spell/spell_capture.h
index 16b6d55e7..92acb8e44 100644
--- a/src/include/spell/spell_capture.h
+++ b/src/include/spell/spell_capture.h
@@ -41,13 +41,14 @@
 class Spell_Capture : public SpellActionType
 {
 public:
-	Spell_Capture() : SacrificeEnable(0), Damage(0), DamagePercent(0) {};
+	Spell_Capture() : SacrificeEnable(false), JoinToAIForce(false), Damage(0), DamagePercent(0) {};
 	virtual int Cast(CUnit &caster, const SpellType &spell,
 					 CUnit *target, const Vec2i &goalPos);
 	virtual void Parse(lua_State *l, int startIndex, int endIndex);
 
 private:
-	char SacrificeEnable; /// true if the caster dies after casting.
+	bool SacrificeEnable; /// true if the caster dies after casting.
+	bool JoinToAIForce;   /// if true, captured unit is joined into caster's AI force, if available
 	int Damage;           /// damage the spell does if unable to caputre
 	int DamagePercent;    /// percent the target must be damaged for a
 	/// capture to suceed.
diff --git a/src/include/spell/spell_summon.h b/src/include/spell/spell_summon.h
index ce4f4aea3..b1e416646 100644
--- a/src/include/spell/spell_summon.h
+++ b/src/include/spell/spell_summon.h
@@ -41,7 +41,8 @@
 class Spell_Summon : public SpellActionType
 {
 public:
-	Spell_Summon() : SpellActionType(1), UnitType(NULL), TTL(0), RequireCorpse(0) {};
+	Spell_Summon() : SpellActionType(1), UnitType(NULL), TTL(0),
+		RequireCorpse(false), JoinToAiForce(false) {};
 	virtual int Cast(CUnit &caster, const SpellType &spell,
 					 CUnit *target, const Vec2i &goalPos);
 	virtual void Parse(lua_State *l, int startIndex, int endIndex);
@@ -50,6 +51,7 @@ private:
 	CUnitType *UnitType;    /// Type of unit to be summoned.
 	int TTL;                /// Time to live for summoned unit. 0 means infinite
 	int RequireCorpse;      /// Corpse consumed while summoning.
+	bool JoinToAiForce;     /// if true, captured unit is joined into caster's AI force, if available
 };
 
 
diff --git a/src/include/spell/spell_teleport.h b/src/include/spell/spell_teleport.h
index e667e6684..3f15e1881 100644
--- a/src/include/spell/spell_teleport.h
+++ b/src/include/spell/spell_teleport.h
@@ -40,15 +40,10 @@
 class Spell_Teleport : public SpellActionType
 {
 public:
-	Spell_Teleport() : SpellActionType(1), UnitType(NULL), TTL(0), RequireCorpse(0) {};
+	Spell_Teleport() : SpellActionType(0) {}
 	virtual int Cast(CUnit &caster, const SpellType &spell,
 					 CUnit *target, const Vec2i &goalPos);
 	virtual void Parse(lua_State *l, int startIndex, int endIndex);
-
-private:
-	CUnitType *UnitType;    /// Type of unit to be summoned.
-	int TTL;                /// Time to live for summoned unit. 0 means infinite
-	int RequireCorpse;      /// Corpse consumed while summoning.
 };
 
 
diff --git a/src/include/spells.h b/src/include/spells.h
index 040dceb62..970477043 100644
--- a/src/include/spells.h
+++ b/src/include/spells.h
@@ -224,6 +224,7 @@ public:
 	bool IsCasterOnly() const {
 		return !Range && Target == TargetSelf;
 	}
+	bool ForceUseAnimation;
 
 };
 
diff --git a/src/include/unit.h b/src/include/unit.h
index b1aacfa10..95e567e2b 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -339,21 +339,23 @@ public:
 	int ResourcesHeld;      /// Resources Held by a unit
 
 	unsigned char DamagedType;   /// Index of damage type of unit which damaged this unit
-	unsigned long Attacked; /// gamecycle unit was last attacked
-	unsigned Blink : 3;     /// Let selection rectangle blink
-	unsigned Moving : 1;    /// The unit is moving
-	unsigned ReCast : 1;    /// Recast again next cycle
-	unsigned AutoRepair : 1;    /// True if unit tries to repair on still action.
+	unsigned long Attacked;      /// gamecycle unit was last attacked
+	unsigned Blink : 3;          /// Let selection rectangle blink
+	unsigned Moving : 1;         /// The unit is moving
+	unsigned ReCast : 1;         /// Recast again next cycle
+	unsigned AutoRepair : 1;     /// True if unit tries to repair on still action.
 
-	unsigned Burning : 1;   /// unit is burning
-	unsigned Destroyed : 1; /// unit is destroyed pending reference
-	unsigned Removed : 1;   /// unit is removed (not on map)
-	unsigned Selected : 1;  /// unit is selected
+	unsigned Burning : 1;        /// unit is burning
+	unsigned Destroyed : 1;      /// unit is destroyed pending reference
+	unsigned Removed : 1;        /// unit is removed (not on map)
+	unsigned Selected : 1;       /// unit is selected
 
 	unsigned Constructed : 1;    /// Unit is in construction
 	unsigned Active : 1;         /// Unit is active for AI
 	unsigned Boarded : 1;        /// Unit is on board a transporter.
-	unsigned CacheLock : 1;        /// Unit is on lock by unitcache operations.
+	unsigned CacheLock : 1;      /// Unit is on lock by unitcache operations.
+
+	unsigned Summoned : 1;       /// Unit is summoned using spells. 
 
 	unsigned TeamSelected;  /// unit is selected by a team member.
 	CPlayer *RescuedFrom;        /// The original owner of a rescued unit.
@@ -417,13 +419,15 @@ class CPreference
 public:
 	CPreference() : ShowSightRange(false), ShowReactionRange(false),
 		ShowAttackRange(false), ShowMessages(true),
-		BigScreen(false), ShowOrders(0), ShowNameDelay(0), ShowNameTime(0) {};
+		BigScreen(false), PauseOnLeave(true),  ShowOrders(0), ShowNameDelay(0),
+		ShowNameTime(0) {};
 
 	bool ShowSightRange;     /// Show sight range.
 	bool ShowReactionRange;  /// Show reaction range.
 	bool ShowAttackRange;    /// Show attack range.
 	bool ShowMessages;		 /// Show messages.
 	bool BigScreen;			 /// If true, shows the big screen(without panels)
+	bool PauseOnLeave;       /// If true, game pauses when cursor is gone
 
 	int  ShowOrders;         /// How many second show orders of unit on map.
 	int  ShowNameDelay;      /// How many cycles need to wait until unit's name popup will appear.
diff --git a/src/include/unit_find.h b/src/include/unit_find.h
index a3186b5bc..b5be40e81 100644
--- a/src/include/unit_find.h
+++ b/src/include/unit_find.h
@@ -281,7 +281,7 @@ extern CUnit *FindIdleWorker(const CPlayer &player, const CUnit *last);
 extern bool FindTerrainType(int movemask, int resmask, int range,
 							const CPlayer &player, const Vec2i &startPos, Vec2i *pos);
 
-extern void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units);
+extern void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units, bool everybody = false);
 
 /// Find all units of this type of the player
 extern void FindPlayerUnitsByType(const CPlayer &player, const CUnitType &type, std::vector<CUnit *> &units);
diff --git a/src/include/unittype.h b/src/include/unittype.h
index 178551ce7..50e4a879d 100644
--- a/src/include/unittype.h
+++ b/src/include/unittype.h
@@ -467,6 +467,10 @@ public:
 	LuaCallback *OnHit;             /// lua function called when unit is hit
 	LuaCallback *OnEachCycle;       /// lua function called every cycle
 	LuaCallback *OnEachSecond;      /// lua function called every second
+	LuaCallback *OnInit;            /// lua function called on unit init
+
+	int TeleportCost;               /// mana used for teleportation
+	MissileConfig TeleportEffect;   /// missile created when teleported
 
 	mutable std::string DamageType; /// DamageType (used for extra death animations and impacts)
 
diff --git a/src/include/widgets.h b/src/include/widgets.h
index 48988c1d6..5650f3239 100644
--- a/src/include/widgets.h
+++ b/src/include/widgets.h
@@ -294,8 +294,6 @@ public:
 	int getPercent() const;
 
 private:
-	int width;            /// width of the widget.
-	int height;           /// height of the widget.
 	std::string caption;  /// caption of the widget.
 	unsigned int percent; /// percent value of the widget.
 };
diff --git a/src/map/map_draw.cpp b/src/map/map_draw.cpp
index dd3da8fbe..496e59798 100644
--- a/src/map/map_draw.cpp
+++ b/src/map/map_draw.cpp
@@ -332,25 +332,68 @@ void CViewport::Draw() const
 
 	CurrentViewport = this;
 	{
+		// Now we need to sort units, missiles, particles by draw level and draw them 
 		std::vector<CUnit *> unittable;
 		std::vector<Missile *> missiletable;
+		std::vector<CParticle *> particletable;
 
-		// We find and sort units after draw level.
 		FindAndSortUnits(*this, unittable);
 		const size_t nunits = unittable.size();
 		FindAndSortMissiles(*this, missiletable);
 		const size_t nmissiles = missiletable.size();
+		ParticleManager.prepareToDraw(*this, particletable);
+		const size_t nparticles = particletable.size();
+
 		size_t i = 0;
 		size_t j = 0;
+		size_t k = 0;
 
-		while (i < nunits && j < nmissiles) {
-			if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) {
-				unittable[i]->Draw(*this);
-				++i;
-			} else {
-				missiletable[j]->DrawMissile(*this);
-				++j;
-			}
+
+		while ((i < nunits && j < nmissiles) || (i < nunits && k < nparticles)
+			|| (j < nmissiles && k < nparticles)) {
+				if (i == nunits) {
+					if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
+						missiletable[j]->DrawMissile(*this);
+						++j;
+					} else {
+						particletable[k]->draw();
+						++k;
+					}	
+				} else if (j == nmissiles) {
+					if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
+						unittable[i]->Draw(*this);
+						++i;
+					} else {
+						particletable[k]->draw();
+						++k;
+					}	
+				} else if (k == nparticles) {
+					if (unittable[i]->Type->DrawLevel < missiletable[j]->Type->DrawLevel) {
+						unittable[i]->Draw(*this);
+						++i;
+					} else {
+						missiletable[j]->DrawMissile(*this);
+						++j;
+					}
+				} else {
+					if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) {
+						if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
+							unittable[i]->Draw(*this);
+							++i;
+						} else {
+							particletable[k]->draw();
+							++k;
+						}
+					} else {
+						if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
+							missiletable[j]->DrawMissile(*this);
+							++j;
+						} else {
+							particletable[k]->draw();
+							++k;
+						}	
+					}
+				}
 		}
 		for (; i < nunits; ++i) {
 			unittable[i]->Draw(*this);
@@ -358,10 +401,12 @@ void CViewport::Draw() const
 		for (; j < nmissiles; ++j) {
 			missiletable[j]->DrawMissile(*this);
 		}
+		for (; k < nparticles; ++k) {
+			particletable[k]->draw();
+		}
+		ParticleManager.endDraw();
 	}
 
-	ParticleManager.draw(*this);
-
 	this->DrawMapFogOfWar();
 
 	//
diff --git a/src/particle/chunkparticle.cpp b/src/particle/chunkparticle.cpp
index e858974a5..b886c5efa 100644
--- a/src/particle/chunkparticle.cpp
+++ b/src/particle/chunkparticle.cpp
@@ -46,8 +46,8 @@ static inline float deg2rad(int degrees)
 
 CChunkParticle::CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation,
 							   GraphicAnimation *destroyAnimation,
-							   int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL) :
-	CParticle(position), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0),
+							   int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL, int drawlevel) :
+	CParticle(position, drawlevel), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0),
 	age(0), height(0.f)
 {
 	float radians = deg2rad(MyRand() % 360);
@@ -112,7 +112,7 @@ void CChunkParticle::update(int ticks)
 		if (destroyAnimation) {
 			CPosition p(pos.x, calculateScreenPos(pos.y, height));
 			GraphicAnimation *destroyanimation = destroyAnimation->clone();
-			StaticParticle *destroy = new StaticParticle(p, destroyanimation);
+			StaticParticle *destroy = new StaticParticle(p, destroyanimation, destroyDrawLevel);
 			ParticleManager.add(destroy);
 		}
 
@@ -126,7 +126,7 @@ void CChunkParticle::update(int ticks)
 	if (age > nextSmokeTicks) {
 		CPosition p(pos.x, calculateScreenPos(pos.y, height));
 		GraphicAnimation *smokeanimation = smokeAnimation->clone();
-		CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation);
+		CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation, 0, -22.0f, smokeDrawLevel);
 		ParticleManager.add(smoke);
 
 		nextSmokeTicks += MyRand() % randSmokeTicks + minSmokeTicks;
@@ -151,7 +151,10 @@ void CChunkParticle::update(int ticks)
 
 CParticle *CChunkParticle::clone()
 {
-	return new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL);
+	CChunkParticle *particle = new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL, drawLevel);
+	particle->smokeDrawLevel = smokeDrawLevel;
+	particle->destroyDrawLevel = destroyDrawLevel;
+	return particle;
 }
 
 //@}
diff --git a/src/particle/particlemanager.cpp b/src/particle/particlemanager.cpp
index 8025f3394..8e1e12270 100644
--- a/src/particle/particlemanager.cpp
+++ b/src/particle/particlemanager.cpp
@@ -34,6 +34,8 @@
 #include "ui.h"
 #include "video.h"
 
+#include <algorithm>
+
 
 CParticleManager ParticleManager;
 
@@ -70,17 +72,27 @@ void CParticleManager::clear()
 	new_particles.clear();
 }
 
-void CParticleManager::draw(const CViewport &vp)
+static inline bool DrawLevelCompare(const CParticle *lhs, const CParticle *rhs)
+{
+	return lhs->getDrawLevel() < rhs->getDrawLevel();
+}
+
+void CParticleManager::prepareToDraw(const CViewport &vp, std::vector<CParticle *> &table)
 {
 	this->vp = &vp;
 
-	std::vector<CParticle *>::iterator i;
-	for (i = particles.begin(); i != particles.end(); ++i) {
-		if ((*i)->isVisible(vp)) {
-			(*i)->draw();
+	for (std::vector<CParticle *>::iterator it = particles.begin(); it != particles.end(); ++it) {
+		CParticle &particle = **it;
+		if (particle.isVisible(vp)) {
+			table.push_back(&particle);
 		}
 	}
 
+	std::sort(table.begin(), table.end(), DrawLevelCompare);
+}
+
+void CParticleManager::endDraw()
+{
 	this->vp = NULL;
 }
 
diff --git a/src/particle/radialparticle.cpp b/src/particle/radialparticle.cpp
index e27008312..20cfb008e 100644
--- a/src/particle/radialparticle.cpp
+++ b/src/particle/radialparticle.cpp
@@ -34,8 +34,8 @@
 #include "stratagus.h"
 #include "particle.h"
 
-CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed) :
-	CParticle(position)
+CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel) :
+	CParticle(position, drawlevel)
 {
 	Assert(animation);
 	this->animation = animation->clone();
@@ -76,7 +76,7 @@ void CRadialParticle::update(int ticks)
 
 CParticle *CRadialParticle::clone()
 {
-	CParticle *p = new CRadialParticle(pos, animation, maxSpeed);
+	CParticle *p = new CRadialParticle(pos, animation, maxSpeed, drawLevel);
 	return p;
 }
 
diff --git a/src/particle/smokeparticle.cpp b/src/particle/smokeparticle.cpp
index e0cbdac18..b735ebaff 100644
--- a/src/particle/smokeparticle.cpp
+++ b/src/particle/smokeparticle.cpp
@@ -36,8 +36,8 @@
 
 
 CSmokeParticle::CSmokeParticle(CPosition position, GraphicAnimation *smoke,
-							   float speedx, float speedy) :
-	CParticle(position)
+							   float speedx, float speedy, int drawlevel) :
+	CParticle(position, drawlevel)
 {
 	Assert(smoke);
 	this->puff = smoke->clone();
@@ -77,7 +77,7 @@ void CSmokeParticle::update(int ticks)
 
 CParticle *CSmokeParticle::clone()
 {
-	return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y);
+	return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y, drawLevel);
 }
 
 //@}
diff --git a/src/particle/staticparticle.cpp b/src/particle/staticparticle.cpp
index e0cfa6f54..a2c32d880 100644
--- a/src/particle/staticparticle.cpp
+++ b/src/particle/staticparticle.cpp
@@ -33,8 +33,8 @@
 #include "particle.h"
 
 
-StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation) :
-	CParticle(position)
+StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel) :
+	CParticle(position, drawlevel)
 {
 	Assert(animation);
 	this->animation = animation->clone();
@@ -66,7 +66,7 @@ void StaticParticle::update(int ticks)
 
 CParticle *StaticParticle::clone()
 {
-	CParticle *p = new StaticParticle(pos, animation);
+	CParticle *p = new StaticParticle(pos, animation, drawLevel);
 	return p;
 }
 
diff --git a/src/sound/sound_server.cpp b/src/sound/sound_server.cpp
index 54f40058f..9b92ec28c 100644
--- a/src/sound/sound_server.cpp
+++ b/src/sound/sound_server.cpp
@@ -438,14 +438,7 @@ int SetChannelStereo(int channel, int stereo)
 		stereo = Channels[channel].Stereo;
 	} else {
 		SDL_LockAudio();
-
-		if (stereo > 127) {
-			stereo = 127;
-		} else if (stereo < -128) {
-			stereo = -128;
-		}
 		Channels[channel].Stereo = stereo;
-
 		SDL_UnlockAudio();
 	}
 	return stereo;
diff --git a/src/spell/script_spell.cpp b/src/spell/script_spell.cpp
index 6280a6bc3..decd53641 100644
--- a/src/spell/script_spell.cpp
+++ b/src/spell/script_spell.cpp
@@ -333,6 +333,9 @@ static int CclDefineSpell(lua_State *l)
 		} else if (!strcmp(value, "repeat-cast")) {
 			spell->RepeatCast = 1;
 			--i;
+		} else if (!strcmp(value, "force-use-animation")) {
+			spell->ForceUseAnimation = true;
+			--i;
 		} else if (!strcmp(value, "target")) {
 			value = LuaToString(l, i + 1);
 			if (!strcmp(value, "self")) {
diff --git a/src/spell/spell_capture.cpp b/src/spell/spell_capture.cpp
index 18c4354e0..09ca88cc8 100644
--- a/src/spell/spell_capture.cpp
+++ b/src/spell/spell_capture.cpp
@@ -34,6 +34,9 @@
 
 #include "spell/spell_capture.h"
 
+#include "../ai/ai_local.h"
+
+#include "commands.h"
 #include "game.h"
 #include "script.h"
 #include "unit.h"
@@ -44,7 +47,9 @@
 		const char *value = LuaToString(l, -1, j + 1);
 		++j;
 		if (!strcmp(value, "sacrifice")) {
-			this->SacrificeEnable = 1;
+			this->SacrificeEnable = true;
+		} else if (!strcmp(value, "join-to-ai-force")) {
+			this->JoinToAIForce = true;
 		} else if (!strcmp(value, "damage")) {
 			this->Damage = LuaToNumber(l, -1, j + 1);
 		} else if (!strcmp(value, "percent")) {
@@ -79,8 +84,7 @@
 			if (this->SacrificeEnable) {
 				// No corpse.
 				caster.Remove(NULL);
-				UnitLost(caster);
-				UnitClearOrders(caster);
+				caster.Release();
 			}
 			return 1;
 		}
@@ -103,15 +107,24 @@
 		caster.Variable[KILL_INDEX].Enable = 1;
 	}
 	target->ChangeOwner(*caster.Player);
+	UnitClearOrders(*target);
+	if (this->JoinToAIForce && caster.Player->AiEnabled) {
+		int force = caster.Player->Ai->Force.GetForce(caster);
+		if (force != -1) {
+			caster.Player->Ai->Force[force].Insert(*target);
+			target->GroupId = caster.GroupId;
+			CommandDefend(*target, caster, FlushCommands);
+		}
+	}
 	if (this->SacrificeEnable) {
 		// No corpse.
 		caster.Remove(NULL);
-		UnitLost(caster);
-		UnitClearOrders(caster);
+		caster.Release();
 	} else {
 		caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
 	}
-	UnitClearOrders(*target);
+	
+	
 	return 0;
 }
 
diff --git a/src/spell/spell_spawnportal.cpp b/src/spell/spell_spawnportal.cpp
index b444dacf7..b730f94ea 100644
--- a/src/spell/spell_spawnportal.cpp
+++ b/src/spell/spell_spawnportal.cpp
@@ -85,6 +85,7 @@
 	} else {
 		portal = MakeUnitAndPlace(goalPos, *this->PortalType,
 			CurrentPlayer ? caster.Player : &Players[PlayerNumNeutral]);
+		portal->Summoned = 1;
 	}
 	portal->TTL = GameCycle + this->TTL;
 	//  Goal is used to link to destination circle of power
diff --git a/src/spell/spell_summon.cpp b/src/spell/spell_summon.cpp
index 2033c9349..58bcfa81c 100644
--- a/src/spell/spell_summon.cpp
+++ b/src/spell/spell_summon.cpp
@@ -36,6 +36,8 @@
 
 #include "spell/spell_summon.h"
 
+#include "../ai/ai_local.h"
+
 #include "actions.h"
 #include "commands.h"
 #include "script.h"
@@ -57,7 +59,10 @@
 		} else if (!strcmp(value, "time-to-live")) {
 			this->TTL = LuaToNumber(l, -1, j + 1);
 		} else if (!strcmp(value, "require-corpse")) {
-			this->RequireCorpse = 1;
+			this->RequireCorpse = true;
+			--j;
+		} else if (!strcmp(value, "join-to-ai-force")) {
+			this->JoinToAiForce = true;
 			--j;
 		} else {
 			LuaError(l, "Unsupported summon tag: %s" _C_ value);
@@ -124,6 +129,8 @@ public:
 		if (target != NULL) {
 			target->tilePos = pos;
 			DropOutOnSide(*target, LookingW, NULL);
+			// To avoid defending summoned unit for AI
+			target->Summoned = 1;
 			//
 			//  set life span. ttl=0 results in a permanent unit.
 			//
@@ -131,13 +138,13 @@ public:
 				target->TTL = GameCycle + ttl;
 			}
 
-			// To avoid defending summoned unit for AI
-			if (caster.Player->AiEnabled) {
-				if (caster.GroupId) {
+			// Insert summoned unit to AI force so it will help them in battle
+			if (this->JoinToAiForce && caster.Player->AiEnabled) {
+				int force = caster.Player->Ai->Force.GetForce(caster);
+				if (force != -1) {
+					caster.Player->Ai->Force[force].Insert(*target);
 					target->GroupId = caster.GroupId;
 					CommandDefend(*target, caster, FlushCommands);
-				} else {
-					target->GroupId = -1;
 				}
 			}
 
diff --git a/src/spell/spells.cpp b/src/spell/spells.cpp
index 6daf10962..92a639071 100644
--- a/src/spell/spells.cpp
+++ b/src/spell/spells.cpp
@@ -485,7 +485,7 @@ SpellType::SpellType(int slot, const std::string &ident) :
 	Ident(ident), Slot(slot), Target(), Action(),
 	Range(0), ManaCost(0), RepeatCast(0),
 	DependencyId(-1), Condition(NULL),
-	AutoCast(NULL), AICast(NULL)
+	AutoCast(NULL), AICast(NULL), ForceUseAnimation(false)
 {
 	memset(Costs, 0, sizeof(Costs));
 }
diff --git a/src/tolua/particle.pkg b/src/tolua/particle.pkg
index 3d157495d..db7d6172a 100644
--- a/src/tolua/particle.pkg
+++ b/src/tolua/particle.pkg
@@ -16,30 +16,35 @@ class GraphicAnimation
 class CParticle
 {
 	virtual CParticle* clone();
+	void setDrawLevel(int value);
 };
 
 class StaticParticle : public CParticle
 {
 public:
-	StaticParticle(CPosition position, GraphicAnimation *animation);
+	StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel = 0);
 };
 
 class CChunkParticle : public CParticle
 {
 public:
-	CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0);
+	CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
+	int getSmokeDrawLevel() const;
+	int getDestroyDrawLevel() const;
+	void setSmokeDrawLevel(int value);
+	void setDestroyDrawLevel(int value);
 };
 
 class CSmokeParticle : public CParticle
 {
 public:
-	CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0);
+	CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0, int drawlevel = 0);
 };
 
 class CRadialParticle : public CParticle
 {
 public:
-	CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed);
+	CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed, int drawlevel = 0);
 };
 
 class CParticleManager
diff --git a/src/tolua/unit.pkg b/src/tolua/unit.pkg
index 61e996c70..e07191b96 100644
--- a/src/tolua/unit.pkg
+++ b/src/tolua/unit.pkg
@@ -22,6 +22,7 @@ class CPreference
 	bool ShowAttackRange;
 	bool ShowMessages;
 	bool BigScreen;
+	bool PauseOnLeave;
 
 	unsigned int ShowOrders;
 	unsigned int  ShowNameDelay;
diff --git a/src/ui/botpanel.cpp b/src/ui/botpanel.cpp
index ae32748b8..ceb6aa5c2 100644
--- a/src/ui/botpanel.cpp
+++ b/src/ui/botpanel.cpp
@@ -847,14 +847,17 @@ void UpdateStatusLineForButton(const ButtonAction &button)
 */
 bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction)
 {
+	bool res = false;
 	if (buttonaction.Allowed) {
-		return buttonaction.Allowed(unit, buttonaction);
+		res = buttonaction.Allowed(unit, buttonaction);
+		if (!res) {
+			return false;
+		} else {
+			res = false;
+		}
 	}
 
-	bool res = false;
-	// FIXME: we have to check and if these unit buttons are available
-	//    i.e. if button action is ButtonTrain for example check if
-	// required unit is not restricted etc...
+	// Check button-specific cases
 	switch (buttonaction.Action) {
 		case ButtonStop:
 		case ButtonStandGround:
diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp
index 1247e3947..dc2713200 100644
--- a/src/ui/mainscr.cpp
+++ b/src/ui/mainscr.cpp
@@ -153,7 +153,7 @@ static void UiDrawLifeBar(const CUnit &unit, int x, int y)
 		}
 
 		f = (f * (unit.Type->Icon.Icon->G->Width)) / 100;
-		Video.FillRectangleClip(color, x + 1, y + 1, f - 2, 5);
+		Video.FillRectangleClip(color, x + 1, y + 1, f > 1 ? f - 2 : 0, 5);
 	}
 }
 
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index 319887e59..07bc18d7b 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -377,6 +377,9 @@ static int CclUnit(lua_State *l)
 		} else if (!strcmp(value, "selected")) {
 			unit->Selected = 1;
 			--j;
+		} else if (!strcmp(value, "summoned")) {
+			unit->Summoned = 1;
+			--j;
 		} else if (!strcmp(value, "rescued-from")) {
 			unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)];
 		} else if (!strcmp(value, "seen-by-player")) {
diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp
index fa839ece0..9d0e87da7 100644
--- a/src/unit/script_unittype.cpp
+++ b/src/unit/script_unittype.cpp
@@ -551,6 +551,11 @@ static int CclDefineUnitType(lua_State *l)
 			type->ExplodeWhenKilled = 1;
 			type->Explosion.Name = LuaToString(l, -1);
 			type->Explosion.Missile = NULL;
+		} else if (!strcmp(value, "TeleportCost")) {
+			type->TeleportCost = LuaToNumber(l, -1);
+		} else if (!strcmp(value, "TeleportEffect")) {
+			type->TeleportEffect.Name = LuaToString(l, -1);
+			type->TeleportEffect.Missile = NULL;
 		} else if (!strcmp(value, "DeathExplosion")) {
 			type->DeathExplosion = new LuaCallback(l, -1);
 		} else if (!strcmp(value, "OnHit")) {
@@ -559,6 +564,8 @@ static int CclDefineUnitType(lua_State *l)
 			type->OnEachCycle = new LuaCallback(l, -1);
 		} else if (!strcmp(value, "OnEachSecond")) {
 			type->OnEachSecond = new LuaCallback(l, -1);
+		} else if (!strcmp(value, "OnInit")) {
+			type->OnInit = new LuaCallback(l, -1);
 		} else if (!strcmp(value, "Type")) {
 			value = LuaToString(l, -1);
 			if (!strcmp(value, "land")) {
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 56d5f42f4..d8f63cb09 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -453,6 +453,7 @@ void CUnit::Init()
 	Moving = 0;
 	ReCast = 0;
 	CacheLock = 0;
+	Summoned = 0;
 	memset(&Anim, 0, sizeof(Anim));
 	CurrentResource = 0;
 	Orders.clear();
@@ -738,6 +739,12 @@ CUnit *MakeUnit(const CUnitType &type, CPlayer *player)
 		unit->AssignToPlayer(*player);
 	}
 
+	if (unit->Type->OnInit) {
+		unit->Type->OnInit->pushPreamble();
+		unit->Type->OnInit->pushInteger(UnitNumber(*unit));
+		unit->Type->OnInit->run();
+	}
+
 	//  fancy buildings: mirror buildings (but shadows not correct)
 	if (type.Building && FancyBuildings
 		&& unit->Type->NoRandomPlacing == false && (MyRand() & 1) != 0) {
diff --git a/src/unit/unit_find.cpp b/src/unit/unit_find.cpp
index 3943f32de..5ca6b6ae9 100644
--- a/src/unit/unit_find.cpp
+++ b/src/unit/unit_find.cpp
@@ -310,7 +310,6 @@ public:
 		resinfo(*worker.Type->ResInfo[resource]),
 		deposit(deposit),
 		movemask(worker.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)),
-		resource(resource),
 		maxRange(maxRange),
 		check_usage(check_usage),
 		res_finder(resource, 1),
@@ -348,7 +347,6 @@ private:
 	const ResourceInfo &resinfo;
 	const CUnit *deposit;
 	unsigned int movemask;
-	int resource;
 	int maxRange;
 	bool check_usage;
 	CResourceFinder res_finder;
@@ -511,15 +509,16 @@ CUnit *FindIdleWorker(const CPlayer &player, const CUnit *last)
 /**
 **  Find all units of type.
 **
-**  @param type   type of unit requested
-**  @param units  array in which we have to store the units
+**  @param type       type of unit requested
+**  @param units      array in which we have to store the units
+**  @param everybody  if true, include all units
 */
-void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units)
+void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units, bool everybody)
 {
 	for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it) {
 		CUnit &unit = **it;
 
-		if (unit.Type == &type && !unit.IsUnusable()) {
+		if (unit.Type == &type && !unit.IsUnusable(everybody)) {
 			units.push_back(&unit);
 		}
 	}
@@ -1008,9 +1007,7 @@ private:
 		}
 
 		// don't consider small damages...
-		if (sgood < 20) {
-			sgood = 20;
-		}
+		sgood = std::max(sgood, 20);
 
 		int cost = sbad / sgood;
 		if (cost > best_cost) {
diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp
index a6a12b8d6..66cb15323 100644
--- a/src/unit/unit_save.cpp
+++ b/src/unit/unit_save.cpp
@@ -177,6 +177,9 @@ void SaveUnit(const CUnit &unit, CFile &file)
 	if (unit.Selected) {
 		file.printf(" \"selected\",");
 	}
+	if (unit.Summoned) {
+		file.printf(" \"summoned\",");
+	}
 	if (unit.RescuedFrom) {
 		file.printf(" \"rescued-from\", %d,", unit.RescuedFrom->Index);
 	}
diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp
index e15fa6653..9f74572f8 100644
--- a/src/unit/unittype.cpp
+++ b/src/unit/unittype.cpp
@@ -611,7 +611,8 @@ CUnitType::CUnitType() :
 	Slot(0), Width(0), Height(0), OffsetX(0), OffsetY(0), DrawLevel(0),
 	ShadowWidth(0), ShadowHeight(0), ShadowOffsetX(0), ShadowOffsetY(0),
 	Animations(NULL), StillFrame(0),
-	DeathExplosion(NULL), OnHit(NULL), OnEachCycle(NULL), OnEachSecond(NULL),
+	DeathExplosion(NULL), OnHit(NULL), OnEachCycle(NULL), OnEachSecond(NULL), OnInit(NULL),
+	TeleportCost(0),
 	CorpseType(NULL), Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
 	BoxWidth(0), BoxHeight(0), BoxOffsetX(0), BoxOffsetY(0), NumDirections(0),
 	MinAttackRange(0), ReactRangeComputer(0), ReactRangePerson(0), Priority(0),
@@ -649,6 +650,7 @@ CUnitType::~CUnitType()
 	delete OnHit;
 	delete OnEachCycle;
 	delete OnEachSecond;
+	delete OnInit;
 
 	BoolFlag.clear();
 
@@ -1123,6 +1125,7 @@ void LoadUnitTypes()
 		// Lookup missiles.
 		type.Missile.MapMissile();
 		type.Explosion.MapMissile();
+		type.TeleportEffect.MapMissile();
 
 		// Lookup impacts
 		for (int i = 0; i < ANIMATIONS_DEATHTYPES + 2; ++i) {
diff --git a/src/unit/upgrade.cpp b/src/unit/upgrade.cpp
index ed6ebb915..4c7e62fab 100644
--- a/src/unit/upgrade.cpp
+++ b/src/unit/upgrade.cpp
@@ -597,7 +597,7 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
 			if (varModified) {
 				std::vector<CUnit *> unitupgrade;
 
-				FindUnitsByType(*UnitTypes[z], unitupgrade);
+				FindUnitsByType(*UnitTypes[z], unitupgrade, true);
 				for (size_t j = 0; j != unitupgrade.size(); ++j) {
 					CUnit &unit = *unitupgrade[j];
 
diff --git a/src/video/sdl.cpp b/src/video/sdl.cpp
index 48a97d57e..b7fe6cc3d 100644
--- a/src/video/sdl.cpp
+++ b/src/video/sdl.cpp
@@ -94,6 +94,7 @@
 #include "sound_server.h"
 #include "translate.h"
 #include "ui.h"
+#include "unit.h"
 #include "video.h"
 #include "widgets.h"
 
@@ -860,7 +861,7 @@ static void SdlDoEvent(const EventCallback &callbacks, SDL_Event &event)
 				}
 				InMainWindow = (event.active.gain != 0);
 			}
-			if (event.active.state & SDL_APPACTIVE || SDL_GetAppState() & SDL_APPACTIVE) {
+			if (Preference.PauseOnLeave && (event.active.state & SDL_APPACTIVE || SDL_GetAppState() & SDL_APPACTIVE)) {
 				static bool DoTogglePause = false;
 
 				if (IsSDLWindowVisible && !event.active.gain) {
diff --git a/tests/network/test_netconnect.cpp b/tests/network/test_netconnect.cpp
index 65fde63e2..d0cecbd17 100644
--- a/tests/network/test_netconnect.cpp
+++ b/tests/network/test_netconnect.cpp
@@ -53,6 +53,7 @@ void FillCustomValue(CServerSetup *obj)
 	obj->GameTypeOption = 52;
 	obj->Difficulty = 54;
 	obj->MapRichness = 56;
+	obj->Opponents = 58;
 	for (int i = 0; i != PlayerMax; ++i) {
 		obj->CompOpt[i] = i + 1;
 	}