From 58f777c425738ccee1094a47e026e8401a26fab0 Mon Sep 17 00:00:00 2001
From: joris <joris.dauphin@gmail.com>
Date: Tue, 21 Feb 2012 15:39:36 +0100
Subject: [PATCH] Add COrder_Built

---
 src/action/action_build.cpp   | 575 +++++++++++++++++++---------------
 src/action/action_repair.cpp  |  88 ++----
 src/action/actions.cpp        |  38 ++-
 src/action/command.cpp        |   2 +-
 src/include/actions.h         |  52 ++-
 src/include/script.h          |   5 +
 src/include/unit.h            |   7 +-
 src/map/script_map.cpp        |   1 -
 src/pathfinder/pathfinder.cpp |   1 +
 src/stratagus/missile.cpp     |   1 +
 src/stratagus/selection.cpp   |   8 +-
 src/ui/botpanel.cpp           |   1 +
 src/ui/button_checks.cpp      |   1 +
 src/ui/interface.cpp          |   1 +
 src/ui/mainscr.cpp            |   7 +-
 src/ui/mouse.cpp              |   1 +
 src/unit/build.cpp            |   1 +
 src/unit/script_unit.cpp      |  52 ---
 src/unit/script_unittype.cpp  |  16 +-
 src/unit/unit.cpp             |  15 +-
 src/unit/unit_draw.cpp        |  24 +-
 src/unit/unit_save.cpp        |  40 +--
 22 files changed, 482 insertions(+), 455 deletions(-)

diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp
index 72aa22856..29ad1d712 100644
--- a/src/action/action_build.cpp
+++ b/src/action/action_build.cpp
@@ -49,42 +49,13 @@
 #include "interface.h"
 #include "pathfinder.h"
 #include "construct.h"
+#include "iolib.h"
+#include "script.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
 ----------------------------------------------------------------------------*/
 
