From c3dea78611482eca2cd31c7652c4cb8ee6613df9 Mon Sep 17 00:00:00 2001
From: joris <joris.dauphin@gmail.com>
Date: Wed, 22 Feb 2012 08:45:58 +0100
Subject: [PATCH] Some more COrder_ (Die, Patrol, StandGroung, Still)

---
 src/action/action_build.cpp     |   4 -
 src/action/action_die.cpp       | 114 ++++++++++-------
 src/action/action_patrol.cpp    | 165 ++++++++++++------------
 src/action/action_research.cpp  |   5 -
 src/action/action_spellcast.cpp |   9 +-
 src/action/action_stand.cpp     |  38 +++++-
 src/action/action_still.cpp     | 161 ++++++++++++++---------
 src/action/actions.cpp          | 219 ++++----------------------------
 src/include/actions.h           | 117 +++++++++++++----
 src/include/script.h            |  23 +++-
 src/unit/script_unit.cpp        | 142 ++++++++-------------
 src/unit/unit_draw.cpp          |   7 +-
 src/unit/unit_save.cpp          |  15 ---
 13 files changed, 492 insertions(+), 527 deletions(-)

diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp
index 29ad1d712..b739b2e24 100644
--- a/src/action/action_build.cpp
+++ b/src/action/action_build.cpp
@@ -350,10 +350,6 @@ void HandleActionBuild(COrder& /*order*/, CUnit &unit)
 // Action_built
 //////////////////////////
 
