From 5d4ddd2508665e089997a620c1b1f399fb891da0 Mon Sep 17 00:00:00 2001
From: joris <joris.dauphin@gmail.com>
Date: Fri, 17 Feb 2012 09:05:42 +0100
Subject: [PATCH] Create specific "construtor" for each order.

---
 src/action/action_attack.cpp |   8 +-
 src/action/action_patrol.cpp |   7 +-
 src/action/action_still.cpp  |  12 +-
 src/action/actions.cpp       | 339 ++++++++++++++
 src/action/command.cpp       | 871 ++++++++++++-----------------------
 src/ai/ai.cpp                |   6 +-
 src/include/actions.h        |  36 +-
 src/include/unit.h           |   2 -
 src/stratagus/groups.cpp     |   6 +-
 src/unit/script_unit.cpp     |   9 +-
 src/unit/unit.cpp            |  34 +-
 11 files changed, 681 insertions(+), 649 deletions(-)

diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp
index d3ecf310c..97e76fb67 100644
--- a/src/action/action_attack.cpp
+++ b/src/action/action_attack.cpp
@@ -147,13 +147,7 @@ static int CheckForTargetInRange(CUnit &unit)
 		CUnit *goal = AttackUnitsInReactRange(unit);
 
 		if (goal) {
-			COrder *savedOrder = new COrder();
-
-			savedOrder->Action = order->Action;
-
-			savedOrder->MinRange = 0;//order->MinRange;
-			savedOrder->Range = 0;//order->Range;
-			savedOrder->goalPos = order->goalPos;
+			COrder *savedOrder = COrder::NewActionAttack(unit, order->goalPos);
 
 			if (unit.StoreOrder(savedOrder) == false) {
 				delete savedOrder;
diff --git a/src/action/action_patrol.cpp b/src/action/action_patrol.cpp
index 2218d0ca0..3124199ec 100644
--- a/src/action/action_patrol.cpp
+++ b/src/action/action_patrol.cpp
@@ -131,15 +131,14 @@ void HandleActionPatrol(COrder& order, CUnit &unit)
 				// Save current command to come back.
 				COrder *savedOrder = new COrder(order);
 
+				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();
-				unit.CurrentOrder()->ClearGoal();
-
-				DebugPrint("Patrol attack %d\n" _C_ UnitNumber(*goal));
-				CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
 				return;
 			}
 		}
diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp
index a342b3535..67110c70f 100644
--- a/src/action/action_still.cpp
+++ b/src/action/action_still.cpp
@@ -272,11 +272,7 @@ static bool AutoAttack(CUnit &unit, bool stand_ground)
 			if ((goal = AttackUnitsInReactRange(unit))) {
 				// Weak goal, can choose other unit, come back after attack
 				CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
-				COrder *savedOrder = new COrder;
-
-				savedOrder->Action = UnitActionAttack;
-				savedOrder->Range = 0;
-				savedOrder->goalPos = unit.tilePos;
+				COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos);
 
 				if (unit.StoreOrder(savedOrder) == false) {
 					delete savedOrder;
@@ -316,11 +312,7 @@ void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground)
 			if (goal) {
 				// Weak goal, can choose other unit, come back after attack
 				CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
-				COrder *savedOrder = new COrder;
-
-				savedOrder->Action = UnitActionAttack;
-				savedOrder->Range = 0;
-				savedOrder->goalPos = unit.tilePos;
+				COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos);
 
 				if (unit.StoreOrder(savedOrder) == false) {
 					delete savedOrder;
diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 44c2cdc8e..13c0d7155 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -82,6 +82,345 @@ COrder::COrder(const COrder &rhs): Goal(rhs.Goal), Range(rhs.Range),
 	}
 }
 