-/**
-**  Update construction frame
-**
-**  @param unit  The building under construction.
-*/
-static void UpdateConstructionFrame(CUnit &unit)
-{
-	CConstructionFrame *cframe;
-	CConstructionFrame *tmp;
-	int percent;
-
-	percent = unit.CurrentOrder()->Data.Built.Progress /
-		(unit.Type->Stats[unit.Player->Index].Costs[TimeCost] * 6);
-	cframe = tmp = unit.Type->Construction->Frames;
-	while (tmp) {
-		if (percent < tmp->Percent) {
-			break;
-		}
-		cframe = tmp;
-		tmp = tmp->Next;
-	}
-	if (cframe != unit.CurrentOrder()->Data.Built.Frame) {
-		unit.CurrentOrder()->Data.Built.Frame = cframe;
-		if (unit.Frame < 0) {
-			unit.Frame = -cframe->Frame - 1;
-		} else {
-			unit.Frame = cframe->Frame;
-		}
-	}
-}
-
 /**
 **  Move to build location
 **
@@ -287,7 +258,8 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
 	}
 
 	// Must set action before placing, otherwise it will incorrectly mark radar
-	build->CurrentOrder()->Action = UnitActionBuilt;
+	delete build->CurrentOrder();
+	build->Orders[0] = COrder::NewActionBuilt(unit, *build);
 
 	// Must place after previous for map flags
 	build->Place(pos);
@@ -298,18 +270,10 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
 	// HACK: the building is not ready yet
 	build->Player->UnitTypesCount[type.Slot]--;
 
-	// Make sure the bulding doesn't cancel itself out right away.
-	build->CurrentOrder()->Data.Built.Progress = 0;//FIXME ? 100 : 0
-	build->Variable[HP_INDEX].Value = 1;
-	if (build->Variable[SHIELD_INDEX].Max)
-		build->Variable[SHIELD_INDEX].Value = 1;
-	UpdateConstructionFrame(*build);
-
 	// We need somebody to work on it.
 	if (!type.BuilderOutside) {
 		//FIXME: cancel buld gen crash
 		// Place the builder inside the building
-		build->CurrentOrder()->Data.Built.Worker = &unit;
 		// HACK: allows the unit to be removed
 		build->CurrentSightRange = 1;
 		//HACK: reset anim
@@ -337,7 +301,6 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
 		// Mark the new building seen.
 		MapMarkUnitSight(*build);
 	}
-	UpdateConstructionFrame(*build);
 }
 
 /**
@@ -359,48 +322,6 @@ static void BuildBuilding(CUnit &unit)
 	//
 	//int animlength = unit.Data.Build.Cycles;
 	unit.CurrentOrder()->Data.Build.Cycles = 0;
-#if 0
-	CUnit *goal;
-	int hp;
-
-	//goal hp are mod by HandleActionBuilt
-	//and outsid builder use repair now.
-	goal = unit.CurrentOrder()->GetGoal();
-	//Assert(goal);
-	if(!goal) {
-		return;
-	}
-
-	if (goal->CurrentAction() == UnitActionDie) {
-		unit.CurrentOrder()->ClearGoal();
-		unit.State = 0;
-		unit.ClearAction();
-		return;
-	}
-
-	// hp is the current damage taken by the unit.
-	hp = (goal->CurrentOrder()->Data.Built.Progress * goal->Variable[HP_INDEX].Max) /
-		(goal->Stats->Costs[TimeCost] * 600) - goal->Variable[HP_INDEX].Value;
-
-	// FIXME: implement this below:
-	// unit.CurrentOrder()->Data.Built.Worker->Type->BuilderSpeedFactor;
-	goal->CurrentOrder()->Data.Built.Progress += 100 * animlength * SpeedBuild;
-	// Keep the same level of damage while increasing HP.
-	goal->Variable[HP_INDEX].Value = (goal->Data.Built.Progress * goal->Variable[HP_INDEX].Max) /
-		(goal->Stats->Costs[TimeCost] * 600) - hp;
-	if (goal->Variable[HP_INDEX].Value > goal->Variable[HP_INDEX].Max) {
-		goal->Variable[HP_INDEX].Value = goal->Variable[HP_INDEX].Max;
-	}
-
-	//
-	// Building is gone or finished
-	//
-	if (goal->Variable[HP_INDEX].Value == goal->Variable[HP_INDEX].Max) {
-		unit.CurrentOrder()->ClearGoal();
-		unit.State = 0;
-		unit.ClearAction();
-	}
-#endif
 }
 
 /**
@@ -425,6 +346,317 @@ 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\", ");
+
+	CConstructionFrame *cframe = unit.Type->Construction->Frames;
+	int frame = 0;
+	while (cframe != this->Data.Frame) {
+		cframe = cframe->Next;
+		++frame;
+	}
+	if (this->Data.Worker == NULL) {
+		file.printf("\"worker\", \"%s\", ", UnitReference(this->Data.Worker).c_str());
+	}
+	file.printf("\"progress\", %d, \"frame\", %d", this->Data.Progress, frame);
+	if (this->Data.Cancel) {
+		file.printf(", \"cancel\"");
+	}
+	file.printf("}");
+}
+
+/* virtual */ bool COrder_Built::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
+{
+	if (!strcmp(value, "worker")) {
+		++j;
+		lua_rawgeti(l, -1, j + 1);
+		this->Data.Worker = CclGetUnitFromRef(l);
+		lua_pop(l, 1);
+	} else if (!strcmp(value, "progress")) {
+		++j;
+		lua_rawgeti(l, -1, j + 1);
+		this->Data.Progress = LuaToNumber(l, -1);
+		lua_pop(l, 1);
+	} else if (!strcmp(value, "cancel")) {
+		this->Data.Cancel = 1;
+	} else if (!strcmp(value, "frame")) {
+		++j;
+		lua_rawgeti(l, -1, j + 1);
+		int frame = LuaToNumber(l, -1);
+		lua_pop(l, 1);
+		CConstructionFrame *cframe = unit.Type->Construction->Frames;
+		while (frame--) {
+			cframe = cframe->Next;
+		}
+		this->Data.Frame = cframe;
+	} else {
+		return false;
+	}
+	return true;
+}
+
+
+static void CancelBuilt(COrder_Built &order, CUnit &unit)
+{
+	Assert(unit.CurrentOrder() == &order);
+	CUnit *worker = order.GetWorkerPtr();
+
+	// Drop out unit
+	if (worker != NULL) {
+
+
+
+		worker->ClearAction();
+
+		// HACK: make sure the sight is updated correctly
+//		unit.CurrentSightRange = 1;
+		DropOutOnSide(*worker, LookingW, &unit);
+//		unit.CurrentSightRange = 0;
+	}
+
+	// Player gets back 75% of the original cost for a building.
+	unit.Player->AddCostsFactor(unit.Stats->Costs, CancelBuildingCostsFactor);
+	// Cancel building
+	LetUnitDie(unit);
+}
+
+static bool Finish(COrder_Built &order, CUnit& unit)
+{
+	const CUnitType &type = *unit.Type;
+	CPlayer &player = *unit.Player;
+
+	DebugPrint("%d: Building %s(%s) ready.\n" _C_ player.Index _C_ type.Ident.c_str() _C_ type.Name.c_str() );
+
+	// HACK: the building is ready now
+	player.UnitTypesCount[type.Slot]++;
+	unit.Constructed = 0;
+	if (unit.Frame < 0) {
+		unit.Frame = -1;
+	} else {
+		unit.Frame = 0;
+	}
+	CUnit *worker = order.GetWorkerPtr();
+
+	if (worker != NULL) {
+		if (type.BuilderLost) {
+			// Bye bye worker.
+			LetUnitDie(*worker);
+			worker = NULL;
+		} else { // Drop out the worker.
+			worker->ClearAction();
+#if 0
+			// HACK: make sure the sight is updated correctly
+			// unit.CurrentSightRange = 1;
+#endif
+			DropOutOnSide(*worker, LookingW, &unit);
+
+			// If we can harvest from the new building, do it.
+			if (worker->Type->ResInfo[type.GivesResource]) {
+				CommandResource(*worker, unit, 0);
+			}
+		}
+	}
+
+	if (type.GivesResource && type.StartingResources != 0) {
+		// Has StartingResources, Use those
+		unit.ResourcesHeld = type.StartingResources;
+	}
+
+	player.Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y, _("New %s done"), type.Name.c_str());
+	if (&player == ThisPlayer) {
+		if (type.Sound.Ready.Sound) {
+			PlayUnitSound(unit, VoiceReady);
+		} else if (worker) {
+			PlayUnitSound(*worker, VoiceWorkCompleted);
+		} else {
+			PlayUnitSound(unit, VoiceBuilding);
+		}
+	}
+
+	if (player.AiEnabled) {
+		/* Worker can be NULL */
+		AiWorkComplete(worker, unit);
+	}
+
+	// FIXME: Vladi: this is just a hack to test wall fixing,
+	// FIXME:  also not sure if the right place...
+	// FIXME: Johns: hardcoded unit-type wall / more races!
+	if (&type == UnitTypeOrcWall || &type == UnitTypeHumanWall) {
+		Map.SetWall(unit.tilePos, &type == UnitTypeHumanWall);
+		unit.Remove(NULL);
+		UnitLost(unit);
+		UnitClearOrders(unit);
+		unit.Release();
+		return false;
+	}
+
+	UpdateForNewUnit(unit, 0);
+
+	// Set the direction of the building if it supports them
+	if (type.NumDirections > 1) {
+		if (type.Wall) { // Special logic for walls
+			CorrectWallDirections(unit);
+			CorrectWallNeighBours(unit);
+		} else {
+			unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
+		}
+		UnitUpdateHeading(unit);
+	}
+
+	if (IsOnlySelected(unit) || &player == ThisPlayer) {
+		SelectedUnitChanged();
+	}
+	MapUnmarkUnitSight(unit);
+	unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max;
+	MapMarkUnitSight(unit);
+	return true;
+}
+
+
+/* virtual */ bool COrder_Built::Execute(CUnit &unit)
+{
+	const CUnitType &type = *unit.Type;
+
+	int amount;
+	if (type.BuilderOutside) {
+		amount = type.AutoBuildRate;
+	} else {
+		// FIXME: implement this below:
+		// this->Data.Worker->Type->BuilderSpeedFactor;
+		amount = 100;
+	}
+	this->Progress(unit, amount);
+
+	// Check if construction should be canceled...
+	if (this->Data.Cancel || this->Data.Progress < 0) {
+		DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index _C_ unit.Type->Name.c_str());
+
+		CancelBuilt(*this, unit);
+		return false;
+	}
+
+	const int maxProgress = type.Stats[unit.Player->Index].Costs[TimeCost] * 600;
+
+	// Check if building ready. Note we can both build and repair.
+	if (!unit.Anim.Unbreakable && this->Data.Progress >= maxProgress) {
+		return Finish(*this, unit);
+	}
+	return false;
+}
+
+/* virtual */ void COrder_Built::Cancel(CUnit &unit)
+{
+	this->Data.Cancel = 1;
+}
+
+/* virtual */ void COrder_Built::UpdateUnitVariables(CUnit &unit) const
+{
+	Assert(unit.CurrentOrder() == this);
+
+	unit.Variable[BUILD_INDEX].Value = this->Data.Progress;
+	unit.Variable[BUILD_INDEX].Max = unit.Type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
+
+	// This should happen when building unit with several peons
+	// Maybe also with only one.
+	// FIXME : Should be better to fix it in action_{build,repair}.c ?
+	if (unit.Variable[BUILD_INDEX].Value > unit.Variable[BUILD_INDEX].Max) {
+		// assume value is wrong.
+		unit.Variable[BUILD_INDEX].Value = unit.Variable[BUILD_INDEX].Max;
+	}
+}
+
+/* virtual */ void COrder_Built::FillSeenValues(CUnit &unit) const
+{
+	unit.Seen.State = 1;
+	unit.Seen.CFrame = this->Data.Frame;
+}
+
+
+static const CConstructionFrame *FindCFramePercent(const CConstructionFrame &cframe, int percent)
+{
+	const CConstructionFrame *prev = &cframe;
+
+	for (const CConstructionFrame *it = cframe.Next; it; it = it->Next) {
+		if (percent < it->Percent) {
+			return prev;
+		}
+		prev = it;
+	}
+	return prev;
+}
+
+/**
+**  Update construction frame
+**
+**  @param unit  The building under construction.
+*/
+void COrder_Built::UpdateConstructionFrame(CUnit &unit)
+{
+	const CUnitType &type = *unit.Type;
+	const int percent = this->Data.Progress / (type.Stats[unit.Player->Index].Costs[TimeCost] * 6);
+	const CConstructionFrame *cframe = FindCFramePercent(*type.Construction->Frames, percent);
+
+	Assert(cframe != NULL);
+
+	if (cframe != this->Data.Frame) {
+		this->Data.Frame = cframe;
+		if (unit.Frame < 0) {
+			unit.Frame = -cframe->Frame - 1;
+		} else {
+			unit.Frame = cframe->Frame;
+		}
+	}
+}
+
+
+void COrder_Built::Progress(CUnit &unit, int amount)
+{
+	Boost(unit, amount, HP_INDEX);
+	Boost(unit, amount, SHIELD_INDEX);
+
+	this->Data.Progress += amount * SpeedBuild;
+	UpdateConstructionFrame(unit);
+}
+
+void COrder_Built::ProgressHp(CUnit &unit, int amount)
+{
+	Boost(unit, amount, HP_INDEX);
+
+	this->Data.Progress += amount * SpeedBuild;
+	UpdateConstructionFrame(unit);
+}
+
+
+void COrder_Built::Boost(CUnit &building, int amount, int varIndex) const
+{
+	Assert(building.CurrentOrder() == this);
+
+	const int costs = building.Stats->Costs[TimeCost] * 600;
+	const int progress = this->Data.Progress;
+	const int newProgress = progress + amount * SpeedBuild;
+	const int maxValue = building.Variable[varIndex].Max;
+
+	int &currentValue = building.Variable[varIndex].Value;
+
+	// damageValue is the current damage taken by the unit.
+	const int damageValue = (progress * maxValue) / costs - currentValue;
+	
+	// Keep the same level of damage while increasing Value.
+	currentValue = (newProgress * maxValue) / costs - damageValue;
+	currentValue = std::min(currentValue, maxValue);
+}
+
+
+
 /**
 **  Unit under Construction
 **
@@ -432,183 +664,12 @@ void HandleActionBuild(COrder& /*order*/, CUnit &unit)
 */
 void HandleActionBuilt(COrder& order, CUnit &unit)
 {
-	CUnit *worker;
-	CUnitType *type;
-	int n, mod;
-	int progress, oldprogress;
-	//For shields
-	int sn, smod;
+	Assert(order.Action == UnitActionBuilt);
 
-	type = unit.Type;
-
-	// mod is use for round to upper
-	mod = (unit.Stats->Costs[TimeCost] * 600) - unit.Variable[HP_INDEX].Value;
-	smod = (unit.Stats->Costs[TimeCost] * 600) - unit.Variable[SHIELD_INDEX].Value;
-
-	// n is the current damage taken by the unit.
-	n = (order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - 1)) / mod;
-	sn = (order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (smod - 1)) / smod;
-
-	// This below is most often 0
-	if (type->BuilderOutside) {
-		progress = unit.Type->AutoBuildRate;
-	} else {
-		progress = 100;
-		// FIXME: implement this below:
-		// unit.Data.Built.Worker->Type->BuilderSpeedFactor;
-	}
-	// Building speeds increase or decrease.
-	progress *= SpeedBuild;
-	oldprogress = order.Data.Built.Progress;
-	order.Data.Built.Progress += progress;
-	// mod is use for round to upper and use it as cache
-	mod = type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
-
-	// Keep the same level of damage while increasing HP.
-	unit.Variable[HP_INDEX].Value +=
-	 (order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n) -
-	  (oldprogress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n);
-	if (unit.Variable[HP_INDEX].Value > unit.Stats->Variables[HP_INDEX].Max) {
-		unit.Variable[HP_INDEX].Value = unit.Stats->Variables[HP_INDEX].Max;
-	}
-	if (unit.Variable[SHIELD_INDEX].Max > 0)
-	{
-		unit.Variable[SHIELD_INDEX].Value +=
-		 (order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn) -
-		  (oldprogress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn);
-		if (unit.Variable[SHIELD_INDEX].Value > unit.Stats->Variables[SHIELD_INDEX].Max) {
-			unit.Variable[SHIELD_INDEX].Value = unit.Stats->Variables[SHIELD_INDEX].Max;
-		}
-	}
-
-	// Check if construction should be canceled...
-	if (order.Data.Built.Cancel || order.Data.Built.Progress < 0) {
-		DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index _C_ unit.Type->Name.c_str());
-		// Drop out unit
-		if ((worker = order.Data.Built.Worker)) {
-
-			worker->CurrentOrder()->ClearGoal();
-			worker->ClearAction();
-			//worker->State = 0;
-
-			unit.CurrentOrder()->Data.Built.Worker = NoUnitP;
-			// HACK: make sure the sight is updated correctly
-			unit.CurrentSightRange = 1;
-			DropOutOnSide(*worker, LookingW, &unit);
-			unit.CurrentSightRange = 0;
-		}
-
-		// Player gets back 75% of the original cost for a building.
-		unit.Player->AddCostsFactor(unit.Stats->Costs, CancelBuildingCostsFactor);
-		// Cancel building
-		LetUnitDie(unit);
-		return;
-	}
-
-	//
-	// Check if building ready. Note we can both build and repair.
-	//
-	//if (unit.CurrentOrder()->Data.Built.Progress >= unit.Stats->Costs[TimeCost] * 600 ||
-	if (!order.Data.Built.Worker->Anim.Unbreakable && (order.Data.Built.Progress >= mod ||
-			unit.Variable[HP_INDEX].Value >= unit.Stats->Variables[HP_INDEX].Max)) {
-		DebugPrint("%d: Building %s(%s) ready.\n" _C_ unit.Player->Index
-		_C_ unit.Type->Ident.c_str() _C_ unit.Type->Name.c_str() );
-		if (unit.Variable[HP_INDEX].Value > unit.Stats->Variables[HP_INDEX].Max) {
-			unit.Variable[HP_INDEX].Value = unit.Stats->Variables[HP_INDEX].Max;
-		}
+	if (order.Execute(unit)) {
+		order.ClearGoal();
 		unit.ClearAction();
-		// HACK: the building is ready now
-		unit.Player->UnitTypesCount[type->Slot]++;
-		unit.Constructed = 0;
-		if (unit.Frame < 0) {
-			unit.Frame = -1;
-		} else {
-			unit.Frame = 0;
-		}
-
-		if ((worker = unit.CurrentOrder()->Data.Built.Worker)) {
-			// Bye bye worker.
-			if (type->BuilderLost) {
-				// FIXME: enough?
-				LetUnitDie(*worker);
-				worker = NULL;
-			// Drop out the worker.
-			} else {
-				worker->ClearAction();
-				worker->SubAction = 0;//may be 40
-				// HACK: make sure the sight is updated correctly
-				unit.CurrentSightRange = 1;
-				DropOutOnSide(*worker, LookingW, &unit);
-
-				worker->CurrentOrder()->ClearGoal();
-
-				//
-				// If we can harvest from the new building, do it.
-				//
-				if (worker->Type->ResInfo[type->GivesResource]) {
-					CommandResource(*worker, unit, 0);
-				}
-			}
-		}
-
-		if (type->GivesResource) {
-			// Set to Zero as it's part of a union
-			memset(&unit.CurrentOrder()->Data, 0, sizeof(unit.CurrentOrder()->Data));
-			// Has StartingResources, Use those
-			unit.ResourcesHeld = type->StartingResources;
-		}
-
-		unit.Player->Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y,
-			_("New %s done"), type->Name.c_str());
-		if (unit.Player == ThisPlayer) {
-			if (unit.Type->Sound.Ready.Sound) {
-				PlayUnitSound(unit, VoiceReady);
-			} else if (worker) {
-				PlayUnitSound(*worker, VoiceWorkCompleted);
-			} else {
-				PlayUnitSound(unit, VoiceBuilding);
-			}
-		}
-
-		if (unit.Player->AiEnabled) {
-			/* Worker can be NULL */
-			AiWorkComplete(worker, unit);
-		}
-
-		// FIXME: Vladi: this is just a hack to test wall fixing,
-		// FIXME:  also not sure if the right place...
-		// FIXME: Johns: hardcoded unit-type wall / more races!
-		if (unit.Type == UnitTypeOrcWall || unit.Type == UnitTypeHumanWall) {
-			Map.SetWall(unit.tilePos, unit.Type == UnitTypeHumanWall);
-			unit.Remove(NULL);
-			UnitLost(unit);
-			UnitClearOrders(unit);
-			unit.Release();
-			return;
-		}
-
-		UpdateForNewUnit(unit, 0);
-
-		// Set the direction of the building if it supports them
-		if (unit.Type->NumDirections > 1) {
-			if (unit.Type->Wall) { // Special logic for walls
-				CorrectWallDirections(unit);
-				CorrectWallNeighBours(unit);
-			} else {
-				unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
-			}
-			UnitUpdateHeading(unit);
-		}
-
-		if (IsOnlySelected(unit) || unit.Player == ThisPlayer) {
-			SelectedUnitChanged();
-		}
-		unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max;
-		MapMarkUnitSight(unit);
-		return;
 	}
