From 13ffa1d0b315ccba4432ff07b1a04f1f1dc30835 Mon Sep 17 00:00:00 2001
From: cybermind <iddqd_mail@mail.ru>
Date: Sun, 12 May 2013 21:09:02 +0600
Subject: [PATCH] [+] Added CUnit flag Summoned to mark units which are
 summoned by spells [*] Summoned units don't bother AI when attacked and join
 into AI attack forces to help in attack wave [*] Some animation code clean-up

---
 src/ai/ai.cpp                                 |  2 +-
 src/ai/ai_force.cpp                           | 24 +++++
 src/ai/ai_local.h                             |  5 +-
 src/animation/animation.cpp                   | 93 +++++++++++++++----
 src/animation/animation_exactframe.cpp        |  6 +-
 src/animation/animation_frame.cpp             |  6 +-
 src/animation/animation_ifvar.cpp             |  4 +-
 src/animation/animation_luacallback.cpp       |  2 +-
 src/animation/animation_move.cpp              |  2 +-
 src/animation/animation_randomgoto.cpp        |  2 +-
 src/animation/animation_randomrotate.cpp      |  4 +-
 src/animation/animation_randomwait.cpp        |  4 +-
 src/animation/animation_rotate.cpp            |  2 +-
 src/animation/animation_setplayervar.cpp      |  4 +-
 src/animation/animation_setvar.cpp            |  2 +-
 src/animation/animation_spawnmissile.cpp      | 83 ++++-------------
 src/animation/animation_spawnunit.cpp         | 30 +++++-
 src/animation/animation_wait.cpp              |  2 +-
 src/include/animation.h                       |  3 +-
 .../animation/animation_spawnmissile.h        | 12 +++
 src/include/animation/animation_spawnunit.h   |  8 ++
 src/include/unit.h                            | 22 +++--
 src/spell/spell_spawnportal.cpp               |  1 +
 src/spell/spell_summon.cpp                    | 12 ++-
 src/unit/script_unit.cpp                      |  3 +
 src/unit/unit.cpp                             |  1 +
 src/unit/unit_save.cpp                        |  3 +
 27 files changed, 219 insertions(+), 123 deletions(-)

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 60e0e8eec..6cd69d8ab 100644
--- a/src/ai/ai_force.cpp
+++ b/src/ai/ai_force.cpp
@@ -467,6 +467,30 @@ unsigned int AiForceManager::FindFreeForce(AiForceRole role, int begin)
 	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.
 */
diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h
index 89bb29ac8..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);
@@ -220,6 +220,7 @@ public:
 		return script[index];
 	}
 
+	int GetForce(const CUnit &unit);
 	void RemoveDeadUnit();
 	bool Assign(CUnit &unit);
 	void Update();
diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp
index 0088b5ba8..4163caec2 100644
--- a/src/animation/animation.cpp
+++ b/src/animation/animation.cpp
@@ -134,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;
 			}
@@ -152,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';
 		}
@@ -164,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;
@@ -178,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;
 			}
@@ -189,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();
@@ -201,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';
 		}
@@ -213,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) {
@@ -224,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 = 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.
diff --git a/src/animation/animation_exactframe.cpp b/src/animation/animation_exactframe.cpp
index f2e1f8ccf..f03bf2790 100644
--- a/src/animation/animation_exactframe.cpp
+++ b/src/animation/animation_exactframe.cpp
@@ -52,7 +52,11 @@
 
 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 1d3c9a731..57c94ef7e 100644
--- a/src/animation/animation_frame.cpp
+++ b/src/animation/animation_frame.cpp
@@ -53,7 +53,11 @@
 
 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_ifvar.cpp b/src/animation/animation_ifvar.cpp
index 1dc5e4fab..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) {
diff --git a/src/animation/animation_luacallback.cpp b/src/animation/animation_luacallback.cpp
index 18f9f778f..055498b5c 100644
--- a/src/animation/animation_luacallback.cpp
+++ b/src/animation/animation_luacallback.cpp
@@ -50,7 +50,7 @@
 	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());
+		const int arg = ParseAnimInt(unit, str.c_str());
 		cb->pushInteger(arg);
 	}
 	cb->run();