+
+
+/* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionAttack;
+
+	if (target.Destroyed) {
+		order->goalPos = target.tilePos + target.Type->GetHalfTileSize();
+	} else {
+		// Removed, Dying handled by action routine.
+		order->SetGoal(&target);
+		order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max;
+		order->MinRange = attacker.Type->MinAttackRange;
+	}
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, const Vec2i &dest)
+{
+	Assert(Map.Info.IsPointOnMap(dest));
+
+	COrder *order = new COrder;
+
+	order->Action = UnitActionAttack;
+
+	if (Map.WallOnMap(dest) && Map.IsFieldExplored(*attacker.Player, dest)) {
+		// FIXME: look into action_attack.cpp about this ugly problem
+		order->goalPos = dest;
+		order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max;
+		order->MinRange = attacker.Type->MinAttackRange;
+	} else {
+		order->goalPos = dest;
+	}
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionAttackGround;
+	order->goalPos = dest;
+	order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max;
+	order->MinRange = attacker.Type->MinAttackRange;
+
+	return order;
+}
+
+
+/* static */ COrder* COrder::NewActionBoard(CUnit &unit)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionBoard;
+	order->SetGoal(&unit);
+	order->Range = 1;
+
+	return order;
+}
+
+
+/* static */ COrder* COrder::NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionBuild;
+
+	order->goalPos = pos;
+	order->Width = building.TileWidth;
+	order->Height = building.TileHeight;
+	if (building.BuilderOutside) {
+		order->Range = builder.Type->RepairRange;
+	} else {
+		// If building inside, but be next to stop
+		if (building.ShoreBuilding && builder.Type->UnitType == UnitTypeLand) {
+				// Peon won't dive :-)
+			order->Range = 1;
+		}
+	}
+	order->Arg1.Type = &building;
+	if (building.BuilderOutside) {
+		order->MinRange = 1;
+	}
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionBuilt()
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionBuilt;
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionDie()
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionDie;
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionFollow(CUnit &dest)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionFollow;
+	// Destination could be killed.
+	// Should be handled in action, but is not possible!
+	// Unit::Refs is used as timeout counter.
+	if (dest.Destroyed) {
+		order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize();
+	} else {
+		order->SetGoal(&dest);
+		order->Range = 1;
+	}
+
+	return order;
+}
+
+
+/* static */ COrder* COrder::NewActionMove(const Vec2i &pos)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionMove;
+	order->goalPos = pos;
+
+	return order;
+}
+
+
+/* static */ COrder* COrder::NewActionPatrol(const Vec2i &currentPos, const Vec2i &dest)
+{
+	Assert(Map.Info.IsPointOnMap(currentPos));
+	Assert(Map.Info.IsPointOnMap(dest));
+
+	COrder *order = new COrder;
+
+	order->Action = UnitActionPatrol;
+	order->goalPos = dest;
+	order->Arg1.Patrol = currentPos;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionRepair;
+	if (target.Destroyed) {
+		order->goalPos = target.tilePos + target.Type->GetHalfTileSize();
+	} else {
+		order->SetGoal(&target);
+		order->Range = unit.Type->RepairRange;
+	}
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionRepair(const Vec2i &pos)
+{
+	Assert(Map.Info.IsPointOnMap(pos));
+
+	COrder *order = new COrder;
+
+	order->Action = UnitActionRepair;
+	order->goalPos = pos;
+	return order;
+}
+
+
+
+/* static */ COrder* COrder::NewActionResearch(CUnit &unit, CUpgrade &upgrade)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionResearch;
+
+	// FIXME: if you give quick an other order, the resources are lost!
+	unit.Player->SubCosts(upgrade.Costs);
+
+	order->Arg1.Upgrade = &upgrade;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionResource(CUnit &harvester, const Vec2i &pos)
+{
+	COrder *order = new COrder;
+	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");
+	}
+	// Max Value > 1
+	if ((MyAbs(ressourceLoc.x - pos.x) | MyAbs(ressourceLoc.y - pos.y)) > 1) {
+		if (!FindTerrainType(0, MapFieldForest, 0, 20, harvester.Player, ressourceLoc, &ressourceLoc)) {
+			DebugPrint("FIXME: Give up???\n");
+		}
+	} else {
+		// The destination is next to a reachable tile.
+		ressourceLoc = pos;
+	}
+	order->goalPos = ressourceLoc;
+	order->Range = 1;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionResource(CUnit &mine)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionResource;
+	order->SetGoal(&mine);
+	order->Range = 1;
+
+	return order;
+}
+
+
+
+/* static */ COrder* COrder::NewActionReturnGoods(CUnit *depot)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionReturnGoods;
+	// Destination could be killed. NETWORK!
+	if (depot && !depot->Destroyed) {
+		order->SetGoal(depot);
+	}
+	order->Range = 1;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionSpellCast(SpellType &spell, const Vec2i &pos, CUnit *target)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionSpellCast;
+
+	order->Range = spell.Range;
+	if (target) {
+		// Destination could be killed.
+		// Should be handled in action, but is not possible!
+		// Unit::Refs is used as timeout counter.
+		if (target->Destroyed) {
+			// FIXME: where check if spell needs a unit as destination?
+			// FIXME: target->Type is now set to 0. maybe we shouldn't bother.
+			const Vec2i diag = {order->Range, order->Range};
+			order->goalPos = target->tilePos /* + target->Type->GetHalfTileSize() */ - diag;
+			order->Range <<= 1;
+		} else {
+			order->SetGoal(target);
+		}
+	} else {
+		order->goalPos = pos;
+	}
+	order->Arg1.Spell = &spell;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionStandGround()
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionStandGround;
+	return order;
+}
+
+
+/* static */ COrder* COrder::NewActionStill()
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionStill;
+	return order;
+}
+
+
+
+
+/* static */ COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionTrain;
+	order->Arg1.Type = &type;
+	// FIXME: if you give quick an other order, the resources are lost!
+	trainer.Player->SubUnitType(type);
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionTransformInto(CUnitType &type)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionTransformInto;
+
+	order->Arg1.Type = &type;
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionUnload;
+	order->goalPos = pos;
+	if (what && !what->Destroyed) {
+		order->SetGoal(what);
+	}
+
+	return order;
+}
+
+/* static */ COrder* COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type)
+{
+	COrder *order = new COrder;
+
+	order->Action = UnitActionUpgradeTo;
+
+	// FIXME: if you give quick an other order, the resources are lost!
+	unit.Player->SubUnitType(type);
+	order->Arg1.Type = &type;
+
+	return order;
+}
+
 COrder& COrder::operator=(const COrder &rhs) {
 	if (this != &rhs) {
 		Action = rhs.Action;
diff --git a/src/action/command.cpp b/src/action/command.cpp
index 5f4b9d1b6..69c92ffae 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -61,15 +61,14 @@
 */
 static void ReleaseOrders(CUnit &unit)
 {
-	int n = unit.OrderCount;
+	Assert(static_cast<size_t>(unit.OrderCount) == unit.Orders.size());
+	Assert(unit.Orders.size() >= 1);
 
-	if (n > 1) {
-		while (--n) {
-			delete unit.Orders[n];
-			unit.Orders.pop_back();
-		}
-		unit.OrderCount = 1;
+	for (size_t i = 1; i != unit.Orders.size(); ++i) {
+		delete unit.Orders[i];
 	}
+	unit.Orders.resize(1);
+	unit.OrderCount = 1;
 	unit.OrderFlush = 1;
 	// Order 0 must be stopped in the action loop.
 }
@@ -82,7 +81,7 @@ static void ReleaseOrders(CUnit &unit)
 **
 **  @return       Pointer to next free order slot.
 */
-static COrderPtr GetNextOrder(CUnit &unit, int flush)
+static COrderPtr *GetNextOrder(CUnit &unit, int flush)
 {
 	if (flush) {
 		// empty command queue
@@ -91,7 +90,9 @@ static COrderPtr GetNextOrder(CUnit &unit, int flush)
 	if (unit.OrderCount == 0x7F) {
 		return NULL;
 	}
-	return unit.CreateOrder();
+	unit.Orders.push_back(NULL);
+	unit.OrderCount++;
+	return &unit.Orders.back();
 }
 
 /**
@@ -104,24 +105,23 @@ static void RemoveOrder(CUnit &unit, int order)
 {
 	Assert(0 <= order && order < unit.OrderCount);
 
-	if (order != 0) {
-		delete unit.Orders[order];
+	delete unit.Orders[order];
+	unit.Orders.erase(unit.Orders.begin() + order);
+	--unit.OrderCount;
+	if (order == 0) {
+		unit.SubAction = 0;
 	}
-	for (int i = order; i < unit.OrderCount - 1; ++i) {
-		unit.Orders[i] = unit.Orders[i + 1];
-	}
-	if (unit.OrderCount > 1) {
-		unit.Orders.pop_back();
-		--unit.OrderCount;
-		if (order == 0) {
-			unit.SubAction = 0;
-		}
-	} else {
-		unit.CurrentOrder()->Init();
-		unit.ClearAction();
+	if (unit.Orders.empty()) {
+		unit.Orders.push_back(COrder::NewActionStill());
 	}
 }
 
+static void ClearNewAction(CUnit &unit)
+{
+	delete unit.NewOrder;
+	unit.NewOrder = NULL;
+}
+
 /**
 **  Clear the saved action.
 **
@@ -136,6 +136,12 @@ static void ClearSavedAction(CUnit &unit)
 	unit.SavedOrder = NULL;
 }
 
+static bool IsUnitValidForNetwork(const CUnit &unit)
+{
+	return !unit.Removed && unit.CurrentAction() != UnitActionDie;
+}
+
+
 /*----------------------------------------------------------------------------
 --  Commands
 ----------------------------------------------------------------------------*/
@@ -148,65 +154,13 @@ static void ClearSavedAction(CUnit &unit)
 void CommandStopUnit(CUnit &unit)
 {
 	// Ignore that the unit could be removed.
-	COrderPtr order = GetNextOrder(unit, FlushCommands); // Flush them.
+	COrderPtr *order = GetNextOrder(unit, FlushCommands); // Flush them.
 	Assert(order);
-	order->Init();
+	Assert(*order == NULL);
+	*order = COrder::NewActionStill();
 
-	order->Action = UnitActionStill;
 	ClearSavedAction(unit);
-	delete unit.NewOrder;
-	unit.NewOrder = NULL;
-}
-
-/**
-**  Order an already formed Order structure
-**
-**  @param unit      pointer to unit
-**  @param cpyorder  pointer to valid order
-**  @param flush     if true, flush command queue.
-*/
-void CommandAnyOrder(CUnit &unit, COrderPtr cpyorder, int flush)
-{
-	COrderPtr order;
-
-	if (!(order = GetNextOrder(unit, flush))) {
-		return;
-	}
-
-	*order = *cpyorder;
-	ClearSavedAction(unit);
-}
-
-/**
-**  Move an order in the order queue.
-**  ( Cannot move the order 0 ! )
-**
-**  @param unit  pointer to unit
-**  @param src   the order to move
-**  @param dst   the new position of the order
-*/
-void CommandMoveOrder(CUnit &unit, int src, int dst)
-{
-	Assert(src != 0 && dst != 0 && src < unit.OrderCount && dst < unit.OrderCount);
-
-	if (src == dst) {
-		return;
-	}
-	if (src < dst) {
-		COrderPtr tmp = unit.Orders[src];
-
-		for (int i = src; i < dst; ++i) {
-			unit.Orders[i] = unit.Orders[i+1];
-		}
-		unit.Orders[dst] = tmp;
-	} else { // dst < src
-		COrderPtr tmp = unit.Orders[src];
-
-		for (int i = src - 1 ; i >= dst; --i) {
-			unit.Orders[i + 1] = unit.Orders[i];
-		}
-		unit.Orders[dst] = tmp;
-	}
+	ClearNewAction(unit);
 }
 
 /**
@@ -217,20 +171,18 @@ void CommandMoveOrder(CUnit &unit, int src, int dst)
 */
 void CommandStandGround(CUnit &unit, int flush)
 {
-	COrderPtr order;
-
-	// Ignore that the unit could be removed.
+	COrderPtr* order;
 
 	if (unit.Type->Building) {
-		// FIXME: should find a better way for pending orders.
-		delete unit.NewOrder;
-		unit.NewOrder = new COrder;
-		order = unit.NewOrder;
-	} else if (!(order = GetNextOrder(unit, flush))) {
-		return;
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
+			return;
+		}
 	}
-	order->Init();
-	order->Action = UnitActionStandGround;
+	*order = COrder::NewActionStandGround();
 	ClearSavedAction(unit);
 }
 
@@ -243,35 +195,21 @@ void CommandStandGround(CUnit &unit, int flush)
 */
 void CommandFollow(CUnit &unit, CUnit &dest, int flush)
 {
-	COrderPtr order;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (!unit.CanMove()) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (!unit.CanMove()) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionFollow;
-		//
-		// Destination could be killed.
-		// Should be handled in action, but is not possible!
-		// Unit::Refs is used as timeout counter.
-		//
-		if (dest.Destroyed) {
-			order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize();
-		} else {
-			order->SetGoal(&dest);
-			order->Range = 1;
-		}
 	}
+	*order = COrder::NewActionFollow(dest);
 	ClearSavedAction(unit);
 }
 
@@ -284,26 +222,23 @@ void CommandFollow(CUnit &unit, CUnit &dest, int flush)
 */
 void CommandMove(CUnit &unit, const Vec2i &pos, int flush)
 {
-	COrderPtr order;
-
 	Assert(Map.Info.IsPointOnMap(pos));
 
-	//
-	//  Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (!unit.CanMove()) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
+
+	if (!unit.CanMove()) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-		order->Action = UnitActionMove;
-		order->goalPos = pos;
 	}
+	*order = COrder::NewActionMove(pos);
 	ClearSavedAction(unit);
 }
 
@@ -317,38 +252,24 @@ void CommandMove(CUnit &unit, const Vec2i &pos, int flush)
 */
 void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush)
 {
-	COrderPtr order;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
 
-	//
-	//  Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionRepair;
-		//
-		//  Destination could be killed.
-		//  Should be handled in action, but is not possible!
-		//  Unit::Refs is used as timeout counter.
-		//
-		if (dest) {
-			if (dest->Destroyed) {
-				order->goalPos = dest->tilePos + dest->Type->GetHalfTileSize();
-			} else {
-				order->SetGoal(dest);
-				order->Range = unit.Type->RepairRange;
-			}
-		} else {
-			order->goalPos = pos;
-		}
+	}
+	if (dest) {
+		*order = COrder::NewActionRepair(unit, *dest);
+	} else {
+		*order = COrder::NewActionRepair(pos);
 	}
 	ClearSavedAction(unit);
 }