-/* virtual */ COrder_Built *COrder_Built::Clone() const
-{
-	return new COrder_Built(*this);
-}
 /* virtual */ void COrder_Built::Save(CFile &file, const CUnit &unit) const
 {
 	file.printf("{\"action-built\", ");
diff --git a/src/action/action_die.cpp b/src/action/action_die.cpp
index 44b712f8d..3646c1cca 100644
--- a/src/action/action_die.cpp
+++ b/src/action/action_die.cpp
@@ -39,15 +39,81 @@
 #include "stratagus.h"
 #include "unittype.h"
 #include "animation.h"
-#include "player.h"
 #include "unit.h"
 #include "actions.h"
-#include "map.h"
+#include "iolib.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
 ----------------------------------------------------------------------------*/
 
+/* virtual */ void COrder_Die::Save(CFile &file, const CUnit &unit) const
+{
+	file.printf("{\"action-die\"}");
+}
+
+/* virtual */ bool COrder_Die::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
+{
+	return false;
+}
+
+static bool AnimateActionDie(CUnit &unit)
+{
+	const CAnimations *animations = unit.Type->Animations;
+
+	if (animations == NULL) {
+		return false;
+	}
+	if (animations->Death[unit.DamagedType]) {
+		UnitShowAnimation(unit, animations->Death[unit.DamagedType]);
+		return true;
+	} else if (animations->Death[ANIMATIONS_DEATHTYPES]) {
+		UnitShowAnimation(unit, animations->Death[ANIMATIONS_DEATHTYPES]);
+		return true;
+	}
+	return false;
+}
+
+
+/* virtual */ bool COrder_Die::Execute(CUnit &unit)
+{
+	// Show death animation
+	if (AnimateActionDie(unit) == false) {
+		// some units has no death animation
+		unit.Anim.Unbreakable = 0;
+	}
+	if (unit.Anim.Unbreakable) {
+		return false;
+	}
+	CUnitType &type = *unit.Type;
+
+	// Die sequence terminated, generate corpse.
+	if (type.CorpseType == NULL) {
+		unit.Remove(NULL);
+		unit.Release();
+		return false;
+	}
+
+	CUnitType &corpseType = *type.CorpseType;
+	Assert(type.TileWidth >= corpseType.TileWidth && type.TileHeight >= corpseType.TileHeight);
+
+	// Update sight for new corpse
+	// We have to unmark BEFORE changing the type.
+	// Always do that, since types can have different vision properties.
+
+	unit.Remove(NULL);
+	unit.Type = &corpseType;
+	unit.Stats = &type.Stats[unit.Player->Index];
+	unit.Place(unit.tilePos);
+
+	unit.SubAction = 0;
+	unit.Frame = 0;
+	UnitUpdateHeading(unit);
+	AnimateActionDie(unit); // with new corpse.
+	return false;
+}
+
+
 /**
 **  Unit dies!
 **
@@ -57,48 +123,8 @@ void HandleActionDie(COrder& order, CUnit &unit)
 {
 	Assert(order.Action == UnitActionDie);
 
-	// Show death animation
-	if (unit.Type->Animations && unit.Type->Animations->Death[unit.DamagedType]) {
-		UnitShowAnimation(unit, unit.Type->Animations->Death[unit.DamagedType]);
-	}
-	else if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) {
-		UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]);
-	} else {
-		// some units has no death animation
-		unit.Anim.Unbreakable = 0;
-	}
-
-	if (unit.Anim.Unbreakable) {
-		return;
-	}
-	// Die sequence terminated, generate corpse.
-	if (!unit.Type->CorpseType) {
-		// We may be in the cache if we just finished out death animation
-		// even though there is no corpse.
-		// (unit.Type->Animations && unit.Type->Animations->Death)
-		// Remove us from the map to be safe
-		unit.Remove(NULL);
-		unit.Release();
-		return;
-	}
-
-	Assert(unit.Type->TileWidth >= unit.Type->CorpseType->TileWidth &&
-		unit.Type->TileHeight >= unit.Type->CorpseType->TileHeight);
-
-	// Update sight for new corpse
-	// We have to unmark BEFORE changing the type.
-	// Always do that, since types can have different vision properties.
-
-	unit.Remove(NULL);
-	unit.Type = unit.Type->CorpseType;
-	unit.Stats = &unit.Type->Stats[unit.Player->Index];
-	unit.Place(unit.tilePos);
-
-	unit.SubAction = 0;
-	unit.Frame = 0;
-	UnitUpdateHeading(unit);
-	if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) {
-		UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]);
+	if (order.Execute(unit)) {
+		unit.ClearAction();
 	}
 }
 
diff --git a/src/action/action_patrol.cpp b/src/action/action_patrol.cpp
index 7e5cceafa..9b4b1cfc2 100644
--- a/src/action/action_patrol.cpp
+++ b/src/action/action_patrol.cpp
@@ -42,26 +42,97 @@
 #include "actions.h"
 #include "pathfinder.h"
 #include "map.h"
+#include "iolib.h"
+#include "script.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
 ----------------------------------------------------------------------------*/
 
-extern bool AutoRepair(CUnit &unit);
-extern bool AutoCast(CUnit &unit);
 
-/**
-**  Swap the patrol points.
-*/
-static void SwapPatrolPoints(CUnit &unit)
+/* virtual */ void COrder_Patrol::Save(CFile &file, const CUnit &unit) const
 {
-	COrderPtr order = unit.CurrentOrder();
+	file.printf("{\"action-patrol\",");
 
-	std::swap(order->Arg1.Patrol.x, order->goalPos.x);
-	std::swap(order->Arg1.Patrol.y, order->goalPos.y);
+	file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
+	file.printf(" \"range\", %d,", this->Range);
 
-	unit.CurrentOrder()->Data.Move.Cycles = 0; //moving counter
-	unit.CurrentOrder()->NewResetPath();
+	file.printf(" \"patrol\", {%d, %d},\n  ", this->WayPoint.x, this->WayPoint.y);
+	SaveDataMove(file);
+	file.printf("}");
+}
+
+/* virtual */ bool COrder_Patrol::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
+{
+	if (ParseMoveData(l, j, value)) {
+		return true;
+	} else if (!strcmp(value, "patrol")) {
+		++j;
+		lua_rawgeti(l, -1, j + 1);
+		CclGetPos(l, &this->WayPoint.x , &this->WayPoint.y);
+		lua_pop(l, 1);
+	} else {
+		return false;
+	}
+	return true;
+}
+
+/* virtual */ bool COrder_Patrol::Execute(CUnit &unit)
+{
+	if (unit.Wait) {
+		unit.Wait--;
+		return false;
+	}
+
+	if (!unit.SubAction) { // first entry.
+		this->Data.Move.Cycles = 0; //moving counter
+		this->NewResetPath();
+		unit.SubAction = 1;
+	}
+
+	switch (DoActionMove(unit)) {
+		case PF_FAILED:
+			unit.SubAction = 1;
+			break;
+		case PF_UNREACHABLE:
+			// Increase range and try again
+			unit.SubAction = 1;
+			if (this->CheckRange()) {
+				this->Range++;
+				break;
+			}
+			// FALL THROUGH
+		case PF_REACHED:
+			unit.SubAction = 1;
+			this->Range = 0;
+			std::swap(this->WayPoint, this->goalPos);
+
+			this->Data.Move.Cycles = 0; //moving counter
+			this->NewResetPath();
+			break;
+		case PF_WAIT:
+			// Wait for a while then give up
+			unit.SubAction++;
+			if (unit.SubAction == 5) {
+				unit.SubAction = 1;
+				this->Range = 0;
+				std::swap(this->WayPoint, this->goalPos);
+
+				this->Data.Move.Cycles = 0; //moving counter
+				this->NewResetPath();
+			}
+			break;
+		default: // moving
+			unit.SubAction = 1;
+			break;
+	}
+
+	if (!unit.Anim.Unbreakable) {
+		if (AutoAttack(unit, false) || AutoRepair(unit) || AutoCast(unit)) {
+			return true;
+		}
+	}
+	return false;
 }
 
 /**
@@ -77,76 +148,10 @@ static void SwapPatrolPoints(CUnit &unit)
 */
 void HandleActionPatrol(COrder& order, CUnit &unit)
 {
-	if (unit.Wait) {
-		unit.Wait--;
-		return;
-	}
+	Assert(order.Action == UnitActionPatrol);
 
-	if (!unit.SubAction) { // first entry.
-		order.Data.Move.Cycles = 0; //moving counter
-		order.NewResetPath();
-		unit.SubAction = 1;
-	}
-
-	switch (DoActionMove(unit)) {
-		case PF_FAILED:
-			unit.SubAction = 1;
-			break;
-		case PF_UNREACHABLE:
-			// Increase range and try again
-			unit.SubAction = 1;
-			if (order.CheckRange()) {
-				order.Range++;
-				break;
-			}
-			// FALL THROUGH
-		case PF_REACHED:
-			unit.SubAction = 1;
-			order.Range = 0;
-			SwapPatrolPoints(unit);
-			break;
-		case PF_WAIT:
-			// Wait for a while then give up
-			unit.SubAction++;
-			if (unit.SubAction == 5) {
-				unit.SubAction = 1;
-				order.Range = 0;
-				SwapPatrolPoints(unit);
-			}
-			break;
-		default: // moving
-			unit.SubAction = 1;
-			break;
-	}
-
-	if (!unit.Anim.Unbreakable) {
-		//
-		// Attack any enemy in reaction range.
-		//  If don't set the goal, the unit can then choose a
-		//  better goal if moving nearer to enemy.
-		//
-		if (unit.Type->CanAttack) {
-			const CUnit *goal = AttackUnitsInReactRange(unit);
-			if (goal) {
-				// Save current command to come back.
-				COrder *savedOrder = order.Clone();
-
-				DebugPrint("Patrol attack %d\n" _C_ UnitNumber(*goal));
-				CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
-
-				if (unit.StoreOrder(savedOrder) == false) {
-					delete savedOrder;
-					savedOrder = NULL;
-				}
-				unit.ClearAction();
-				return;
-			}
-		}
-
-		// Look for something to auto repair or auto cast
-		if (AutoRepair(unit) || AutoCast(unit)) {
-			return;
-		}
+	if (order.Execute(unit)) {
+		unit.ClearAction();
 	}
 }
 
diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp
index 700c59e59..4fa71899b 100644
--- a/src/action/action_research.cpp
+++ b/src/action/action_research.cpp
@@ -54,11 +54,6 @@
 --  Functions
 ----------------------------------------------------------------------------*/
 
-/* virtual */ COrder_Research *COrder_Research::Clone() const
-{
-	return new COrder_Research(*this);
-}
-
 /* virtual */ void COrder_Research::Save(CFile &file, const CUnit &unit) const
 {
 	file.printf("{\"action-research\"");
diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp
index 22fbd2c5a..6276a4da2 100644
--- a/src/action/action_spellcast.cpp
+++ b/src/action/action_spellcast.cpp
@@ -62,11 +62,6 @@
 --  Functions
 ----------------------------------------------------------------------------*/
 
-/* virtual */ COrder_SpellCast *COrder_SpellCast::Clone() const
-{
-	return new COrder_SpellCast(*this);
-}
-
 /* virtual */ void COrder_SpellCast::Save(CFile &file, const CUnit &unit) const
 {
 	file.printf("{\"action-spell-cast\",");
@@ -94,7 +89,9 @@
 
 /* virtual */ bool COrder_SpellCast::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
 {
-	if (!strcmp(value, "spell")) {
+	if (ParseMoveData(l, j, value)) {
+		return true;
+	} else if (!strcmp(value, "spell")) {
 		++j;
 		lua_rawgeti(l, -1, j + 1);
 		this->Spell = SpellTypeByIdent(LuaToString(l, -1));
diff --git a/src/action/action_stand.cpp b/src/action/action_stand.cpp
index 30a4136f8..22c830f95 100644
--- a/src/action/action_stand.cpp
+++ b/src/action/action_stand.cpp
@@ -38,19 +38,53 @@
 #include "stratagus.h"
 #include "unit.h"
 #include "actions.h"
+#include "iolib.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
 ----------------------------------------------------------------------------*/
 
+
+/* virtual */ void COrder_StandGround::Save(CFile &file, const CUnit &unit) const
+{
+	file.printf("{\"action-stand-ground\"");
+	if (this->HasGoal()) {
+		CUnit &goal = *this->GetGoal();
+		if (goal.Destroyed) {
+			/* this unit is destroyed so it's not in the global unit
+			 * array - this means it won't be saved!!! */
+			printf ("FIXME: storing destroyed Goal - loading will fail.\n");
+		}
+		file.printf(", \"goal\", \"%s\"", UnitReference(goal).c_str());
+	}
+	file.printf("}");
+}
+
+/* virtual */ bool COrder_StandGround::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
+{
+	return false;
+}
+
+/* virtual */ bool COrder_StandGround::Execute(CUnit &unit)
+{
+	ActionStillGeneric(unit, true);
+
+	return false;
+}
+
+
 /**
 **  Unit stands ground!
 **
 **  @param unit  Action handled for this unit pointer.
 */
-void HandleActionStandGround(COrder& /*order*/, CUnit &unit)
+void HandleActionStandGround(COrder& order, CUnit &unit)
 {
-	ActionStillGeneric(unit, true);
+	Assert(order.Action == UnitActionStandGround);
+
+	if (order.Execute(unit)) {
+		unit.ClearAction();
+	}
 }
 
 //@}
diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp
index ead9d330d..8f8614154 100644
--- a/src/action/action_still.cpp
+++ b/src/action/action_still.cpp
@@ -47,11 +47,35 @@
 #include "pathfinder.h"
 #include "spells.h"
 #include "player.h"
+#include "iolib.h"
 
 #define SUB_STILL_INIT		0
 #define SUB_STILL_STANDBY	1
 #define SUB_STILL_ATTACK	2
 
+
+
+/* virtual */ void COrder_Still::Save(CFile &file, const CUnit &unit) const
+{
+	file.printf("{\"action-still\"");
+	if (this->HasGoal()) {
+		CUnit &goal = *this->GetGoal();
+		if (goal.Destroyed) {
+			/* this unit is destroyed so it's not in the global unit
+			 * array - this means it won't be saved!!! */
+			printf ("FIXME: storing destroyed Goal - loading will fail.\n");
+		}
+		file.printf(", \"goal\", \"%s\"", UnitReference(goal).c_str());
+	}
+	file.printf("}");
+}
+
+/* virtual */ bool COrder_Still::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
+{
+	return false;
+}
+
+
 /*----------------------------------------------------------------------------
 --  Functions
 ----------------------------------------------------------------------------*/
@@ -239,66 +263,81 @@ bool AutoRepair(CUnit &unit)
 {
 	const int repairRange = unit.Type->Variable[AUTOREPAIRRANGE_INDEX].Value;
 
-	if (unit.AutoRepair && repairRange) {
-		CUnit *repairedUnit = UnitToRepairInRange(unit, repairRange);
-
-		if (repairedUnit != NoUnitP) {
-			const Vec2i invalidPos = {-1, -1};
-			COrder *savedOrder = unit.CurrentOrder()->Clone();
-
-			//Command* will clear unit.SavedOrder
-			CommandRepair(unit, invalidPos, repairedUnit, FlushCommands);
-			if (unit.StoreOrder(savedOrder) == false) {
-				delete savedOrder;
-				savedOrder = NULL;
-			}
-			return true;
-		}
+	if (unit.AutoRepair == false || repairRange == 0) {
+		return false;
 	}
-	return false;
+	CUnit *repairedUnit = UnitToRepairInRange(unit, repairRange);
+
+	if (repairedUnit == NoUnitP) {
+		return false;
+	}
+	const Vec2i invalidPos = {-1, -1};
+	COrder *savedOrder = unit.CurrentOrder()->Clone();
+
+	//Command* will clear unit.SavedOrder
+	CommandRepair(unit, invalidPos, repairedUnit, FlushCommands);
+	if (unit.StoreOrder(savedOrder) == false) {
+		delete savedOrder;
+		savedOrder = NULL;
+	}
+	return true;
 }
 
 /**
 **  Auto attack nearby units if possible
 */
-static bool AutoAttack(CUnit &unit, bool stand_ground)
+bool AutoAttack(CUnit &unit, bool stand_ground)
 {
-	CUnit *goal;
-
-	// Cowards and invisible units don't attack unless ordered.
-	if (unit.IsAgressive()) {
-		// Normal units react in reaction range.
-		if (!stand_ground && !unit.Removed && unit.CanMove()) {
-			if ((goal = AttackUnitsInReactRange(unit))) {
-				// Weak goal, can choose other unit, come back after attack
-				CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
-				COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos);
-
-				if (unit.StoreOrder(savedOrder) == false) {
-					delete savedOrder;
-				}
-				return true;
-			}
-		// Removed units can only attack in AttackRange, from bunker
-		} else {
-			if ((goal = AttackUnitsInRange(unit))) {
-				CUnit *temp = unit.CurrentOrder()->GetGoal();
-				if (temp && temp->CurrentAction() == UnitActionDie) {
-					unit.CurrentOrder()->ClearGoal();
-					temp = NoUnitP;
-				}
-				if (unit.SubAction < SUB_STILL_ATTACK || temp != goal) {
-					// New target.
-					unit.CurrentOrder()->SetGoal(goal);
-					unit.State = 0;
-					unit.SubAction = SUB_STILL_ATTACK; // Mark attacking.
-					UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
-				}
-				return true;
-			}
-		}
+	if (unit.Type->CanAttack == false) {
+		return false;
 	}
-	return false;
+
+	if (stand_ground || unit.Removed || unit.CanMove() == false) {
+		// Removed units can only attack in AttackRange, from bunker
+		CUnit *goal = AttackUnitsInRange(unit);
+
+		if (goal == NULL) {
+			return false;
+		}
+
+		CUnit *temp = unit.CurrentOrder()->GetGoal();
+		if (temp && temp->CurrentAction() == UnitActionDie) {
+			unit.CurrentOrder()->ClearGoal();
+			temp = NoUnitP;
+		}
+		if (unit.SubAction < SUB_STILL_ATTACK || temp != goal) {
+			// New target.
+			unit.CurrentOrder()->SetGoal(goal);
+			unit.State = 0;
+			unit.SubAction = SUB_STILL_ATTACK; // Mark attacking.
+			UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
+		}
+		return true;
+	}
+	// Normal units react in reaction range.
+	CUnit *goal = AttackUnitsInReactRange(unit);
+
+	if (goal == NULL) {
+		return false;
+	}
+
+	COrder *savedOrder;
+
+	if (unit.SavedOrder != NULL) {
+		savedOrder = unit.SavedOrder->Clone();
+	} else if (unit.CurrentAction() == UnitActionStill) {
+		savedOrder = COrder::NewActionAttack(unit, unit.tilePos);
+	} else {
+		savedOrder = unit.CurrentOrder()->Clone();
+	}
+
+	// Weak goal, can choose other unit, come back after attack
+	CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
+
+	if (unit.StoreOrder(savedOrder) == false) {
+		delete savedOrder;
+	}
+	return true;
 }
 
 void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground)
@@ -360,8 +399,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground)
 		return;
 	}
 
-	switch (unit.SubAction)
-	{
+	switch (unit.SubAction) {
 		case SUB_STILL_INIT: //first entry
 			MapMarkUnitGuard(unit);
 			unit.SubAction = SUB_STILL_STANDBY;
@@ -378,7 +416,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground)
 		return;
 	}
 
-	if (AutoAttack(unit, stand_ground)
+	if ((unit.IsAgressive() && AutoAttack(unit, stand_ground))
 		|| AutoCast(unit)
 		|| AutoRepair(unit)
 		|| MoveRandomly(unit)) {
@@ -391,9 +429,18 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground)
 **
 **  @param unit  Unit pointer for still action.
 */
-void HandleActionStill(COrder& /*order*/, CUnit &unit)
+void HandleActionStill(COrder& order, CUnit &unit)
 {
-	ActionStillGeneric(unit, false);
+	Assert(order.Action == UnitActionStill);
+
+	order.Execute(unit);
 }
 
+/* virtual */ bool COrder_Still::Execute(CUnit &unit)
+{
+	ActionStillGeneric(unit, false);
+	return false;
+}
+
+
 //@}
diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 9cf0349db..c38ed5f68 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -92,9 +92,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target)
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionAttack;
+	COrder *order = new COrder(UnitActionAttack);
 
 	if (target.Destroyed) {
 		order->goalPos = target.tilePos + target.Type->GetHalfTileSize();
@@ -111,9 +109,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 {
 	Assert(Map.Info.IsPointOnMap(dest));
 
-	COrder *order = new COrder;
-
-	order->Action = UnitActionAttack;
+	COrder *order = new COrder(UnitActionAttack);
 
 	if (Map.WallOnMap(dest) && Map.IsFieldExplored(*attacker.Player, dest)) {
 		// FIXME: look into action_attack.cpp about this ugly problem
@@ -128,9 +124,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionAttackGround);
 
-	order->Action = UnitActionAttackGround;
 	order->goalPos = dest;
 	order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max;
 	order->MinRange = attacker.Type->MinAttackRange;
@@ -141,9 +136,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionBoard(CUnit &unit)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionBoard);
 
-	order->Action = UnitActionBoard;
 	order->SetGoal(&unit);
 	order->Range = 1;
 
@@ -153,9 +147,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building)
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionBuild;
+	COrder *order = new COrder(UnitActionBuild);
 
 	order->goalPos = pos;
 	order->Width = building.TileWidth;
@@ -200,17 +192,13 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionDie()
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionDie;
-	return order;
+	return new COrder_Die;
 }
 
 /* static */ COrder* COrder::NewActionFollow(CUnit &dest)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionFollow);
 
-	order->Action = UnitActionFollow;
 	// Destination could be killed.
 	// Should be handled in action, but is not possible!
 	// Unit::Refs is used as timeout counter.
@@ -227,9 +215,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionMove(const Vec2i &pos)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionMove);
 
-	order->Action = UnitActionMove;
 	order->goalPos = pos;
 
 	return order;
@@ -241,20 +228,18 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 	Assert(Map.Info.IsPointOnMap(currentPos));
 	Assert(Map.Info.IsPointOnMap(dest));
 
-	COrder *order = new COrder;
+	COrder_Patrol *order = new COrder_Patrol();
 
-	order->Action = UnitActionPatrol;
 	order->goalPos = dest;
-	order->Arg1.Patrol = currentPos;
+	order->WayPoint = currentPos;
 
 	return order;
 }
 
 /* static */ COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionRepair);
 