diff --git a/src/animation/animation_move.cpp b/src/animation/animation_move.cpp
index 3e37de3bd..88d9c034f 100644
--- a/src/animation/animation_move.cpp
+++ b/src/animation/animation_move.cpp
@@ -44,7 +44,7 @@
 	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, lua_State *)
diff --git a/src/animation/animation_randomgoto.cpp b/src/animation/animation_randomgoto.cpp
index 3aef2a086..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;
 	}
 }
diff --git a/src/animation/animation_randomrotate.cpp b/src/animation/animation_randomrotate.cpp
index c0d10b7fe..f6969c90f 100644
--- a/src/animation/animation_randomrotate.cpp
+++ b/src/animation/animation_randomrotate.cpp
@@ -45,9 +45,9 @@
 	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()));
 	}
 }
 
diff --git a/src/animation/animation_randomwait.cpp b/src/animation/animation_randomwait.cpp
index 1336f7436..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);
 }
diff --git a/src/animation/animation_rotate.cpp b/src/animation/animation_rotate.cpp
index 963f94652..b15eab44b 100644
--- a/src/animation/animation_rotate.cpp
+++ b/src/animation/animation_rotate.cpp
@@ -66,7 +66,7 @@ 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()));
 	}
 }
 
diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp
index e41d528a2..80981a7c4 100644
--- a/src/animation/animation_setplayervar.cpp
+++ b/src/animation/animation_setplayervar.cpp
@@ -178,8 +178,8 @@ 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) {
diff --git a/src/animation/animation_setvar.cpp b/src/animation/animation_setvar.cpp
index b6b4369bd..0f7957170 100644
--- a/src/animation/animation_setvar.cpp
+++ b/src/animation/animation_setvar.cpp
@@ -95,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;
diff --git a/src/animation/animation_spawnmissile.cpp b/src/animation/animation_spawnmissile.cpp
index 2535e0735..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;
 		}
 	}
diff --git a/src/animation/animation_spawnunit.cpp b/src/animation/animation_spawnunit.cpp
index e96fa7b55..b150dfb78 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,7 +144,7 @@ found:
 }
 
 /*
-**  s = "unitType offX offY range player"
+**  s = "unitType offX offY range player flags"
 */
 /* virtual */ void CAnimation_SpawnUnit::Init(const char *s, lua_State *)
 {
@@ -154,6 +170,10 @@ 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));
+	this->flagsStr.assign(str, begin, end - begin);
 }
 
 //@}
diff --git a/src/animation/animation_wait.cpp b/src/animation/animation_wait.cpp
index 7b65d2097..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;
 	}
diff --git a/src/include/animation.h b/src/include/animation.h
index 91a931940..bab6db85c 100644
--- a/src/include/animation.h
+++ b/src/include/animation.h
@@ -167,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_spawnmissile.h b/src/include/animation/animation_spawnmissile.h
index bb938d8e6..f1e461ec0 100644
--- a/src/include/animation/animation_spawnmissile.h
+++ b/src/include/animation/animation_spawnmissile.h
@@ -35,6 +35,18 @@
 #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:
diff --git a/src/include/animation/animation_spawnunit.h b/src/include/animation/animation_spawnunit.h
index c3ff2c456..7e4e5dd8c 100644
--- a/src/include/animation/animation_spawnunit.h
+++ b/src/include/animation/animation_spawnunit.h
@@ -35,6 +35,13 @@
 #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:
@@ -49,6 +56,7 @@ private:
 	std::string offYStr;
 	std::string rangeStr;
 	std::string playerStr;
+	std::string flagsStr;
 };
 
 //@}
diff --git a/src/include/unit.h b/src/include/unit.h
index 8570613bf..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.
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..08670643d 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"
@@ -124,6 +126,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 +135,13 @@ public:
 				target->TTL = GameCycle + ttl;
 			}
 
-			// To avoid defending summoned unit for AI
+			// Insert summoned unit to AI force so it will help them in battle
 			if (caster.Player->AiEnabled) {
-				if (caster.GroupId) {
+				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/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/unit.cpp b/src/unit/unit.cpp
index e3ccdb745..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();
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);
 	}