@@ -361,12 +282,10 @@ void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush)
 */
 void CommandAutoRepair(CUnit &unit, int on)
 {
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		unit.AutoRepair = on;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	unit.AutoRepair = on;
 }
 
 /**
@@ -374,52 +293,31 @@ void CommandAutoRepair(CUnit &unit, int on)
 **
 **  @param unit    pointer to unit.
 **  @param pos     map position to attack.
-**  @param attack  or unit to be attacked.
+**  @param target  or unit to be attacked.
 **  @param flush   if true, flush command queue.
 */
-void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush)
+void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *target, int flush)
 {
-	COrderPtr order;
-
 	Assert(Map.Info.IsPointOnMap(pos));
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (!unit.Type->CanAttack) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	COrderPtr *order;
+
+	if (!unit.Type->CanAttack) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionAttack;
-		if (attack) {
-			//
-			// Destination could be killed.
-			// Should be handled in action, but is not possible!
-			// Unit::Refs is used as timeout counter.
-			//
-			if (attack->Destroyed) {
-				order->goalPos = attack->tilePos + attack->Type->GetHalfTileSize();
-			} else {
-				// Removed, Dying handled by action routine.
-				order->SetGoal(attack);
-				order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
-				order->MinRange = unit.Type->MinAttackRange;
-			}
-		} else if (Map.WallOnMap(pos)) {
-			// FIXME: look into action_attack.c about this ugly problem
-			order->goalPos = pos;
-			order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
-			order->MinRange = unit.Type->MinAttackRange;
-		} else {
-			order->goalPos = pos;
-		}
+	}
+	if (target) {
+		*order = COrder::NewActionAttack(unit, *target);
+	} else {
+		*order = COrder::NewActionAttack(unit, pos);
 	}
 	ClearSavedAction(unit);
 }