-
-	UpdateConstructionFrame(unit);
 }
 
 //@}
diff --git a/src/action/action_repair.cpp b/src/action/action_repair.cpp
index 63ba2d25a..a4b983d3d 100644
--- a/src/action/action_repair.cpp
+++ b/src/action/action_repair.cpp
@@ -62,69 +62,45 @@
 */
 static void RepairUnit(CUnit &unit, CUnit &goal)
 {
-	CPlayer *player;
-	int animlength;
-	int hp;
+	if (goal.CurrentAction() == UnitActionBuilt) {
+		COrder_Built &order = *static_cast<COrder_Built *>(goal.CurrentOrder());
+
+		order.ProgressHp(goal, 100 * unit.CurrentOrder()->Data.Repair.Cycles);
+		unit.CurrentOrder()->Data.Repair.Cycles = 0;
+		return ;
+	}
+	CPlayer *player = unit.Player;
 	char buf[100];
 
-	player = unit.Player;
+	// Calculate the repair costs.
+	Assert(goal.Stats->Variables[HP_INDEX].Max);
 
-	if (goal.CurrentAction() != UnitActionBuilt) {
-		//
-		// Calculate the repair costs.
-		//
-		Assert(goal.Stats->Variables[HP_INDEX].Max);
-
-		//
-		// Check if enough resources are available
-		//
-		for (int i = 1; i < MaxCosts; ++i) {
-			if (player->Resources[i] < goal.Type->RepairCosts[i]) {
-				snprintf(buf, 100, _("We need more %s for repair!"),
-					DefaultResourceNames[i].c_str());
-				player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
-				if (player->AiEnabled) {
-					// FIXME: call back to AI?
-					unit.CurrentOrder()->ClearGoal();
-					if (!unit.RestoreOrder()) {
-						unit.ClearAction();
-						unit.State = 0;
-					}
+	// Check if enough resources are available
+	for (int i = 1; i < MaxCosts; ++i) {
+		if (player->Resources[i] < goal.Type->RepairCosts[i]) {
+			snprintf(buf, 100, _("We need more %s for repair!"),
+				DefaultResourceNames[i].c_str());
+			player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
+			if (player->AiEnabled) {
+				// FIXME: call back to AI?
+				unit.CurrentOrder()->ClearGoal();
+				if (!unit.RestoreOrder()) {
+					unit.ClearAction();
+					unit.State = 0;
 				}
-				// FIXME: We shouldn't animate if no resources are available.
-				return;
 			}
+			// FIXME: We shouldn't animate if no resources are available.
+			return;
 		}
-		//
-		// Subtract the resources
-		//
-		player->SubCosts(goal.Type->RepairCosts);
+	}
+	//
+	// Subtract the resources
+	//
+	player->SubCosts(goal.Type->RepairCosts);
 
-		goal.Variable[HP_INDEX].Value += goal.Type->RepairHP;
-		if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
-			goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
-		}
-	} else {
-		int costs = goal.Stats->Costs[TimeCost] * 600;
-		// hp is the current damage taken by the unit.
-		hp = (goal.CurrentOrder()->Data.Built.Progress * goal.Variable[HP_INDEX].Max) /
-			costs - goal.Variable[HP_INDEX].Value;
-		//
-		// Calculate the length of the attack (repair) anim.
-		//
-		animlength = unit.CurrentOrder()->Data.Repair.Cycles;
-		unit.CurrentOrder()->Data.Repair.Cycles = 0;
-
-		// FIXME: implement this below:
-		//unit.Data.Built.Worker->Type->BuilderSpeedFactor;
-		goal.CurrentOrder()->Data.Built.Progress += 100 * animlength * SpeedBuild;
-		// Keep the same level of damage while increasing HP.
-		goal.Variable[HP_INDEX].Value =
-			(goal.CurrentOrder()->Data.Built.Progress * goal.Stats->Variables[HP_INDEX].Max) /
-			costs - hp;
-		if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
-			goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
-		}
+	goal.Variable[HP_INDEX].Value += goal.Type->RepairHP;
+	if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
+		goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
 	}
 }
 
diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 319f2d2c4..9cf0349db 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -176,14 +176,28 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 	return order;
 }
 