-	order->Action = UnitActionRepair;
 	if (target.Destroyed) {
 		order->goalPos = target.tilePos + target.Type->GetHalfTileSize();
 	} else {
@@ -268,9 +253,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 {
 	Assert(Map.Info.IsPointOnMap(pos));
 
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionRepair);
 
-	order->Action = UnitActionRepair;
 	order->goalPos = pos;
 	return order;
 }
@@ -293,11 +277,9 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionResource(CUnit &harvester, const Vec2i &pos)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionResource);
 	Vec2i ressourceLoc;
 
-	order->Action = UnitActionResource;
-
 	//  Find the closest piece of wood next to a tile where the unit can move
 	if (!FindTerrainType(0, (harvester.Type->MovementMask), 1, 20, harvester.Player, pos, &ressourceLoc)) {
 		DebugPrint("FIXME: Give up???\n");
@@ -319,9 +301,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionResource(CUnit &mine)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionResource);
 
-	order->Action = UnitActionResource;
 	order->SetGoal(&mine);
 	order->Range = 1;
 
@@ -332,9 +313,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionReturnGoods(CUnit *depot)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionReturnGoods);
 
-	order->Action = UnitActionReturnGoods;
 	// Destination could be killed. NETWORK!
 	if (depot && !depot->Destroyed) {
 		order->SetGoal(depot);
@@ -374,19 +354,12 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionStandGround()
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionStandGround;
-	return order;
+	return new COrder_StandGround;
 }
 