@@ -433,31 +331,23 @@ void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush)
 */
 void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush)
 {
-	COrderPtr order;
-
 	Assert(Map.Info.IsPointOnMap(pos));
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
+
+	if (unit.Type->CanAttack) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionAttackGround;
-		order->goalPos = pos;
-		order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
-		order->MinRange = unit.Type->MinAttackRange;
-
-		DebugPrint("FIXME this next\n");
 	}
+	*order = COrder::NewActionAttackGround(unit, pos);
 	ClearSavedAction(unit);
 }
 
@@ -472,29 +362,24 @@ void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush)
 */
 void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush)
 {
-	COrderPtr order;
-
 	Assert(Map.Info.IsPointOnMap(pos));
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (!unit.CanMove()) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
+
+	if (!unit.CanMove()) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionPatrol;
-		order->goalPos = pos;
-		Assert(!(unit.tilePos.x & ~0xFFFF) && !(unit.tilePos.y & ~0xFFFF));
-		order->Arg1.Patrol = unit.tilePos;
 	}
+	*order = COrder::NewActionPatrol(unit.tilePos, pos);
+
 	ClearSavedAction(unit);
 }
 
@@ -507,35 +392,24 @@ void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush)
 */
 void CommandBoard(CUnit &unit, CUnit &dest, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		//
-		// Destination could be killed.
-		// Should be handled in action, but is not possible!
-		// Unit::Refs is used as timeout counter.
-		//
-		if (dest.Destroyed) {
-			return;
-		}
-
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		order->Action = UnitActionBoard;
-		order->SetGoal(&dest);
-		order->Range = 1;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	if (dest.Destroyed) {
+		return ;
+	}
+	COrderPtr *order;
+
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
+			return;
+		}
+	}
+	*order = COrder::NewActionBoard(dest);
 	ClearSavedAction(unit);
 }
 
@@ -549,28 +423,15 @@ void CommandBoard(CUnit &unit, CUnit &dest, int flush)
 */
 void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		order->Action = UnitActionUnload;
-		order->goalPos = pos;
-		//
-		// Destination could be killed.
-		// Should be handled in action, but is not possible!
-		// Unit::Refs is used as timeout counter.
-		//
-		if (what && !what->Destroyed) {
-			order->SetGoal(what);
-		}
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	COrderPtr *order = GetNextOrder(unit, flush);
+
+	if (order == NULL) {
+		return;
+	}
+	*order = COrder::NewActionUnload(pos, what);
 	ClearSavedAction(unit);
 }
 
@@ -584,40 +445,21 @@ void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush)
 */
 void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int flush)
 {
-	COrderPtr order;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	COrderPtr *order;
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionBuild;
-		order->goalPos = pos;
-		order->Width = what.TileWidth;
-		order->Height = what.TileHeight;
-		if (what.BuilderOutside) {
-			order->Range = unit.Type->RepairRange;
-		} else {
-			// If building inside, but be next to stop
-			if (what.ShoreBuilding && unit.Type->UnitType == UnitTypeLand) {
-					// Peon won't dive :-)
-				order->Range = 1;
-			}
-		}
-		order->Arg1.Type = &what;
-		if (what.BuilderOutside) {
-			order->MinRange = 1;
-		}
 	}