-/* static */ COrder* COrder::NewActionBuilt()
+/* static */ COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit)
 {
-	COrder *order = new COrder;
+	COrder_Built* order = new COrder_Built();
 
 	order->Action = UnitActionBuilt;
+
+	// Make sure the bulding doesn't cancel itself out right away.
+
+	order->Data.Progress = 0;//FIXME ? 100 : 0
+	unit.Variable[HP_INDEX].Value = 1;
+	if (unit.Variable[SHIELD_INDEX].Max) {
+		unit.Variable[SHIELD_INDEX].Value = 1;
+	}
+	order->UpdateConstructionFrame(unit);
+
+	if (unit.Type->BuilderOutside == false) {
+		order->Data.Worker = &builder;
+	}
 	return order;
 }
 
+
 /* static */ COrder* COrder::NewActionDie()
 {
 	COrder *order = new COrder;
@@ -460,6 +474,14 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 	return order;
 }
 
+/* static */ COrder* COrder::NewActionBuilt()
+{
+	COrder *order = new COrder_Built;
+
+	order->Action = UnitActionBuilt;
+	return order;
+}
+
 /* static */ COrder* COrder::NewActionFollow()
 {
 	COrder *order = new COrder;
@@ -518,7 +540,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
 
 /* static */ COrder* COrder::NewActionSpellCast()
 {
-	COrder *order = new COrder;
+	COrder *order = new COrder_SpellCast;
 
 	order->Action = UnitActionSpellCast;
 	return order;
@@ -655,17 +677,13 @@ bool COrder::CheckRange() const
 	return (Range <= Map.Info.MapWidth || Range <= Map.Info.MapHeight);
 }
 
-void COrder::FillSeenValues(CUnit &unit) const
+/* virtual */ void COrder::FillSeenValues(CUnit &unit) const
 {
-	unit.Seen.State = (Action == UnitActionBuilt) | ((Action == UnitActionUpgradeTo) << 1);
+	unit.Seen.State = ((Action == UnitActionUpgradeTo) << 1);
 	if (unit.CurrentAction() == UnitActionDie) {
 		unit.Seen.State = 3;
 	}
-	if (Action == UnitActionBuilt) {
-		unit.Seen.CFrame = Data.Built.Frame;
-	} else {
-		unit.Seen.CFrame = NULL;
-	}
+	unit.Seen.CFrame = NULL;
 }
 
 bool COrder::OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/)