-
 /* static */ COrder* COrder::NewActionStill()
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionStill;
-	return order;
+	return new COrder_Still;
 }
 
 
@@ -394,9 +367,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionTrain);
 
-	order->Action = UnitActionTrain;
 	order->Arg1.Type = &type;
 	// FIXME: if you give quick an other order, the resources are lost!
 	trainer.Player->SubUnitType(type);
@@ -406,9 +378,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionTransformInto(CUnitType &type)
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionTransformInto;
+	COrder *order = new COrder(UnitActionTransformInto);
 
 	order->Arg1.Type = &type;
 
@@ -417,9 +387,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what)
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder(UnitActionUnload);
 
-	order->Action = UnitActionUnload;
 	order->goalPos = pos;
 	if (what && !what->Destroyed) {
 		order->SetGoal(what);
@@ -430,9 +399,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type)
 {
-	COrder *order = new COrder;
-
-	order->Action = UnitActionUpgradeTo;
+	COrder *order = new COrder(UnitActionUpgradeTo);
 
 	// FIXME: if you give quick an other order, the resources are lost!
 	unit.Player->SubUnitType(type);
@@ -441,152 +408,10 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 	return order;
 }
 
-#if 1 // currently needed for parsing
-/* static */ COrder* COrder::NewActionAttack()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionAttack;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionAttackGround()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionAttackGround;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionBoard()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionBoard;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionBuild()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionBuild;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionBuilt()
-{
-	COrder *order = new COrder_Built;
-
-	order->Action = UnitActionBuilt;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionFollow()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionFollow;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionMove()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionMove;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionPatrol()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionPatrol;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionRepair()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionRepair;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionResearch()
-{
-	COrder_Research *order = new COrder_Research;
-
-	order->Action = UnitActionResearch;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionResource()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionResource;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionReturnGoods()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionReturnGoods;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionSpellCast()
-{
-	COrder *order = new COrder_SpellCast;
-
-	order->Action = UnitActionSpellCast;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionTrain()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionTrain;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionTransformInto()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionTransformInto;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionUnload()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionUnload;
-	return order;
-}
-
-/* static */ COrder* COrder::NewActionUpgradeTo()
-{
-	COrder *order = new COrder;
-
-	order->Action = UnitActionUpgradeTo;
-	return order;
-}
-
-#endif
-
-
-
 COrder* COrder::Clone() const
 {
-	COrder *clone = new COrder();
+	COrder *clone = new COrder(this->Action);
 
-	clone->Action = this->Action;
 	clone->Range = this->Range;
 	clone->MinRange = this->MinRange;
 	clone->Width = this->Width;
diff --git a/src/include/actions.h b/src/include/actions.h
index 93c4e87f4..4f9440723 100644
--- a/src/include/actions.h
+++ b/src/include/actions.h
@@ -102,8 +102,8 @@ struct lua_State;
 class COrder
 {
 public:
-	COrder() : Goal(NULL), Range(0), MinRange(0), Width(0),
-		Height(0), Action(UnitActionNone), CurrentResource(0)
+	COrder(int action) : Goal(NULL), Range(0), MinRange(0), Width(0),
+		Height(0), Action(action), CurrentResource(0)
 	{
 		goalPos.x = -1;
 		goalPos.y = -1;
@@ -154,7 +154,7 @@ public:
 	*/
 	void NewResetPath() { Data.Move.Fast = 1; Data.Move.Length = 0; }
 	void SaveDataMove(CFile &file) const;
-
+	bool ParseMoveData(lua_State *l, int &j, const char *value);
 
 	bool OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/);
 	void AiUnitKilled(CUnit &unit);
@@ -165,7 +165,6 @@ public:
 	static COrder* NewActionAttackGround(const CUnit &attacker, const Vec2i &dest);
 	static COrder* NewActionBoard(CUnit &unit);
 	static COrder* NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building);
-	static COrder* NewActionBuilt();
 	static COrder* NewActionBuilt(CUnit &builder, CUnit &unit);
 	static COrder* NewActionDie();
 	static COrder* NewActionFollow(CUnit &dest);
@@ -186,22 +185,19 @@ public:
 	static COrder* NewActionUpgradeTo(CUnit &unit, CUnitType &type);
 
 #if 1 // currently needed for parsing
-	static COrder* NewActionAttack();
-	static COrder* NewActionAttackGround();
-	static COrder* NewActionBoard();
-	static COrder* NewActionBuild();
-	static COrder* NewActionFollow();
-	static COrder* NewActionMove();
-	static COrder* NewActionPatrol();
-	static COrder* NewActionRepair();
-	static COrder* NewActionResearch();
-	static COrder* NewActionResource();
-	static COrder* NewActionReturnGoods();
-	static COrder* NewActionSpellCast();
-	static COrder* NewActionTrain();
-	static COrder* NewActionTransformInto();
-	static COrder* NewActionUnload();
-	static COrder* NewActionUpgradeTo();
+	static COrder* NewActionAttack() { return new COrder(UnitActionAttack); }
+	static COrder* NewActionAttackGround() { return new COrder(UnitActionAttackGround); }
+	static COrder* NewActionBoard() { return new COrder(UnitActionBoard); }
+	static COrder* NewActionBuild() { return new COrder(UnitActionBuild); }
+	static COrder* NewActionFollow() { return new COrder(UnitActionFollow); }
+	static COrder* NewActionMove() { return new COrder(UnitActionMove); }
+	static COrder* NewActionRepair() { return new COrder(UnitActionRepair); }
+	static COrder* NewActionResource() { return new COrder(UnitActionResource); }
+	static COrder* NewActionReturnGoods() { return new COrder(UnitActionReturnGoods); }
+	static COrder* NewActionTrain() { return new COrder(UnitActionTrain); }
+	static COrder* NewActionTransformInto() { return new COrder(UnitActionTransformInto); }
+	static COrder* NewActionUnload() { return new COrder(UnitActionUnload); }
+	static COrder* NewActionUpgradeTo() { return new COrder(UnitActionUpgradeTo); }
 #endif
 
 private:
@@ -218,7 +214,6 @@ public:
 	Vec2i goalPos;          /// or tile coordinate of destination
 
 	union {
-		Vec2i Patrol; /// position for patroling.
 		struct {
 			Vec2i Pos; /// position for terrain resource.
 			CUnit *Mine;
@@ -257,7 +252,9 @@ class COrder_Built : public COrder
 {
 	friend COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit);
 public:
-	virtual COrder_Built *Clone() const;
+	COrder_Built() : COrder(UnitActionBuilt) {}
+
+	virtual COrder_Built *Clone() const { return new COrder_Built(*this); }
 
 	virtual void Save(CFile &file, const CUnit &unit) const;
 	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
@@ -289,11 +286,45 @@ private:
 };
 
 
+class COrder_Die : public COrder
+{
+public:
+	COrder_Die() : COrder(UnitActionDie) {}
+
+	virtual COrder_Die *Clone() const { return new COrder_Die(*this); }
+
+	virtual void Save(CFile &file, const CUnit &unit) const;
+	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
+
+	virtual bool Execute(CUnit &unit);
+};
+
+
+class COrder_Patrol : public COrder
+{
+	friend COrder* COrder::NewActionPatrol(const Vec2i &currentPos, const Vec2i &dest);
+public:
+	COrder_Patrol() : COrder(UnitActionPatrol) {}
+
+	virtual COrder_Patrol *Clone() const { return new COrder_Patrol(*this); }
+
+	virtual void Save(CFile &file, const CUnit &unit) const;
+	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
+
+	virtual bool Execute(CUnit &unit);
+
+	const Vec2i& GetWayPoint() const { return WayPoint; }
+private:
+	Vec2i WayPoint; /// position for patroling.
+};
+
 
 class COrder_Research : public COrder
 {
 public:
-	virtual COrder_Research *Clone() const;
+	COrder_Research() : COrder(UnitActionResearch), Upgrade(NULL) {}
+
+	virtual COrder_Research *Clone() const { return new COrder_Research(*this); }
 
 	virtual void Save(CFile &file, const CUnit &unit) const;
 	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
@@ -309,10 +340,12 @@ private:
 	CUpgrade *Upgrade;
 };
 
-class COrder_SpellCast: public COrder
+class COrder_SpellCast : public COrder
 {
 public:
-	virtual COrder_SpellCast *Clone() const;
+	COrder_SpellCast() : COrder(UnitActionSpellCast), Spell(NULL) {}
+
+	virtual COrder_SpellCast *Clone() const { return new COrder_SpellCast(*this); }
 
 	virtual void Save(CFile &file, const CUnit &unit) const;
 	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
@@ -329,6 +362,36 @@ private:
 
 
 
+
+class COrder_StandGround : public COrder
+{
+public:
+	COrder_StandGround() : COrder(UnitActionStandGround) {}
+
+	virtual COrder_StandGround *Clone() const { return new COrder_StandGround(*this); }
+
+	virtual void Save(CFile &file, const CUnit &unit) const;
+	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
+
+	virtual bool Execute(CUnit &unit);
+};
+
+class COrder_Still : public COrder
+{
+public:
+	COrder_Still() : COrder(UnitActionStill) {}
+
+	virtual COrder_Still *Clone() const { return new COrder_Still(*this); }
+
+	virtual void Save(CFile &file, const CUnit &unit) const;
+	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
+
+	virtual bool Execute(CUnit &unit);
+};
+
+
+
+
 /*----------------------------------------------------------------------------
 --  Variables
 ----------------------------------------------------------------------------*/
@@ -413,6 +476,10 @@ extern void DropResource(CUnit &unit);
 extern void ResourceGiveUp(CUnit &unit);
 extern int GetNumWaitingWorkers(const CUnit &mine);
 extern void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground);
+extern bool AutoAttack(CUnit &unit, bool stand_ground);
+extern bool AutoRepair(CUnit &unit);
+extern bool AutoCast(CUnit &unit);
+
 extern void UnHideUnit(CUnit &unit);
 
 typedef void HandleActionFunc(COrder& order, CUnit &unit);
diff --git a/src/include/script.h b/src/include/script.h
index d241a44a4..62bb2ce91 100644
--- a/src/include/script.h
+++ b/src/include/script.h
@@ -287,7 +287,28 @@ extern int CclCommand(const std::string &command, bool exitOnError = true);
 
 CUnit *CclGetUnitFromRef(lua_State *l);
 
-
+/**
+**  Get a position from lua state
+**
+**  @param l  Lua state.
+**  param x  pointer to output x position.
+**  @param y  pointer to output y position.
+**
+**  @return   The unit pointer
+*/
+template <typename T>
+static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1)
+{
+	if (!lua_istable(l, offset) || lua_objlen(l, offset) != 2) {
+		LuaError(l, "incorrect argument");
+	}
+	lua_rawgeti(l, offset, 1);
+	*x = LuaToNumber(l, -1);
+	lua_pop(l, 1);
+	lua_rawgeti(l, offset, 2);
+	*y = LuaToNumber(l, -1);
+	lua_pop(l, 1);
+}
 
 extern NumberDesc *Damage;  /// Damage calculation for missile.
 
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index a913f54bd..504919800 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -132,29 +132,6 @@ CUnit *CclGetUnitFromRef(lua_State *l)
 	return UnitSlots[slot];
 }
 
-/**
-**  Get a position from lua state
-**
-**  @param l  Lua state.
-**	@param x  pointer to output x position.
-**	@param y  pointer to output y position.
-**
-**  @return   The unit pointer
-*/
-template <typename T>
-static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1)
-{
-	if (!lua_istable(l, offset) || lua_objlen(l, offset) != 2) {
-		LuaError(l, "incorrect argument");
-	}
-	lua_rawgeti(l, offset, 1);
-	*x = LuaToNumber(l, -1);
-	lua_pop(l, 1);
-	lua_rawgeti(l, offset, 2);
-	*y = LuaToNumber(l, -1);
-	lua_pop(l, 1);
-}
-
 /**
 **  Parse res worker data
 **
@@ -251,55 +228,6 @@ static void CclParseTrain(lua_State *l, COrderPtr order)
 	}
 }
 
-/**
-**  Parse stored data for move order
-**
-**  @param l     Lua state.
-**  @param unit  Unit pointer which should be filled with the data.
-*/
-static void CclParseMove(lua_State *l, COrderPtr order)
-{
-	const char *value;
-	int args;
-	int j;
-
-	if (!lua_istable(l, -1)) {
-		LuaError(l, "incorrect argument");
-	}
-	args = lua_objlen(l, -1);
-	for (j = 0; j < args; ++j) {
-		lua_rawgeti(l, -1, j + 1);
-		value = LuaToString(l, -1);
-		lua_pop(l, 1);
-		++j;
-		if (!strcmp(value, "cycles")) {
-			lua_rawgeti(l, -1, j + 1);
-			order->Data.Move.Cycles = LuaToNumber(l, -1);
-			lua_pop(l, 1);
-		} else if (!strcmp(value, "fast")) {
-			order->Data.Move.Fast = 1;
-			--j;
-		} else if (!strcmp(value, "path")) {
-			int subargs;
-			int k;
-
-			lua_rawgeti(l, -1, j + 1);
-			if (!lua_istable(l, -1)) {
-				LuaError(l, "incorrect argument");
-			}
-			subargs = lua_objlen(l, -1);
-			for (k = 0; k < subargs; ++k) {
-				lua_rawgeti(l, -1, k + 1);
-				order->Data.Move.Path[k] = LuaToNumber(l, -1);
-				lua_pop(l, 1);
-			}
-			order->Data.Move.Length = subargs;
-			lua_pop(l, 1);
-		} else {
-			LuaError(l, "ParseMove: Unsupported tag: %s" _C_ value);
-		}
-	}
-}
 
 bool COrder::ParseGenericData(lua_State *l, int &j, const char *value)
 {
@@ -339,6 +267,52 @@ bool COrder::ParseGenericData(lua_State *l, int &j, const char *value)
 	return true;
 }
 
+
+bool COrder::ParseMoveData(lua_State *l, int &j, const char *value)
+{
+	if (strcmp(value, "data-move") != 0) {
+		return false;
+	}
+	++j;
+	lua_rawgeti(l, -1, j + 1);
+
+	if (!lua_istable(l, -1)) {
+		LuaError(l, "incorrect argument");
+	}
+	const int args = 1 + lua_objlen(l, -1);
+	for (int i = 1; i < args; ++i) {
+		lua_rawgeti(l, -1, i);
+		const char *tag = LuaToString(l, -1);
+		lua_pop(l, 1);
+		++i;
+		if (!strcmp(tag, "cycles")) {
+			lua_rawgeti(l, -1, i);
+			this->Data.Move.Cycles = LuaToNumber(l, -1);
+			lua_pop(l, 1);
+		} else if (!strcmp(tag, "fast")) {
+			this->Data.Move.Fast = 1;
+			--i;
+		} else if (!strcmp(tag, "path")) {
+			lua_rawgeti(l, -1, i);
+			if (!lua_istable(l, -1)) {
+				LuaError(l, "incorrect argument _");
+			}
+			const int subargs = lua_objlen(l, -1);
+			for (int k = 0; k < subargs; ++k) {
+				lua_rawgeti(l, -1, k + 1);
+				this->Data.Move.Path[k] = LuaToNumber(l, -1);
+				lua_pop(l, 1);
+			}
+			this->Data.Move.Length = subargs;
+			lua_pop(l, 1);
+		} else {
+			LuaError(l, "ParseMove: Unsupported tag: %s" _C_ tag);
+		}
+	}
+	lua_pop(l, 1);
+	return true;
+}
+
 bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
 {
 	if (!strcmp(value, "type")) {
@@ -347,11 +321,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU
 		this->Arg1.Type = UnitTypeByIdent(LuaToString(l, -1));
 		lua_pop(l, 1);
 
-	} else if (!strcmp(value, "patrol")) {
-		++j;
-		lua_rawgeti(l, -1, j + 1);
-		CclGetPos(l, &this->Arg1.Patrol.x , &this->Arg1.Patrol.y);
-		lua_pop(l, 1);
 	} else if (!strcmp(value, "current-resource")) {
 		++j;
 		lua_rawgeti(l, -1, j + 1);
@@ -387,11 +356,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU
 		lua_rawgeti(l, -1, j + 1);
 		CclParseTrain(l, this);
 		lua_pop(l, 1);
-	} else if (!strcmp(value, "data-move")) {
-		++j;
-		lua_rawgeti(l, -1, j + 1);
-		CclParseMove(l, this);
-		lua_pop(l, 1);
 	} else if (!strcmp(value, "mine")) { /* old save format */
 		int pos;
 		++j;
@@ -439,9 +403,9 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
 	lua_pop(l, 1);
 
 	if (!strcmp(actiontype, "action-still")) {
-		*orderPtr = COrder::NewActionStill();
+		*orderPtr = new COrder_Still;
 	} else if (!strcmp(actiontype, "action-stand-ground")) {
-		*orderPtr = COrder::NewActionStandGround();
+		*orderPtr = new COrder_StandGround;
 	} else if (!strcmp(actiontype, "action-follow")) {
 		*orderPtr = COrder::NewActionFollow();
 	} else if (!strcmp(actiontype, "action-move")) {
@@ -451,23 +415,23 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
 	} else if (!strcmp(actiontype, "action-attack-ground")) {
 		*orderPtr = COrder::NewActionAttackGround();
 	} else if (!strcmp(actiontype, "action-die")) {
-		*orderPtr = COrder::NewActionDie();
+		*orderPtr = new COrder_Die;
 	} else if (!strcmp(actiontype, "action-spell-cast")) {
-		*orderPtr = COrder::NewActionSpellCast();
+		*orderPtr = new COrder_SpellCast;
 	} else if (!strcmp(actiontype, "action-train")) {
 		*orderPtr = COrder::NewActionTrain();
 	} else if (!strcmp(actiontype, "action-upgrade-to")) {
 		*orderPtr = COrder::NewActionUpgradeTo();
 	} else if (!strcmp(actiontype, "action-research")) {
-		*orderPtr = COrder::NewActionResearch();
+		*orderPtr = new COrder_Research;
 	} else if (!strcmp(actiontype, "action-built")) {
-		*orderPtr = COrder::NewActionBuilt();
+		*orderPtr = new COrder_Built;
 	} else if (!strcmp(actiontype, "action-board")) {
 		*orderPtr = COrder::NewActionBoard();
 	} else if (!strcmp(actiontype, "action-unload")) {
 		*orderPtr = COrder::NewActionUnload();
 	} else if (!strcmp(actiontype, "action-patrol")) {
-		*orderPtr = COrder::NewActionPatrol();
+		*orderPtr = new COrder_Patrol;
 	} else if (!strcmp(actiontype, "action-build")) {
 		*orderPtr = COrder::NewActionBuild();
 	} else if (!strcmp(actiontype, "action-repair")) {
diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp
index 9fdf3e5f2..6a3050c92 100644
--- a/src/unit/unit_draw.cpp
+++ b/src/unit/unit_draw.cpp
@@ -737,12 +737,15 @@ static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder
 			break;
 
 		case UnitActionPatrol:
+		{
 			Video.DrawLineClip(ColorGreen, pos1.x, pos1.y, pos2.x, pos2.y);
 			e_color = color = ColorBlue;
-			pos1 = CurrentViewport->TilePosToScreen_Center(order.Arg1.Patrol);
+			const COrder_Patrol &orderPatrol = static_cast<const COrder_Patrol&>(order);
+
+			pos1 = CurrentViewport->TilePosToScreen_Center(orderPatrol.GetWayPoint());
 			dest = true;
 			break;
-
+		}
 		case UnitActionRepair:
 			e_color = color = ColorGreen;
 			dest = true;
diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp
index fed0b6265..81e7a4447 100644
--- a/src/unit/unit_save.cpp
+++ b/src/unit/unit_save.cpp
@@ -96,12 +96,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 		case UnitActionNone:
 			file.printf("\"action-none\",");
 			break;
-		case UnitActionStill:
-			file.printf("\"action-still\",");
-			break;
-		case UnitActionStandGround:
-			file.printf("\"action-stand-ground\",");
-			break;
 		case UnitActionFollow:
 			file.printf("\"action-follow\",");
 			break;
@@ -114,9 +108,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 		case UnitActionAttackGround:
 			file.printf("\"action-attack-ground\",");
 			break;
-		case UnitActionDie:
-			file.printf("\"action-die\",");
-			break;
 		case UnitActionTrain:
 			file.printf("\"action-train\",");
 			break;
@@ -129,9 +120,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 		case UnitActionUnload:
 			file.printf("\"action-unload\",");
 			break;
-		case UnitActionPatrol:
-			file.printf("\"action-patrol\",");
-			break;
 		case UnitActionBuild:
 			file.printf("\"action-build\",");
 			break;
@@ -174,9 +162,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 		case UnitActionTransformInto:
 			file.printf(", \"type\", \"%s\"", order.Arg1.Type->Ident.c_str());
 		break;
-		case UnitActionPatrol:
-			file.printf(", \"patrol\", {%d, %d}", order.Arg1.Patrol.x, order.Arg1.Patrol.y);
-			break;
 		case UnitActionResource :
 		case UnitActionReturnGoods :
 			if (order.CurrentResource) {