+	*order = COrder::NewActionBuild(unit, pos, what);
 	ClearSavedAction(unit);
 }
 
@@ -628,9 +470,7 @@ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int fl
 */
 void CommandDismiss(CUnit &unit)
 {
-	//
 	// Check if building is still under construction? (NETWORK!)
-	//
 	if (unit.CurrentAction() == UnitActionBuilt) {
 		unit.CurrentOrder()->Data.Built.Cancel = 1;
 	} else {
@@ -649,42 +489,25 @@ void CommandDismiss(CUnit &unit)
 */
 void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush)
 {
-	COrderPtr order;
-	Vec2i ressourceLoc;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
+	}
+	if (!unit.Type->Building && !unit.Type->Harvester) {
+		ClearSavedAction(unit);
+		return ;
+	}
+	COrderPtr *order;
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
 			return;
 		}
-		order->Init();
-
-		order->Action = UnitActionResource;
-
-		//  Find the closest piece of wood next to a tile where the unit can move
-		if (!FindTerrainType(0, (unit.Type->MovementMask), 1, 20, unit.Player, pos, &ressourceLoc)) {
-			DebugPrint("FIXME: Give up???\n");
-		}
-
-		// Max Value > 1
-		if ((MyAbs(ressourceLoc.x - pos.x) | MyAbs(ressourceLoc.y - pos.y)) > 1) {
-			if (!FindTerrainType(0, MapFieldForest, 0, 20, unit.Player, ressourceLoc, &ressourceLoc)) {
-				DebugPrint("FIXME: Give up???\n");
-			}
-		} else {
-			// The destination is next to a reachable tile.
-			ressourceLoc = pos;
-		}
-		order->goalPos = ressourceLoc;
-		order->Range = 1;
 	}
+	*order = COrder::NewActionResource(unit, pos);
 	ClearSavedAction(unit);
 }
 
@@ -697,33 +520,28 @@ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush)
 */
 void CommandResource(CUnit &unit, CUnit &dest, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid and Goal still alive? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie && !dest.Destroyed) {
-		// FIXME: more races, could happen with many orders in queue.
-		if (!unit.Type->Building && !unit.Type->Harvester) {
-			ClearSavedAction(unit);
-			return;
-		}
-
-		// FIXME: if low-level supports searching, pass NoUnitP down.
-
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-		order->Action = UnitActionResource;
-		order->SetGoal(&dest);
-		order->Range = 1;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	if (dest.Destroyed) {
+		return ;
+	}
+	if (!unit.Type->Building && !unit.Type->Harvester) {
+		ClearSavedAction(unit);
+		return ;
+	}
+	COrderPtr *order;
+
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
+			return;
+		}
+	}
+	*order = COrder::NewActionResource(dest);
 	ClearSavedAction(unit);
 }
 
@@ -736,37 +554,26 @@ void CommandResource(CUnit &unit, CUnit &dest, int flush)
 */
 void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid and Goal still alive? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		// FIXME: more races, could happen with many orders in queue.
-		if (!unit.Type->Building && !unit.Type->Harvester && !unit.ResourcesHeld) {
-			ClearSavedAction(unit);
-			return;
-		}
-
-		if (unit.Type->Building) {
-			// FIXME: should find a better way for pending orders.
-			delete unit.NewOrder;
-			unit.NewOrder = new COrder;
-			order = unit.NewOrder;
-		} else if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		order->Action = UnitActionReturnGoods;
-		//
-		// Destination could be killed. NETWORK!
-		//
-		if (goal && !goal->Destroyed) {
-			order->SetGoal(goal);
-		}
-		order->Range = 1;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	if ((unit.Type->Harvester && unit.ResourcesHeld == 0)
+		|| (!unit.Type->Building && !unit.Type->Harvester)) {
+		ClearSavedAction(unit);
+		return ;
+	}
+	COrderPtr *order;
+
+	if (unit.Type->Building) {
+		ClearNewAction(unit);
+		order = &unit.NewOrder;
+	} else {
+		order = GetNextOrder(unit, flush);
+		if (order == NULL) {
+			return;
+		}
+	}
+	*order = COrder::NewActionReturnGoods(goal);
 	ClearSavedAction(unit);
 }
 
@@ -779,38 +586,28 @@ void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush)
 */
 void CommandTrainUnit(CUnit &unit, CUnitType &type, int)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		//
-		// Check if enough resources remains? (NETWORK!)
-		// FIXME: wrong if append to message queue!!!
-		//
-		if (unit.Player->CheckLimits(type) < 0 ||
-				unit.Player->CheckUnitType(type)) {
-			return;
-		}
-
-		//
-		// Not already training?
-		//
-		if (!EnableTrainingQueue && unit.CurrentAction() == UnitActionTrain) {
-			DebugPrint("Unit queue full!\n");
-			return;
-		}
-		if (!(order = GetNextOrder(unit, 0))) {
-			return;
-		}
-		order->Init();
-
-		order->Action = UnitActionTrain;
-		order->Arg1.Type = &type;
-		// FIXME: if you give quick an other order, the resources are lost!
-		unit.Player->SubUnitType(type);
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	// Check if enough resources remains? (NETWORK!)
+	// FIXME: wrong if append to message queue!!!
+	if (unit.Player->CheckLimits(type) < 0
+		|| unit.Player->CheckUnitType(type)) {
+		return;
+	}
+	// Not already training?
+	if (!EnableTrainingQueue && unit.CurrentAction() == UnitActionTrain) {
+		DebugPrint("Unit queue disabled!\n");
+		return;
+	}
+
+	const int noFlushCommands = 0;
+	COrderPtr *order = GetNextOrder(unit, noFlushCommands);
+
+	if (order == NULL) {
+		return;
+	}
+	*order = COrder::NewActionTrain(unit, type);
 	ClearSavedAction(unit);
 }
 
@@ -828,10 +625,7 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type)
 
 	ClearSavedAction(unit);
 
-	//
 	// Check if unit is still training 'slot'? (NETWORK!)
-	//
-
 	if (slot == -1) {
 		// Cancel All training
 		while (unit.CurrentAction() == UnitActionTrain) {
@@ -840,7 +634,6 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type)
 				CancelTrainingCostsFactor);
 			RemoveOrder(unit, 0);
 		}
-		unit.CurrentOrder()->Data.Train.Ticks = 0;
 		if (unit.Player == ThisPlayer && unit.Selected) {
 			SelectedUnitChanged();
 		}
@@ -856,22 +649,14 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type)
 			// Different unit being trained
 			return;
 		}
-
 		DebugPrint("Cancel training\n");
 
 		unit.Player->AddCostsFactor(
 			unit.Orders[slot]->Arg1.Type->Stats[unit.Player->Index].Costs,
 			CancelTrainingCostsFactor);
-
-
-		if (!slot) { // Canceled in work slot
-			unit.CurrentOrder()->Data.Train.Ticks = 0;
-		}
 		RemoveOrder(unit, slot);
 
-		//
 		// Update interface.
-		//
 		if (unit.Player == ThisPlayer && unit.Selected) {
 			SelectedUnitChanged();
 		}
@@ -887,33 +672,21 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type)
 */
 void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid and Goal still alive? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		//
-		// Check if enough resources remains? (NETWORK!)
-		//
-		if (unit.Player->CheckUnitType(type)) {
-			return;
-		}
-
-		if (!flush) {
-			DebugPrint("FIXME: must support order queing!!");
-		}
-		if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		// FIXME: if you give quick an other order, the resources are lost!
-		unit.Player->SubUnitType(type);
-
-		order->Action = UnitActionUpgradeTo;
-		order->Arg1.Type = &type;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+
+	// Check if enough resources remains? (NETWORK!)
+	if (unit.Player->CheckUnitType(type)) {
+		return;
+	}
+
+	COrderPtr *order = GetNextOrder(unit, flush);
+
+	if (order == NULL) {
+		return;
+	}
+	*order = COrder::NewActionUpgradeTo(unit, type);
 	ClearSavedAction(unit);
 }
 
@@ -925,13 +698,9 @@ void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush)
 */
 void CommandTransformIntoType(CUnit &unit, CUnitType &type)
 {
-	COrderPtr order = new COrder;
-
 	Assert(unit.CriticalOrder == NULL);
 
-	order->Action = UnitActionTransformInto;
-	order->Arg1.Type = &type;
-	unit.CriticalOrder = order;
+	unit.CriticalOrder = COrder::NewActionTransformInto(type);
 }
 
 /**
@@ -941,19 +710,16 @@ void CommandTransformIntoType(CUnit &unit, CUnitType &type)
 */
 void CommandCancelUpgradeTo(CUnit &unit)
 {
-	ReleaseOrders(unit); // empty command queue
-
-	//
 	// Check if unit is still upgrading? (NETWORK!)
-	//
 	if (unit.CurrentAction() == UnitActionUpgradeTo) {
-
 		unit.Player->AddCostsFactor(
 			unit.CurrentOrder()->Arg1.Type->Stats[unit.Player->Index].Costs,
 			CancelUpgradeCostsFactor);
 
-		unit.CurrentOrder()->Init();
-		unit.ClearAction();
+		RemoveOrder(unit, 0);
+		if (Selected) {
+			SelectedUnitChanged();
+		}
 	}
 	ClearSavedAction(unit);
 }
@@ -967,46 +733,18 @@ void CommandCancelUpgradeTo(CUnit &unit)
 */
 void CommandResearch(CUnit &unit, CUpgrade *what, int flush)
 {
-	COrderPtr order;
-
-	//
-	// Check if unit is still valid and Goal still alive? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		//
-		// Check if enough resources remains? (NETWORK!)
-		//
-		if (unit.Player->CheckCosts(what->Costs)) {
-			return;
-		}
-
-		if (!flush) {
-			DebugPrint("FIXME: must support order queing!!");
-		} else {
-			if (unit.CurrentAction() == UnitActionResearch) {
-				const CUpgrade *upgrade;
-
-				// Cancel current research
-				upgrade = unit.CurrentOrder()->Data.Research.Upgrade;
-				unit.Player->UpgradeTimers.Upgrades[upgrade->ID] = 0;
-				unit.Player->AddCostsFactor(upgrade->Costs,
-					CancelResearchCostsFactor);
-				unit.SubAction = 0;
-			}
-		}
-
-		if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		// FIXME: if you give quick an other order, the resources are lost!
-		unit.Player->SubCosts(what->Costs);
-
-		order->Action = UnitActionResearch;
-		order->goalPos.x = order->goalPos.y = -1;
-		order->Arg1.Upgrade = what;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	// Check if enough resources remains? (NETWORK!)
+	if (unit.Player->CheckCosts(what->Costs)) {
+		return;
+	}
+	COrderPtr *order = GetNextOrder(unit, flush);
+	if (order == NULL) {
+		return;
+	}
+	*order = COrder::NewActionResearch(unit, *what);
 	ClearSavedAction(unit);
 }
 
@@ -1017,21 +755,16 @@ void CommandResearch(CUnit &unit, CUpgrade *what, int flush)
 */
 void CommandCancelResearch(CUnit &unit)
 {
-	ReleaseOrders(unit); // empty command queue
-
-	//
 	// Check if unit is still researching? (NETWORK!)
-	//
 	if (unit.CurrentAction() == UnitActionResearch) {
-		const CUpgrade *upgrade;
+		const CUpgrade &upgrade = *unit.CurrentOrder()->Data.Research.Upgrade;
+		unit.Player->UpgradeTimers.Upgrades[upgrade.ID] = 0;
 
-		upgrade = unit.CurrentOrder()->Data.Research.Upgrade;
-		unit.Player->UpgradeTimers.Upgrades[upgrade->ID] = 0;
-
-		unit.Player->AddCostsFactor(upgrade->Costs,
-			CancelResearchCostsFactor);
-		unit.CurrentOrder()->Init();
-		unit.ClearAction();
+		unit.Player->AddCostsFactor(upgrade.Costs, CancelResearchCostsFactor);
+		RemoveOrder(unit, 0);
+		if (Selected) {
+			SelectedUnitChanged();
+		}
 	}
 	ClearSavedAction(unit);
 }
@@ -1047,47 +780,21 @@ void CommandCancelResearch(CUnit &unit)
 */
 void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, SpellType *spell, int flush)
 {
-	COrderPtr order;
-
-	Assert(Map.Info.IsPointOnMap(pos));
-
 	DebugPrint(": %d casts %s at %d %d on %d\n" _C_
 		UnitNumber(unit) _C_ spell->Ident.c_str() _C_ pos.x _C_ pos.y _C_ dest ? UnitNumber(*dest) : 0);
 	Assert(unit.Type->CanCastSpell[spell->Slot]);
+	Assert(Map.Info.IsPointOnMap(pos));
 
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		// FIXME: should I check here, if there is still enough mana?
-
-		if (!(order = GetNextOrder(unit, flush))) {
-			return;
-		}
-		order->Init();
-
-		order->Action = UnitActionSpellCast;
-		order->Range = spell->Range;
-		if (dest) {
-			//
-			// Destination could be killed.
-			// Should be handled in action, but is not possible!
-			// Unit::Refs is used as timeout counter.
-			//
-			if (dest->Destroyed) {
-				// FIXME: where check if spell needs a unit as destination?
-				// FIXME: dest->Type is now set to 0. maybe we shouldn't bother.
-				const Vec2i diag = {order->Range, order->Range};
-				order->goalPos = dest->tilePos /* + dest->Type->GetHalfTileSize() */ - diag;
-				order->Range <<= 1;
-			} else {
-				order->SetGoal(dest);
-			}
-		} else {
-			order->goalPos = pos;
-		}
-		order->Arg1.Spell = spell;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	COrderPtr *order = GetNextOrder(unit, flush);
+
+	if (order == NULL) {
+		return;
+	}
+
+	*order = COrder::NewActionSpellCast(*spell, pos, dest);
 	ClearSavedAction(unit);
 }
 
@@ -1100,12 +807,10 @@ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, SpellType *spe
 */
 void CommandAutoSpellCast(CUnit &unit, int spellid, int on)
 {
-	//
-	// Check if unit is still valid? (NETWORK!)
-	//
-	if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
-		unit.AutoCastSpell[spellid] = on;
+	if (IsUnitValidForNetwork(unit) == false) {
+		return ;
 	}
+	unit.AutoCastSpell[spellid] = on;
 }
 
 /**
diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp
index f51556c1e..1a08d3c22 100644
--- a/src/ai/ai.cpp
+++ b/src/ai/ai.cpp
@@ -714,11 +714,7 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender)
 				&& CanTarget(aiunit.Type, attacker->Type)) {
 				CommandAttack(aiunit, attacker->tilePos, const_cast<CUnit*>(attacker), FlushCommands);
 				if (aiunit.SavedOrder == NULL) {
-					COrder *savedOrder = new COrder;
-
-					savedOrder->Action = UnitActionAttack;
-					savedOrder->Range = 0;
-					savedOrder->goalPos = aiunit.tilePos;
+					COrder *savedOrder = COrder::NewActionAttack(aiunit, aiunit.tilePos);
 
 					if (aiunit.StoreOrder(savedOrder) == false) {
 						delete savedOrder;
diff --git a/src/include/actions.h b/src/include/actions.h
index e7b3e9dec..058135249 100644
--- a/src/include/actions.h
+++ b/src/include/actions.h
@@ -10,7 +10,7 @@
 //
 /**@name actions.h - The actions headerfile. */
 //
-//      (c) Copyright 1998-2006 by Lutz Sammer and Jimmy Salmon
+//      (c) Copyright 1998-2012 by Lutz Sammer and Jimmy Salmon
 //
 //      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
@@ -150,6 +150,31 @@ public:
 	void AiUnitKilled(CUnit &unit);
 
 	void OnAnimationAttack(CUnit &unit);
+
+	static COrder* NewActionAttack(const CUnit &attacker, CUnit &target);
+	static COrder* NewActionAttack(const CUnit &attacker, const Vec2i &dest);
+	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* NewActionDie();
+	static COrder* NewActionFollow(CUnit &dest);
+	static COrder* NewActionMove(const Vec2i &pos);
+	static COrder* NewActionPatrol(const Vec2i &currentPos, const Vec2i &dest);
+	static COrder* NewActionRepair(CUnit &unit, CUnit &target);
+	static COrder* NewActionRepair(const Vec2i &pos);
+	static COrder* NewActionResearch(CUnit &unit, CUpgrade &upgrade);
+	static COrder* NewActionResource(CUnit &harvester, const Vec2i &pos);
+	static COrder* NewActionResource(CUnit &mine);
+	static COrder* NewActionReturnGoods(CUnit *depot);
+	static COrder* NewActionSpellCast(SpellType &spell, const Vec2i &pos, CUnit *target);
+	static COrder* NewActionStandGround();
+	static COrder* NewActionStill();
+	static COrder* NewActionTrain(CUnit &trainer, CUnitType &type);
+	static COrder* NewActionTransformInto(CUnitType &type);
+	static COrder* NewActionUnload(const Vec2i &pos, CUnit *what);
+	static COrder* NewActionUpgradeTo(CUnit &unit, CUnitType &type);
+
 private:
 	friend void CclParseOrder(lua_State *l, const CUnit &unit, COrder* order);
 
@@ -160,8 +185,7 @@ public:
 	unsigned char Width;    /// Goal Width (used when Goal is not)
 	unsigned char Height;   /// Goal Height (used when Goal is not)
 	unsigned char Action;   /// global action
-	unsigned char CurrentResource;	 //used in 	UnitActionResource and
-										//UnitActionReturnGoods
+	unsigned char CurrentResource; ///used in UnitActionResource and UnitActionReturnGoods
 
 	Vec2i goalPos;          /// or tile coordinate of destination
 
@@ -292,10 +316,6 @@ extern void CommandDiplomacy(int player, int state, int opponent);
 extern void CommandSetResource(int player, int resource, int value);
 	/// Prepare shared vision command
 extern void CommandSharedVision(int player, bool state, int opponent);
-	/// Send any command
-//extern void CommandAnyOrder(CUnit &unit, COrder *order, int flush);
-	/// Move an order in command queue
-extern void CommandMoveOrder(CUnit &unit, int src, int dst);
 
 /*----------------------------------------------------------------------------
 --  Actions: in action_<name>.c
@@ -328,7 +348,7 @@ extern HandleActionFunc HandleActionPatrol;
 	/// Show attack animation
 extern void AnimateActionAttack(CUnit &unit);
 	/// Handle command attack
-extern HandleActionFunc  HandleActionAttack;
+extern HandleActionFunc HandleActionAttack;
 	/// Handle command board
 extern HandleActionFunc HandleActionBoard;
 	/// Handle command unload
diff --git a/src/include/unit.h b/src/include/unit.h
index 4862936c7..55a8b3167 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -597,8 +597,6 @@ public:
 
 	CUnit *Goal; /// Generic/Teleporter goal pointer
 
-	COrder *CreateOrder();
-
 	COrder *CurrentOrder() const { return Orders[0]; }
 
 	unsigned int CurrentAction() const;
diff --git a/src/stratagus/groups.cpp b/src/stratagus/groups.cpp
index 30da49b5c..18c3f7c30 100644
--- a/src/stratagus/groups.cpp
+++ b/src/stratagus/groups.cpp
@@ -307,13 +307,11 @@ void GroupHelpMe(CUnit *attacker, CUnit &defender)
 						&& CanTarget(gunit.Type, attacker->Type)) {
 						CommandAttack(gunit, attacker->tilePos, attacker, FlushCommands);
 						if (gunit.SavedOrder == NULL) {
-							COrder *savedOrder = new COrder;
-
-							savedOrder->Action = UnitActionAttack;
-							savedOrder->goalPos = gunit.tilePos;
+							COrder *savedOrder = COrder::NewActionAttack(gunit, gunit.tilePos);
 
 							if (gunit.StoreOrder(savedOrder) == false) {
 								delete savedOrder;
+								savedOrder = NULL;
 							}
 						}
 					}
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index 12f5d80bc..7d256db29 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -589,9 +589,12 @@ static void CclParseOrders(lua_State *l, CUnit &unit)
 	unit.OrderCount = 0;
 	for (int j = 0; j < n; ++j) {
 		lua_rawgeti(l, -1, j + 1);
-		COrderPtr order = unit.CreateOrder();
-		Assert(order == unit.Orders[j]);
-		CclParseOrder(l, unit, order);
+
+		unit.Orders.push_back(new COrder);
+		COrderPtr* order = &unit.Orders[(int)unit.OrderCount++];
+
+		Assert(order == &unit.Orders[j]);
+		CclParseOrder(l, unit, *order);
 		lua_pop(l, 1);
 	}
 }
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index d6c022e43..90f6d5fa8 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -260,13 +260,6 @@ void CUnit::Release(bool final)
 	UnitManager.ReleaseUnit(this);
 }
 
-
-COrder *CUnit::CreateOrder()
-{
-	Orders.push_back(new COrder);
-	return Orders[(int)OrderCount++];
-}
-
 unsigned int CUnit::CurrentAction() const
 {
 	return (CurrentOrder()->Action);
@@ -1059,8 +1052,8 @@ void UnitClearOrders(CUnit &unit)
 		delete unit.Orders[i];
 	}
 	unit.Orders.clear();
-	unit.OrderCount = 0;
-	CommandStopUnit(unit);
+	unit.OrderCount = 1;
+	unit.Orders.push_back(COrder::NewActionStill());
 	unit.SubAction = unit.State = 0;
 }
 
@@ -2720,14 +2713,15 @@ void LetUnitDie(CUnit &unit)
 	UnitLost(unit);
 	UnitClearOrders(unit);
 
-	//
+
+
 	// Unit has death animation.
-	//
 
 	// Not good: UnitUpdateHeading(unit);
 	unit.SubAction = 0;
 	unit.State = 0;
-	unit.CurrentOrder()->Action = UnitActionDie;
+	delete unit.Orders[0];
+	unit.Orders[0] = COrder::NewActionDie();
 	if (type->CorpseType) {
 #ifdef DYNAMIC_LOAD
 		if (!type->Sprite) {
@@ -2977,19 +2971,13 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage)
 			}
 		}
 		if (goal) {
-			if (target.SavedOrder == NULL) {
-				COrder* savedOrder = new COrder;
+			COrder *savedOrder = new COrder(*target.CurrentOrder());
 
-				savedOrder->Action = UnitActionAttack;
-				savedOrder->goalPos = target.tilePos;
-				savedOrder->Range = target.Stats->Variables[ATTACKRANGE_INDEX].Max;
-				savedOrder->MinRange = target.Type->MinAttackRange;
-
-				if (target.StoreOrder(savedOrder) == false) {
-					delete savedOrder;
-				}
-			}
 			CommandAttack(target, goal->tilePos, NoUnitP, FlushCommands);
+			if (target.StoreOrder(savedOrder) == false) {
+				delete savedOrder;
+				savedOrder = NULL;
+			}
 			return;
 		}
 	}