diff --git a/src/action/command.cpp b/src/action/command.cpp
index 8960c7087..22f481245 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -471,7 +471,7 @@ void CommandDismiss(CUnit &unit)
 {
 	// Check if building is still under construction? (NETWORK!)
 	if (unit.CurrentAction() == UnitActionBuilt) {
-		unit.CurrentOrder()->Data.Built.Cancel = 1;
+		unit.CurrentOrder()->Cancel(unit);
 	} else {
 		DebugPrint("Suicide unit ... \n");
 		LetUnitDie(unit);
diff --git a/src/include/actions.h b/src/include/actions.h
index a5ef7e54e..93c4e87f4 100644
--- a/src/include/actions.h
+++ b/src/include/actions.h
@@ -31,16 +31,14 @@
 #define __ACTIONS_H__
 
 //@{
-#ifndef __UNIT_CACHE_H__
-#include "unit_cache.h"
+#ifndef __UNIT_H__
+#include "unit.h"
 #endif
 
 #ifndef __VEC2I_H__
 #include "vec2i.h"
 #endif
 
-//#include "vec2i.h"
-
 /*----------------------------------------------------------------------------
 --  Declarations
 ----------------------------------------------------------------------------*/
@@ -124,6 +122,7 @@ public:
 	virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
 
 	virtual void UpdateUnitVariables(CUnit &unit) const;
+	virtual void FillSeenValues(CUnit &unit) const;
 
 
 	void ReleaseRefs(CUnit &owner);
@@ -156,7 +155,6 @@ public:
 	void NewResetPath() { Data.Move.Fast = 1; Data.Move.Length = 0; }
 	void SaveDataMove(CFile &file) const;
 
-	void FillSeenValues(CUnit &unit) const;
 
 	bool OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/);
 	void AiUnitKilled(CUnit &unit);
@@ -168,6 +166,7 @@ public:
 	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);
 	static COrder* NewActionMove(const Vec2i &pos);
@@ -235,12 +234,6 @@ public:
 #define MAX_PATH_LENGTH 28          /// max length of precalculated path
 		char Path[MAX_PATH_LENGTH]; /// directions of stored path
 	} Move; /// ActionMove,...
-	struct _order_built_ {
-		CUnit *Worker;              /// Worker building this unit
-		int Progress;               /// Progress counter, in 1/100 cycles.
-		int Cancel;                 /// Cancel construction
-		CConstructionFrame *Frame;   /// Construction frame
-	} Built; /// ActionBuilt,...
 	struct _order_build_ {
 		int Cycles;                 /// Cycles unit has been building for
 	} Build; /// ActionBuild
@@ -260,6 +253,43 @@ public:
 	} Data; /// Storage room for different commands
 };
 
+class COrder_Built : public COrder
+{
+	friend COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit);
+public:
+	virtual COrder_Built *Clone() const;
+
+	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);
+	virtual void Cancel(CUnit &unit);
+
+	virtual void UpdateUnitVariables(CUnit &unit) const;
+	virtual void FillSeenValues(CUnit &unit) const;
+
+	void Progress(CUnit & unit, int amount);
+	void ProgressHp(CUnit &unit, int amount);
+
+	const CConstructionFrame& GetFrame() const { return *Data.Frame; }
+	const CUnitPtr &GetWorker() const { return Data.Worker; }
+	CUnit *GetWorkerPtr() { return Data.Worker; }
+
+private:
+	void Boost(CUnit &building, int amount, int varIndex) const;
+	void UpdateConstructionFrame(CUnit &unit);
+
+private:
+	struct {
+		CUnitPtr Worker;            /// Worker building this unit
+		int Progress;               /// Progress counter, in 1/100 cycles.
+		int Cancel;                 /// Cancel construction
+		const CConstructionFrame *Frame;  /// Construction frame
+	} Data; /// ActionBuilt,...
+};
+
+
+
 class COrder_Research : public COrder
 {
 public:
diff --git a/src/include/script.h b/src/include/script.h
index 46efb910e..d241a44a4 100644
--- a/src/include/script.h
+++ b/src/include/script.h
@@ -284,6 +284,11 @@ extern void SaveCcl(CFile *file);     /// Save CCL module
 extern void SavePreferences();        /// Save user preferences
 extern int CclCommand(const std::string &command, bool exitOnError = true);
 
+
+CUnit *CclGetUnitFromRef(lua_State *l);
+
+
+
 extern NumberDesc *Damage;  /// Damage calculation for missile.
 
 /// transform string in corresponding index.
diff --git a/src/include/unit.h b/src/include/unit.h
index fe9179b8c..650d6aa5c 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -354,8 +354,6 @@
 #include "player.h"
 #endif
 
-#include "actions.h"
-
 #include "vec2i.h"
 
 /*----------------------------------------------------------------------------
@@ -546,7 +544,7 @@ public:
 	/* Seen stuff. */
 	int VisCount[PlayerMax];     /// Unit visibility counts
 	struct _seen_stuff_ {
-		CConstructionFrame  *CFrame;                  /// Seen construction frame
+		const CConstructionFrame  *CFrame;           /// Seen construction frame
 		int                 Frame;                   /// last seen frame/stage of buildings
 		CUnitType          *Type;                    /// Pointer to last seen unit-type
 		int                 X;                       /// Last unit->X Seen
@@ -1105,6 +1103,9 @@ extern int CanTransport(const CUnit &transporter, const CUnit &unit);
 
 	/// Generate a unit reference, a printable unique string for unit
 extern std::string UnitReference(const CUnit &unit);
+	/// Generate a unit reference, a printable unique string for unit
+extern std::string UnitReference(const CUnitPtr &unit);
+
 	/// Save an order
 extern void SaveOrder(const COrder &order, const CUnit &unit, CFile *file);
 	/// save unit-structure
diff --git a/src/map/script_map.cpp b/src/map/script_map.cpp
index 32eca5223..cc46123d4 100644
--- a/src/map/script_map.cpp
+++ b/src/map/script_map.cpp
@@ -44,7 +44,6 @@
 #include "map.h"
 #include "tileset.h"
 #include "minimap.h"
-#include "actions.h"
 #include "results.h"
 #include "ui.h"
 #include "player.h"
diff --git a/src/pathfinder/pathfinder.cpp b/src/pathfinder/pathfinder.cpp
index 495344071..f98777824 100644
--- a/src/pathfinder/pathfinder.cpp
+++ b/src/pathfinder/pathfinder.cpp
@@ -40,6 +40,7 @@
 #include "unittype.h"
 #include "unit.h"
 #include "pathfinder.h"
+#include "actions.h"
 
 //astar.cpp
 
diff --git a/src/stratagus/missile.cpp b/src/stratagus/missile.cpp
index ec86cca82..2b9c51a5f 100644
--- a/src/stratagus/missile.cpp
+++ b/src/stratagus/missile.cpp
@@ -56,6 +56,7 @@
 #include "missile.h"
 #include "sound.h"
 #include "ui.h"
+#include "actions.h"
 #include "iolib.h"
 
 #include "util.h"
diff --git a/src/stratagus/selection.cpp b/src/stratagus/selection.cpp
index 0865fa808..d3d005e27 100644
--- a/src/stratagus/selection.cpp
+++ b/src/stratagus/selection.cpp
@@ -165,7 +165,7 @@ void ChangeSelectedUnits(CUnit **units, int count)
 	if (count == 1 && units[0]->Type->ClicksToExplode &&
 		!units[0]->Type->IsNotSelectable) {
 		HandleSuicideClick(*units[0]);
-		if (units[0]->CurrentAction() == UnitActionDie) {
+		if (!units[0]->IsAlive()) {
 			NetworkSendSelection(units, count);
 			return ;
 		}
@@ -379,7 +379,7 @@ int SelectUnitsByType(CUnit &base)
 
 	// if unit is a cadaver or hidden (not on map)
 	// no unit can be selected.
-	if (base.Removed || base.CurrentAction() == UnitActionDie) {
+	if (base.Removed || base.IsAlive() == false) {
 		return 0;
 	}
 
@@ -464,7 +464,7 @@ int ToggleUnitsByType(CUnit &base)
 
 	// if unit is a cadaver or hidden (not on map)
 	// no unit can be selected.
-	if (base.Removed || base.CurrentAction() == UnitActionDie) {
+	if (base.Removed || base.IsAlive() == false) {
 		return 0;
 	}
 	// if unit isn't belonging to the player, or is a static unit
@@ -709,7 +709,7 @@ CUnit**table, int num_units = UnitMax)
 			continue;
 		}
 		// FIXME: Can we get this?
-		if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
+		if (!unit.Removed && unit.IsAlive()) {
 			SelectSingleUnit(unit);
 			return 1;
 		}
diff --git a/src/ui/botpanel.cpp b/src/ui/botpanel.cpp
index a178f83aa..16ef88b08 100644
--- a/src/ui/botpanel.cpp
+++ b/src/ui/botpanel.cpp
@@ -56,6 +56,7 @@
 #include "commands.h"
 #include "video.h"
 #include "font.h"
+#include "actions.h"
 #include "guichan/key.h"
 #include "guichan/sdl/sdlinput.h"
 
diff --git a/src/ui/button_checks.cpp b/src/ui/button_checks.cpp
index 58632a816..c5bc67146 100644
--- a/src/ui/button_checks.cpp
+++ b/src/ui/button_checks.cpp
@@ -44,6 +44,7 @@
 #include "interface.h"
 #include "network.h"
 #include "player.h"
+#include "actions.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index 8fd0fd269..cecc041b6 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -60,6 +60,7 @@
 #include "ai.h"
 #include "widgets.h"
 #include "replay.h"
+#include "actions.h"
 
 /*----------------------------------------------------------------------------
 --  Defines
diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp
index c9054ec3f..4b60fae06 100644
--- a/src/ui/mainscr.cpp
+++ b/src/ui/mainscr.cpp
@@ -59,6 +59,7 @@
 #include "network.h"
 #include "menus.h"
 #include "spells.h"
+#include "actions.h"
 #ifdef DEBUG
 #include "../ai/ai_local.h"
 #endif
@@ -285,7 +286,7 @@ UStrInt GetComponent(const CUnit &unit, int index, EnumVariable e, int t)
 **
 **  @return      The desired unit.
 */
-const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
+static const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
 {
 	switch (e) {
 		case UnitRefItSelf:
@@ -296,7 +297,9 @@ const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
 			return unit.Container;
 		case UnitRefWorker :
 			if (unit.CurrentAction() == UnitActionBuilt) {
-				return unit.CurrentOrder()->Data.Built.Worker;
+				COrder_Built &order = *static_cast<COrder_Built*>(unit.CurrentOrder());
+
+				return order.GetWorkerPtr();
 			} else {
 				return NoUnitP;
 			}
diff --git a/src/ui/mouse.cpp b/src/ui/mouse.cpp
index 7c8add4d3..6c761e27a 100644
--- a/src/ui/mouse.cpp
+++ b/src/ui/mouse.cpp
@@ -61,6 +61,7 @@
 #include "network.h"
 #include "spells.h"
 #include "widgets.h"
+#include "actions.h"
 
 /*----------------------------------------------------------------------------
 --  Variables
diff --git a/src/unit/build.cpp b/src/unit/build.cpp
index c0d1d0acb..48d4ba0fe 100644
--- a/src/unit/build.cpp
+++ b/src/unit/build.cpp
@@ -38,6 +38,7 @@
 #include "unittype.h"
 #include "map.h"
 #include "player.h"
+#include "actions.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index 0126043fd..a913f54bd 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -155,53 +155,6 @@ static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1)
 	lua_pop(l, 1);
 }
 
-/**
-**  Parse built
-**
-**  @param l     Lua state.
-**  @param order  Unit pointer which should be filled with the data.
-*/
-static void CclParseBuilt(lua_State *l, const CUnit &unit, 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, "worker")) {
-			lua_rawgeti(l, -1, j + 1);
-			order->Data.Built.Worker = CclGetUnitFromRef(l);
-			lua_pop(l, 1);
-		} else if (!strcmp(value, "progress")) {
-			lua_rawgeti(l, -1, j + 1);
-			order->Data.Built.Progress = LuaToNumber(l, -1);
-			lua_pop(l, 1);
-		} else if (!strcmp(value, "cancel")) {
-			order->Data.Built.Cancel = 1;
-			--j;
-		} else if (!strcmp(value, "frame")) {
-			lua_rawgeti(l, -1, j + 1);
-			int frame = LuaToNumber(l, -1);
-			lua_pop(l, 1);
-			CConstructionFrame *cframe = unit.Type->Construction->Frames;
-			while (frame--) {
-				cframe = cframe->Next;
-			}
-			order->Data.Built.Frame = cframe;
-		} else {
-			LuaError(l, "ParseBuilt: Unsupported tag: %s" _C_ value);
-		}
-	}
-}
-
 /**
 **  Parse res worker data
 **
@@ -419,11 +372,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU
 		this->Arg1.Resource.Pos = invalidPos;
 		this->Arg1.Resource.Mine = CclGetUnitFromRef(l);
 		lua_pop(l, 1);
-	} else if (!strcmp(value, "data-built")) {
-		++j;
-		lua_rawgeti(l, -1, j + 1);
-		CclParseBuilt(l, unit, this);
-		lua_pop(l, 1);
 	} else if (!strcmp(value, "data-res-worker")) {
 		++j;
 		lua_rawgeti(l, -1, j + 1);
diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp
index e7a9be242..6c7defc10 100644
--- a/src/unit/script_unittype.cpp
+++ b/src/unit/script_unittype.cpp
@@ -53,6 +53,7 @@
 #include "unit.h"
 #include "unit_manager.h"
 #include "player.h"
+#include "actions.h"
 #include "luacallback.h"
 
 /*----------------------------------------------------------------------------
@@ -2158,22 +2159,7 @@ static int CclDefineDecorations(lua_State *l)
 
 /* virtual */ void COrder::UpdateUnitVariables(CUnit &unit) const
 {
-	const CUnitType *type = unit.Type;
-
 	switch (unit.CurrentAction()) {
-		// Build
-		case UnitActionBuilt:
-			unit.Variable[BUILD_INDEX].Value = unit.CurrentOrder()->Data.Built.Progress;
-			unit.Variable[BUILD_INDEX].Max = type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
-
-			// This should happen when building unit with several peons
-			// Maybe also with only one.
-			// FIXME : Should be better to fix it in action_{build,repair}.c ?
-			if (unit.Variable[BUILD_INDEX].Value > unit.Variable[BUILD_INDEX].Max) {
-				// assume value is wrong.
-				unit.Variable[BUILD_INDEX].Value = unit.Variable[BUILD_INDEX].Max;
-			}
-		break;
 		// Training
 		case UnitActionTrain:
 			unit.Variable[TRAINING_INDEX].Value = unit.CurrentOrder()->Data.Train.Ticks;
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 873ddb397..ed87baf44 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -266,7 +266,9 @@ unsigned int CUnit::CurrentAction() const
 
 void CUnit::ClearAction()
 {
-	CurrentOrder()->Action = UnitActionStill;
+	delete CurrentOrder();
+	Orders[0] = COrder::NewActionStill();
+
 	SubAction = 0;
 	if (Selected) {
 		SelectedUnitChanged();
@@ -2821,16 +2823,6 @@ void LetUnitDie(CUnit &unit)
 		unit.Goal = NULL;
 	}
 
-	// During resource build, the worker holds the resource amount,
-	// but if canceling building the platform, the worker is already
-	// outside.
-	if (type->GivesResource &&
-			unit.CurrentAction() == UnitActionBuilt &&
-			unit.CurrentOrder()->Data.Built.Worker) {
-		// Restore value for oil-patch
-		unit.ResourcesHeld = unit.CurrentOrder()->Data.Built.Worker->ResourcesHeld;
-	}
-
 	// Transporters lose or save their units and building their workers
 	if (unit.UnitInside && unit.Type->SaveCargo)
 		DropOutAll(unit);
@@ -2842,7 +2834,6 @@ void LetUnitDie(CUnit &unit)
 	UnitClearOrders(unit);
 
 
-
 	// Unit has death animation.
 
 	// Not good: UnitUpdateHeading(unit);
diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp
index c21d6a05a..9fdf3e5f2 100644
--- a/src/unit/unit_draw.cpp
+++ b/src/unit/unit_draw.cpp
@@ -55,6 +55,7 @@
 #include "interface.h"
 #include "font.h"
 #include "ui.h"
+#include "actions.h"
 #include "script.h"
 
 /*----------------------------------------------------------------------------
@@ -173,7 +174,7 @@ void DrawUnitSelection(const CViewport *vp, const CUnit &unit)
 
 	const CUnitType &type = *unit.Type;
 	const PixelPos screenPos = vp->TilePosToScreen_TopLeft(unit.tilePos);
-	const int x = screenPos.x + unit.IX +type.TileWidth * PixelTileSize.x / 2
+	const int x = screenPos.x + unit.IX + type.TileWidth * PixelTileSize.x / 2
 		- type.BoxWidth / 2 - (type.Width - type.Sprite->Width) / 2;
 	const int y = screenPos.y + unit.IY + type.TileHeight * PixelTileSize.y / 2
 		- type.BoxHeight / 2 - (type.Height - type.Sprite->Height) / 2;
@@ -1080,7 +1081,7 @@ void CUnit::Draw(const CViewport *vp) const
 	int constructed;
 	CPlayerColorGraphic *sprite;
 	ResourceInfo *resinfo;
-	CConstructionFrame *cframe;
+	const CConstructionFrame *cframe;
 	CUnitType *type;
 
 	/*
@@ -1113,8 +1114,14 @@ void CUnit::Draw(const CViewport *vp) const
 		if (state == 2) {
 			type = this->CurrentOrder()->Arg1.Type;
 		}
-		// This is trash unless the unit is being built, and that's when we use it.
-		cframe = this->CurrentOrder()->Data.Built.Frame;
+
+		if (this->CurrentAction() == UnitActionBuilt) {
+			COrder_Built &order = *static_cast<COrder_Built*>(this->CurrentOrder());
+
+			cframe = &order.GetFrame();
+		} else {
+			cframe = NULL;
+		}
 	} else {
 		const Vec2i seenTilePos = {this->Seen.X, this->Seen.Y};
 		const PixelPos &screenPos = vp->TilePosToScreen_TopLeft(seenTilePos);
@@ -1257,8 +1264,13 @@ void CUnitDrawProxy::operator=(const CUnit *unit)
 		}
 
 		if (unit->Constructed) {
-			// This is trash unless the unit is being built, and that's when we use it.
-			cframe = unit->CurrentOrder()->Data.Built.Frame;
+			if (unit->CurrentAction() == UnitActionBuilt) {
+				COrder_Built &order = *static_cast<COrder_Built*>(unit->CurrentOrder());
+
+				cframe = &order.GetFrame();
+			} else {
+				cframe = NULL;
+			}
 		}
 	} else {
 		IY = unit->Seen.IY;
diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp
index 4443516c4..fed0b6265 100644
--- a/src/unit/unit_save.cpp
+++ b/src/unit/unit_save.cpp
@@ -45,6 +45,7 @@
 #include "spells.h"
 #include "construct.h"
 #include "iolib.h"
+#include "actions.h"
 
 /*----------------------------------------------------------------------------
 --  Functions
@@ -61,6 +62,20 @@ std::string UnitReference(const CUnit &unit)
 	return ss.str();
 }
 
+/**
+**  Generate a unit reference, a printable unique string for unit.
+*/
+std::string UnitReference(const CUnitPtr &unit)
+{
+	Assert(unit != NULL);
+
+	std::ostringstream ss;
+	ss << "U" << std::setfill('0') << std::setw(4) << std::uppercase <<
+		std::hex << unit->Slot;
+	return ss.str();
+}
+
+
 /**
 **  Save an order.
 **
@@ -108,9 +123,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 		case UnitActionUpgradeTo:
 			file.printf("\"action-upgrade-to\",");
 			break;
-		case UnitActionBuilt:
-			file.printf("\"action-built\",");
-			break;
 		case UnitActionBoard:
 			file.printf("\"action-board\",");
 			break;
@@ -203,28 +215,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
 			file.printf("}");
 			break;
 		case UnitActionBuilt:
-		{
-			CConstructionFrame *cframe;
-			int frame;
-
-			cframe = unit.Type->Construction->Frames;
-			frame = 0;
-			while (cframe != order.Data.Built.Frame) {
-				cframe = cframe->Next;
-				++frame;
-			}
-			file.printf(",\n  \"data-built\", {");
-
-			if (order.Data.Built.Worker) {
-				file.printf("\"worker\", \"%s\", ", UnitReference(*order.Data.Built.Worker).c_str());
-			}
-			file.printf("\"progress\", %d, \"frame\", %d", order.Data.Built.Progress, frame);
-			if (order.Data.Built.Cancel) {
-				file.printf(", \"cancel\"");
-			}
-			file.printf("}");
-			break;
-		}
 		case UnitActionResearch:
 			break;
 		case UnitActionUpgradeTo: