| Attached Files | 
 ArcWeapon&Fight.patch  (39,579 bytes) 2006-06-28 00:48   Index: rts/build/vstudio7/rts.vcproj
===================================================================
--- rts/build/vstudio7/rts.vcproj	(revision 1536)
+++ rts/build/vstudio7/rts.vcproj	(working copy)
@@ -2246,6 +2246,12 @@
 					RelativePath="..\..\System\FileSystem\ArchiveBuffered.h">
 				</File>
 				<File
+					RelativePath="..\..\System\FileSystem\ArchiveDir.cpp">
+				</File>
+				<File
+					RelativePath="..\..\System\FileSystem\ArchiveDir.h">
+				</File>
+				<File
 					RelativePath="..\..\System\FileSystem\ArchiveFactory.cpp">
 				</File>
 				<File
@@ -3026,6 +3032,12 @@
 			</Filter>
 		</Filter>
 		<File
+			RelativePath="..\..\System\IconHandler.cpp">
+		</File>
+		<File
+			RelativePath="..\..\System\IconHandler.h">
+		</File>
+		<File
 			RelativePath=".\resource.h">
 		</File>
 		<File
Index: rts/Game/command.h
===================================================================
--- rts/Game/command.h	(revision 1536)
+++ rts/Game/command.h	(working copy)
@@ -15,6 +15,7 @@
 #define CMD_WAIT 5
 #define CMD_MOVE 10
 #define CMD_PATROL 15
+#define CMD_FIGHT 16
 #define CMD_ATTACK 20
 #define CMD_AREA_ATTACK 21
 #define CMD_GUARD 25
Index: rts/Game/UI/MouseHandler.cpp
===================================================================
--- rts/Game/UI/MouseHandler.cpp	(revision 1536)
+++ rts/Game/UI/MouseHandler.cpp	(working copy)
@@ -76,6 +76,7 @@
 	cursors["Attack"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["DGun"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["Patrol"] = new CMouseCursor("cursorpatrol", CMouseCursor::Center);
+	cursors["Fight"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["Repair"] = new CMouseCursor("cursorrepair", CMouseCursor::Center);
 	cursors["Load units"] = new CMouseCursor("cursorpickup", CMouseCursor::Center);
 	cursors["Unload units"] = new CMouseCursor("cursorunload", CMouseCursor::Center);	
Index: rts/Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- rts/Sim/MoveTypes/groundmovetype.cpp	(revision 1536)
+++ rts/Sim/MoveTypes/groundmovetype.cpp	(working copy)
@@ -24,6 +24,7 @@
 #include "Mobility.h"
 #include "MoveMath/MoveMath.h"
 #include "Sim/Misc/GeometricObjects.h"
+#include "Sim/Weapons/Weapon.h"
 #include "Game/SelectedUnits.h"
 #include "Rendering/GroundDecalHandler.h"
 #include "ExternalAI/GlobalAIHandler.h"
@@ -90,7 +91,9 @@
 	nextDeltaSpeedUpdate(0),
 	nextObstacleAvoidanceUpdate(0),
 	oldPhysState(CSolidObject::OnGround),
-	lastTrackUpdate(0)
+	lastTrackUpdate(0),
+	mainHeadingPos(0,0,0),
+	useMainHeading(false)
 {
 	moveSquareX=(int)owner->pos.x/(SQUARE_SIZE*2);
 	moveSquareY=(int)owner->pos.z/(SQUARE_SIZE*2);
@@ -155,7 +158,6 @@
 		ChangeHeading(owner->heading+deltaHeading);
 	} else
 #endif
-	{
 	if(pathId || currentSpeed > 0.0) {	//TODO: Stop the unit from moving as a reaction on collision/explosion physics.
 		//Initial calculations.
 		currentDistanceToWaypoint = owner->pos.distance2D(waypoint);
@@ -191,8 +193,11 @@
 		//Apply obstacle avoidance.
 		float3 desiredVelocity = /*waypointDir/*/ObstacleAvoidance(waypointDir)/**/;
 
-		if(desiredVelocity != ZeroVector)
+		if(desiredVelocity != ZeroVector){
 			ChangeHeading(GetHeadingFromVector(desiredVelocity.x, desiredVelocity.z));
+		} else {
+			this->SetMainHeading();
+		}
 
 		if(nextDeltaSpeedUpdate<=gs->frameNum){
 			wantedSpeed = pathId ? requestedSpeed : 0;
@@ -203,8 +208,9 @@
 			wantedSpeed*=max(0.,std::min(1.,desiredVelocity.dot(owner->frontdir)+0.1));
 			SetDeltaSpeed();
 		}
+	} else {
+		this->SetMainHeading();
 	}
-	}
 
 	if(wantedSpeed>0 || currentSpeed>0) {
 
@@ -343,6 +349,7 @@
 	requestedSpeed = min(speed, maxSpeed*2);
 	requestedTurnRate = owner->mobility->maxTurnRate;
 	atGoal = false;
+	useMainHeading = false;
 
 	progressState = Active;
 
@@ -368,6 +375,7 @@
 
 	StopEngine();
 
+	this->useMainHeading = false;
 	if(progressState != Done)
 		progressState = Done;
 }
@@ -1411,3 +1419,52 @@
 {
 	oldPos=owner->pos+UpVector*0.001;
 }
+
+void CGroundMoveType::KeepPointingTo(float3 pos, float distance, bool aggressive){
+	this->mainHeadingPos = pos;
+	this->useMainHeading = aggressive;
+	if(this->useMainHeading && !this->owner->weapons.empty()){
+		float3 dir1 = this->owner->weapons.front()->mainDir;
+		dir1.y = 0;
+		dir1.Normalize();
+		float3 dir2 = this->mainHeadingPos-this->owner->pos;
+		dir2.y = 0;
+		dir2.Normalize();
+		if(dir2 != ZeroVector){
+			short heading = GetHeadingFromVector(dir2.x,dir2.z) - GetHeadingFromVector(dir1.x,dir1.z);
+			if(this->owner->heading != heading
+			  && !this->owner->weapons.front()->TryTarget(this->mainHeadingPos, true,0)){
+				this->progressState = Active;
+			}
+		}
+	}
+}
+
+/**
+* @breif Orients owner so that weapon[0]'s arc includes mainHeadingPos
+*/
+void CGroundMoveType::SetMainHeading(){
+	if(this->useMainHeading && !this->owner->weapons.empty()){
+		float3 dir1 = this->owner->weapons.front()->mainDir;
+		dir1.y = 0;
+		dir1.Normalize();
+		float3 dir2 = this->mainHeadingPos-this->owner->pos;
+		dir2.y = 0;
+		dir2.Normalize();
+		if(dir2 != ZeroVector){
+			short heading = GetHeadingFromVector(dir2.x,dir2.z) - GetHeadingFromVector(dir1.x,dir1.z);
+			if(this->progressState == Active && this->owner->heading == heading){
+				this->owner->cob->Call(COBFN_StopMoving);
+				this->progressState = Done;
+			} else if(this->progressState == Active){
+				this->ChangeHeading(heading);
+			} else if(this->progressState != Active
+			  && this->owner->heading != heading
+			  && !this->owner->weapons.front()->TryTarget(this->mainHeadingPos, true,0)){
+				this->progressState = Active;
+				this->owner->cob->Call(COBFN_StartMoving);
+				this->ChangeHeading(heading);
+			}
+		}
+	}
+}
Index: rts/Sim/MoveTypes/groundmovetype.h
===================================================================
--- rts/Sim/MoveTypes/groundmovetype.h	(revision 1536)
+++ rts/Sim/MoveTypes/groundmovetype.h	(working copy)
@@ -27,6 +27,8 @@
 	void StopMoving();
 
 	void ImpulseAdded(void);
+	
+	void KeepPointingTo(float3 pos, float distance, bool aggressive);
 
 	//float baseSpeed;		//Not used
 	//float maxSpeed;		//Moved to CMoveType, by Lars 04-08-23
@@ -120,6 +122,11 @@
 	bool CheckColV(int y, int x1, int x2, float zmove, int squareTestY);
 
 	static std::vector<int2> lineTable[11][11];
+	
+	float3 mainHeadingPos;
+	bool useMainHeading;
+	void SetMainHeading();
+
 public:
 	static void CreateLineTable(void);
 	void TestNewTerrainSquare(void);
Index: rts/Sim/Units/CommandAI/AirCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/AirCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/AirCAI.cpp	(working copy)
@@ -12,7 +12,7 @@
 #include "mmgr.h"
 
 CAirCAI::CAirCAI(CUnit* owner)
-: CCommandAI(owner)
+: CCommandAI(owner), lastPC1(-1), lastPC2(-1)
 {
 	CommandDescription c;
 	c.id=CMD_MOVE;
@@ -29,6 +29,13 @@
 	c.tooltip="Patrol: Sets the aircraft to patrol a path to one or more waypoints";
 	possibleCommands.push_back(c);
 
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order the aircraft to take action while moving to a position";
+	possibleCommands.push_back(c);
+
 	c.id=CMD_AREA_ATTACK;
 	c.type=CMDTYPE_ICON_AREA;
 	c.name="Area attack";
@@ -254,63 +261,99 @@
 		}
 		break;}
 	case CMD_PATROL:{
+		float3 curPos=owner->pos;
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in aircai",
+				owner->unitDef->humanName.c_str());
+			return;
+		}
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		break;}
+	case CMD_FIGHT:{
 		if(tempOrder){
 			tempOrder=false;
 			inCommand=true;
 		}
+		goalPos=float3(c.params[0],c.params[1],c.params[2]);
 		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
+			commandPos2=goalPos;
 			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			commandPos1=curPos;
-			activeCommand=1;
-			patrolTime=3;
 		}
-		Command& c=commandQue[activeCommand];
-		if(c.params.size()<3){
-			info->AddLine("Patrol command with insufficient parameters ?");
+		commandPos1=curPos;
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got fight cmd with less than 3 params on %s in aircai",
+				owner->unitDef->humanName.c_str());
 			return;
 		}
-		goalPos=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=goalPos;
-		patrolTime++;
 
+		float testRad=1000*owner->moveState;
+		CUnit* enemy = helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam);
 		if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){
-			if(myPlane->isFighter){
-				float testRad=1000*owner->moveState;
-				CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam);
-				if(enemy && !enemy->crashing){
-					if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){
-						Command nc;
-						nc.id=CMD_ATTACK;
-						nc.params.push_back(enemy->id);
-						nc.options=c.options;
-						commandQue.push_front(nc);
-						tempOrder=true;
-						inCommand=false;
-						SlowUpdate();
-						return;
-					}
+			if(myPlane->isFighter
+				&& enemy && !enemy->crashing
+				&& (owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000))
+			{
+				Command nc,c3;
+				c3.id = CMD_MOVE; //keep it from being pulled too far off the path
+				float3 dir = goalPos-curPos;
+				dir.Normalize();
+				dir*=sqrtf(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize);
+				dir+=curPos;
+				c3.params.push_back(dir.x);
+				c3.params.push_back(dir.y);
+				c3.params.push_back(dir.z);
+				c3.options = c.options|INTERNAL_ORDER;
+				nc.id=CMD_ATTACK;
+				nc.params.push_back(enemy->id);
+				nc.options=c.options|INTERNAL_ORDER;
+				commandQue.push_front(nc);
+				tempOrder=true;
+				inCommand=false;
+				if(lastPC1!=gs->frameNum){	//avoid infinite loops
+					lastPC1=gs->frameNum;
+					SlowUpdate();
 				}
-			}
-			if((!myPlane->isFighter || owner->moveState==2) && owner->maxRange>0){
+				return;
+			} else if(owner->maxRange>0){
 				float testRad=500*owner->moveState;
-				CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam);
-				if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)  && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)){
+				enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam);
+				if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)  && !enemy->crashing
+					&& (myPlane->isFighter || !enemy->unitDef->canfly))
+				{
 					if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){
-						Command nc;
+						Command nc,c3;
+						c3.id = CMD_MOVE; //keep it from being pulled too far off the path
+						float3 dir = goalPos-curPos;
+						dir.Normalize();
+						dir*=sqrtf(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize);
+						dir+=curPos;
+						c3.params.push_back(dir.x);
+						c3.params.push_back(dir.y);
+						c3.params.push_back(dir.z);
+						c3.options = c.options|INTERNAL_ORDER;
 						nc.id=CMD_ATTACK;
 						nc.params.push_back(enemy->id);
-						nc.options=c.options;
+						nc.options=c.options|INTERNAL_ORDER;
+						commandQue.push_front(c3);
 						commandQue.push_front(nc);
 						tempOrder=true;
 						inCommand=false;
-						SlowUpdate();
+						if(lastPC2!=gs->frameNum){	//avoid infinite loops
+							lastPC2=gs->frameNum;
+							SlowUpdate();
+						}
 						return;
 					}
 				}
@@ -319,18 +362,7 @@
 		myPlane->goalPos=goalPos;
 
 		if((owner->pos-goalPos).SqLength2D()<16000 || (owner->pos+owner->speed*8-goalPos).SqLength2D()<16000){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			commandPos1=commandPos2;
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
+			FinishCommand();
 		}
 		return;}
 	case CMD_ATTACK:
@@ -481,10 +513,11 @@
 			glColor4f(0.5,1,0.5,0.4);
 			glVertexf3(pos);	
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1]+curHeight,ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
-			glVertexf3(pos);	
+			glVertexf3(pos);
 			break;
 		case CMD_ATTACK:
 			if(ci->params.size()==1){
Index: rts/Sim/Units/CommandAI/AirCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/AirCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/AirCAI.h	(working copy)
@@ -31,8 +31,11 @@
 
 	int activeCommand;
 	int targetAge;
-	unsigned int patrolTime;
+//	unsigned int patrolTime;
 
+	int lastPC1;
+	int lastPC2;
+
 	float3 commandPos1;		//used to limit how far away stuff can fly from path
 	float3 commandPos2;
 };
Index: rts/Sim/Units/CommandAI/BuilderCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/BuilderCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/BuilderCAI.cpp	(working copy)
@@ -26,11 +26,12 @@
 CBuilderCAI::CBuilderCAI(CUnit* owner)
 : CMobileCAI(owner),
 	building(false),
-	commandFromPatrol(false),
 	buildPos(0,0,0),
 	cachedRadius(0),
 	cachedRadiusId(0),
-	buildRetries(0)
+	buildRetries(0),
+	lastPC1(-1),
+	lastPC2(-1)
 {
 	CommandDescription c;
 	c.id=CMD_REPAIR;
@@ -107,6 +108,7 @@
 
 	Command& c=commandQue.front();
 	CBuilder* fac=(CBuilder*)owner;
+	float3 curPos=owner->pos;
 
 	map<int,string>::iterator boi;
 	if((boi=buildOptions.find(c.id))!=buildOptions.end()){
@@ -114,7 +116,8 @@
 		if(cachedRadiusId==c.id){
 			radius=cachedRadius;
 		} else {
-			radius=modelParser->Load3DO(unitDefHandler->GetUnitByName(boi->second)->model.modelpath,1,owner->team)->radius;
+			radius=modelParser->Load3DO(
+				unitDefHandler->GetUnitByName(boi->second)->model.modelpath,1,owner->team)->radius;
 			cachedRadiusId=c.id;
 			cachedRadius=radius;
 		}
@@ -192,7 +195,7 @@
 	case CMD_REPAIR:{
 		if(c.params.size()==1){		//repair unit
 			CUnit* unit=uh->units[(int)c.params[0]];
-			if(commandFromPatrol && owner->moveState==1){		//limit how far away we go
+			if(tempOrder && owner->moveState==1){		//limit how far away we go
 				if(unit && LinePointDist(commandPos1,commandPos2,unit->pos) > 500){
 					StopMove();
 					FinishCommand();
@@ -360,7 +363,7 @@
 		} else if(c.params.size()==4){//area reclaim
 			float3 pos(c.params[0],c.params[1],c.params[2]);
 			float radius=c.params[3];
-			if(FindReclaimableFeatureAndReclaim(pos,radius,c.options)){
+			if(FindReclaimableFeatureAndReclaim(pos,radius,c.options,true)){
 				inCommand=false;
 				SlowUpdate();
 				return;
@@ -426,75 +429,81 @@
 		return;}
 	case CMD_PATROL:{
 		float3 curPos=owner->pos;
-		if(commandFromPatrol){
-			commandFromPatrol=false;
-			inCommand=true;
-			--patrolTime;		//prevent searching reclaimtargets etc directly if one of those call returned directly (infinite loop)
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in buildercai",
+				owner->unitDef->humanName.c_str());
+			return;
 		}
-		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		return;}
+	case CMD_FIGHT:{
+		if(tempOrder){
+			tempOrder=false;
 			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			activeCommand=1;
-			commandPos1=curPos;
-			patrolTime=0;
 		}
-		Command& c=commandQue[activeCommand];
-
 		if(c.params.size()<3){		//this shouldnt happen but anyway ...
 			info->AddLine("Error: got patrol cmd with less than 3 params on %s in BuilderCAI",owner->unitDef->humanName.c_str());
 			return;
 		}
+		if(c.params.size() >= 6){
+			if(!inCommand){
+				commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
+			}
+		} else {
+			commandPos1 = curPos;
+		}
 		patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=patrolGoal;
-
-		if(!(patrolTime&3) && owner->fireState==2){
-			if(FindRepairTargetAndRepair(owner->pos,300*owner->moveState,c.options,true)){
-				CUnit* target=uh->units[(int)commandQue.front().params[0]];
-				if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,target->pos) < 300){
-					commandFromPatrol=true;
-					inCommand=false;
+		if(!inCommand){
+			inCommand = true;
+			commandPos2=patrolGoal;
+		}
+		if(!(patrolGoal==goalPos)){
+			SetGoal(patrolGoal,curPos);
+		}
+		if(FindRepairTargetAndRepair(curPos,300*owner->moveState+fac->buildDistance-8,c.options,true)){
+			CUnit* target=uh->units[(int)commandQue.front().params[0]];
+			if(owner->moveState==2 || LinePointDist(commandPos1,commandPos2,target->pos) < 300){
+				tempOrder=true;
+				inCommand=false;
+				if(lastPC1!=gs->frameNum){	//avoid infinite loops
+					lastPC1=gs->frameNum;
 					SlowUpdate();
-					return;
-				} else {
-					commandQue.pop_front();
 				}
+				return;
+			} else {
+				commandQue.pop_front();
 			}
-			if(FindReclaimableFeatureAndReclaim(owner->pos,300*owner->moveState,c.options)){
-				commandFromPatrol=true;
-				inCommand=false;
+		}
+		if(FindReclaimableFeatureAndReclaim(owner->pos,300,c.options,false)){
+			tempOrder=true;
+			inCommand=false;
+			if(lastPC2!=gs->frameNum){	//avoid infinite loops
+				lastPC2=gs->frameNum;
 				SlowUpdate();
-				return;
 			}
+			return;
 		}
-		patrolTime++;
-		if(!(patrolGoal==goalPos)){
-			SetGoal(patrolGoal,curPos);
-		}
 		if((curPos-patrolGoal).SqLength2D()<4096){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
-			commandPos1=commandPos2;
+			FinishCommand();
+			return;
 		}
-		if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done)
+		if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done){
 			StopMove();
-		else if(owner->moveType->progressState!=CMoveType::Active)
+		} else if(owner->moveType->progressState!=CMoveType::Active){
 			owner->moveType->StartMoving(goalPos, 8);
-
+		}
 		return;}
 	case CMD_RESTORE:{
 		if(inCommand){
@@ -605,6 +614,7 @@
 			}
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
@@ -763,7 +773,7 @@
 	}
 }
 
-bool CBuilderCAI::FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options)
+bool CBuilderCAI::FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options, bool recAny)
 {
 	CFeature* best=0;
 	float bestDist=10000000;
@@ -771,7 +781,9 @@
 	for(std::vector<CFeature*>::iterator fi=features.begin();fi!=features.end();++fi){
 		if((*fi)->def->destructable && (*fi)->allyteam!=owner->allyteam){
 			float dist=(*fi)->pos.distance2D(owner->pos);
-			if(dist<bestDist){
+			if(dist<bestDist && (recAny
+			  ||((*fi)->def->energy > 0 && gs->Team(owner->team)->energy < gs->Team(owner->team)->energyStorage)
+			  ||((*fi)->def->metal > 0 && gs->Team(owner->team)->metal < gs->Team(owner->team)->metalStorage))){
 				bestDist=dist;
 				best=*fi;
 			}
@@ -779,6 +791,9 @@
 	}
 	if(best){
 		Command c2;
+		if(!recAny){
+			commandQue.push_front(this->GetReturnFight(commandQue.front()));
+		}
 		c2.options=options | INTERNAL_ORDER;
 		c2.id=CMD_RECLAIM;
 		c2.params.push_back(MAX_UNITS+best->id);
@@ -796,7 +811,8 @@
 	for(std::vector<CFeature*>::iterator fi=features.begin();fi!=features.end();++fi){
 		if((*fi)->def->destructable && (*fi)->createdFromUnit!=""){
 			float dist=(*fi)->pos.distance2D(owner->pos);
-			if(dist<bestDist){
+			if(dist<bestDist)
+			{
 				bestDist=dist;
 				best=*fi;
 			}
@@ -820,7 +836,7 @@
 	CMobileCAI::FinishCommand();
 }
 
-bool CBuilderCAI::FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options,bool attackEnemy)
+bool CBuilderCAI::FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options, bool attackEnemy)
 {
 	std::vector<CUnit*> cu=qf->GetUnits(pos,radius);
 	int myAllyteam=owner->allyteam;
@@ -829,6 +845,9 @@
 			if((*ui)->mobility && (*ui)->beingBuilt && owner->moveState<2)		//dont help factories produce units unless set on roam
 				continue;
 			Command nc;
+			if(attackEnemy){
+				commandQue.push_front(this->GetReturnFight(this->commandQue.front()));
+			}
 			nc.id=CMD_REPAIR;
 			nc.options=options | INTERNAL_ORDER;
 			nc.params.push_back((*ui)->id);
@@ -836,6 +855,7 @@
 			return true;
 		} else if(attackEnemy && owner->maxRange>0 && !gs->Ally(owner->allyteam,(*ui)->allyteam)){
 			Command nc;
+			commandQue.push_front(this->GetReturnFight(this->commandQue.front()));
 			nc.id=CMD_ATTACK;
 			nc.options=options | INTERNAL_ORDER;
 			nc.params.push_back((*ui)->id);
Index: rts/Sim/Units/CommandAI/BuilderCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/BuilderCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/BuilderCAI.h	(working copy)
@@ -17,13 +17,12 @@
 	void GiveCommand(Command& c);
 	void DrawQuedBuildingSquares(void);
 
-	bool FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options);
+	bool FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options, bool recAny);
 	bool FindResurrectableFeatureAndResurrect(float3 pos, float radius,unsigned char options);
 	void FinishCommand(void);
 	bool FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options,bool attackEnemy);
 	bool FindCaptureTargetAndCapture(float3 pos, float radius,unsigned char options);
 
-	bool commandFromPatrol;
 	map<int,string> buildOptions;
 	bool building;
 	float3 buildPos;
@@ -32,6 +31,9 @@
 	int cachedRadiusId;
 
 	int buildRetries;
+
+	int lastPC1; //helps avoid infinite loops
+	int lastPC2;
 };
 
 #endif // __BUILDER_CAI_H__
Index: rts/Sim/Units/CommandAI/CommandAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/CommandAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/CommandAI.cpp	(working copy)
@@ -295,18 +295,20 @@
 			stockpileWeapon->numStockpileQued=0;
 		UpdateStockpileIcon();
 		return; }
-	case CMD_SELFD:
+	case CMD_SELFD:{
 		if(owner->selfDCountdown){
 			owner->selfDCountdown=0;
 		} else {
 			owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1;
 		}
-		return;
+		return;}
 	}
-
+    
 	if(!(c.options & SHIFT_KEY)){
 		if(!commandQue.empty()){
-			if(commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_AREA_ATTACK || commandQue.front().id==CMD_DGUN){
+			if(commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_AREA_ATTACK
+				|| commandQue.front().id==CMD_DGUN)
+			{
 				owner->AttackUnit(0,true);
 			}
 
@@ -321,30 +323,65 @@
 			orderTarget=0;
 		}
 	}
+	if(c.id == CMD_PATROL){
+		std::deque<Command>::iterator ci = commandQue.begin();
+		for(; ci != commandQue.end() && ci->id!=CMD_PATROL; ci++);
+		if(ci==commandQue.end()){
+			if(commandQue.empty()){
+				Command c2;
+				c2.id = CMD_PATROL;
+				c2.params.push_back(owner->pos.x);
+				c2.params.push_back(owner->pos.y);
+				c2.params.push_back(owner->pos.z);
+				c2.options = c.options;
+				commandQue.push_back(c2);
+			} else {
+				do{
+					ci--;
+					if(ci->params.size() >=3){
+						Command c2;
+						c2.id = CMD_PATROL;
+						c2.params = ci->params;
+						c2.options = c.options;
+						commandQue.push_back(c2);
+						ci=commandQue.begin();
+					} else if(ci==commandQue.begin()){
+						Command c2;
+						c2.id = CMD_PATROL;
+						c2.params.push_back(owner->pos.x);
+						c2.params.push_back(owner->pos.y);
+						c2.params.push_back(owner->pos.z);
+						c2.options = c.options;
+						commandQue.push_back(c2);
+					}
+				}while(ci!=commandQue.begin());
+			}
+		}
+	}
 	std::deque<Command>::iterator ci = CCommandAI::GetCancelQueued(c);
-	if(c.id<0 && ci != this->commandQue.end()){
+	if(c.id<0 && ci != commandQue.end()){
 		do{
-			if(ci == this->commandQue.begin()){
-				this->commandQue.erase(ci);
+			if(ci == commandQue.begin()){
+				commandQue.erase(ci);
 				Command c2;
 				c2.id = CMD_STOP;
-				this->commandQue.push_front(c2);
-				this->SlowUpdate();
+				commandQue.push_front(c2);
+				SlowUpdate();
 			} else {
-				this->commandQue.erase(ci);
+				commandQue.erase(ci);
 			}
 			ci = CCommandAI::GetCancelQueued(c);
-		}while(ci != this->commandQue.end());
+		}while(ci != commandQue.end());
 		return;
-	} else if(ci != this->commandQue.end()){
-		if(ci == this->commandQue.begin()){
-			this->commandQue.erase(ci);
+	} else if(ci != commandQue.end()){
+		if(ci == commandQue.begin()){
+			commandQue.erase(ci);
 			Command c2;
 			c2.id = CMD_STOP;
-			this->commandQue.push_front(c2);
-			this->SlowUpdate();
+			commandQue.push_front(c2);
+			SlowUpdate();
 		} else {
-			this->commandQue.erase(ci);
+			commandQue.erase(ci);
 		}
 		ci = CCommandAI::GetCancelQueued(c);
 		return;
@@ -547,7 +584,7 @@
 void CCommandAI::FinishCommand(void)
 {
 	int type=commandQue.front().id;
-	if(repeatOrders && type!=CMD_STOP && !(commandQue.front().options & INTERNAL_ORDER))
+	if(repeatOrders && type!=CMD_STOP && type != CMD_PATROL && !(commandQue.front().options & INTERNAL_ORDER))
 		commandQue.push_back(commandQue.front());
 	commandQue.pop_front();
 	inCommand=false;
@@ -589,7 +626,8 @@
 	for(pci=possibleCommands.begin();pci!=possibleCommands.end();++pci){
 		if(pci->id==CMD_STOCKPILE){
 			char name[50];
-			sprintf(name,"%i/%i",stockpileWeapon->numStockpiled,stockpileWeapon->numStockpiled+stockpileWeapon->numStockpileQued);
+			sprintf(name,"%i/%i",stockpileWeapon->numStockpiled,
+				stockpileWeapon->numStockpiled+stockpileWeapon->numStockpileQued);
 			pci->name=name;
 			selectedUnits.PossibleCommandChange(owner);
 		}
@@ -598,7 +636,9 @@
 
 void CCommandAI::WeaponFired(CWeapon* weapon)
 {
-	if(weapon->weaponDef->manualfire && !weapon->weaponDef->dropped && !commandQue.empty() && (commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_DGUN) && inCommand){
+	if(weapon->weaponDef->manualfire && !weapon->weaponDef->dropped && !commandQue.empty()
+		&& (commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_DGUN) && inCommand)
+	{
 		owner->AttackUnit(0,true);
 		globalAI->WeaponFired(owner,weapon->weaponDef);
 		FinishCommand();
Index: rts/Sim/Units/CommandAI/FactoryCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/FactoryCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/FactoryCAI.cpp	(working copy)
@@ -21,12 +21,21 @@
 	c.key='M';
 	c.tooltip="Move: Order ready built units to move to a position";
 	possibleCommands.push_back(c);
+
 	c.id=CMD_PATROL;
 	c.type=CMDTYPE_ICON_MAP;
 	c.name="Patrol";
 	c.key='P';
 	c.tooltip="Patrol: Order ready built units to patrol to one or more waypoints";
 	possibleCommands.push_back(c);
+
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order ready built units to take action while moving to a position";
+	possibleCommands.push_back(c);
+
 	c.id=CMD_GUARD;
 	c.type=CMDTYPE_ICON_UNIT;
 	c.name="Guard";
@@ -220,6 +229,7 @@
 			glColor4f(0.5,1,0.5,0.4);
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1]+3,ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
Index: rts/Sim/Units/CommandAI/MobileCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/MobileCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/MobileCAI.cpp	(working copy)
@@ -17,8 +17,7 @@
 
 CMobileCAI::CMobileCAI(CUnit* owner)
 : CCommandAI(owner),
-	activeCommand(0),
-	patrolTime(0),
+//	patrolTime(0),
 	goalPos(-1,-1,-1),
 	tempOrder(false),
 	patrolGoal(1,1,1),
@@ -28,7 +27,8 @@
 	maxWantedSpeed(0),
 	lastIdleCheck(0),
 	commandPos1(ZeroVector),
-	commandPos2(ZeroVector)
+	commandPos2(ZeroVector),
+	lastPC(-1)
 {
 	lastUserGoal=owner->pos;
 
@@ -48,6 +48,15 @@
 	c.tooltip="Patrol: Order the unit to patrol to one or more waypoints";
 	possibleCommands.push_back(c);
 
+	c.params.clear();
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order the unit to take action while moving to a position";
+	possibleCommands.push_back(c);
+
+
 	c.id=CMD_GUARD;
 	c.type=CMDTYPE_ICON_UNIT;
 	c.name="Guard";
@@ -114,7 +123,6 @@
 	}
 
 	if(!(c.options & SHIFT_KEY) && nonQueingCommands.find(c.id)==nonQueingCommands.end()){
-		activeCommand=0;
 		tempOrder=false;
 	}
 	CCommandAI::GiveCommand(c);
@@ -154,72 +162,83 @@
 		}
 		break;}
 	case CMD_PATROL:{
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in mobilecai",
+				owner->unitDef->humanName.c_str());
+			return;
+		}
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		return;}
+	case CMD_FIGHT:{
 		if(tempOrder){
-			tempOrder=false;
-			inCommand=true;
-			patrolTime=1;
+			inCommand = true;
+			tempOrder = false;
 		}
-		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
-			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			activeCommand=1;
-			commandPos1=curPos;
-			patrolTime=1;
-		}
-		Command& c=commandQue[activeCommand];
 		if(c.params.size()<3){		//this shouldnt happen but anyway ...
-			info->AddLine("Error: got patrol cmd with less than 3 params on %s in mobilecai",owner->unitDef->humanName.c_str());
+			info->AddLine("Error: got fight cmd with less than 3 params on %s in mobilecai",
+				owner->unitDef->humanName.c_str());
 			return;
 		}
-		patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=patrolGoal;
-		patrolTime++;
+		if(c.params.size() >= 6){
+			if(!inCommand){
+				commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
+			}
+		} else {
+			commandPos1 = curPos;
+		}
+		float3 pos(c.params[0],c.params[1],c.params[2]);
+		if(!inCommand){
+			inCommand = true;
+			commandPos2 = pos;
+		}
+		if(pos!=goalPos){
+			SetGoal(pos,curPos);
+		}
 
-		if(!(patrolTime&1) && owner->fireState==2){
-			CUnit* enemy=helper->GetClosestEnemyUnit(curPos,owner->maxRange+100*owner->moveState*owner->moveState,owner->allyteam);
-			if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()){			//todo: make sure they dont stray to far from path
-				if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 300+owner->maxRange){
-					Command c2;
+		if(owner->fireState==2){
+			CUnit* enemy=helper->GetClosestEnemyUnit(
+				curPos, owner->maxRange+100*owner->moveState*owner->moveState, owner->allyteam);
+			if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
+			  && !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()){	//todo: make sure they dont stray to far from path
+				if(owner->moveState!=1 
+				  || LinePointDist(commandPos1,commandPos2,enemy->pos)
+				  < 300+max(owner->maxRange, (float)owner->losRadius)){
+					Command c2,c3;
+					c3 = this->GetReturnFight(c);
 					c2.id=CMD_ATTACK;
-					c2.options=c.options;
+					c2.options=c.options|INTERNAL_ORDER;
 					c2.params.push_back(enemy->id);
+					commandQue.push_front(c3);
 					commandQue.push_front(c2);
 					inCommand=false;
 					tempOrder=true;
-					SlowUpdate();				//if attack can finish immidiatly this could lead to an infinite loop so make sure it doesnt
+					if(lastPC!=gs->frameNum){	//avoid infinite loops
+						lastPC=gs->frameNum;
+						SlowUpdate();
+					}
 					return;
 				}
 			}
 		}
-		if((curPos-patrolGoal).SqLength2D()<4096 || owner->moveType->progressState==CMoveType::Failed){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
-			Command& c=commandQue[activeCommand];
-			patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-			commandPos1=commandPos2;
-			commandPos2=patrolGoal;
+		if((curPos-goalPos).SqLength2D()<4096 || owner->moveType->progressState==CMoveType::Failed){
+			FinishCommand();
 		}
-		if((patrolGoal!=goalPos)){
-			SetGoal(patrolGoal,curPos);
-		}
 		return;}
 	case CMD_DGUN:
-		if(uh->limitDgun && owner->unitDef->isCommander && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
+		if(uh->limitDgun && owner->unitDef->isCommander
+		  && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
 			StopMove();
 			FinishCommand();
 			return;
@@ -259,33 +278,35 @@
 		}
 		if(orderTarget){
 			//note that we handle aircrafts slightly differently
-			if(((owner->AttackUnit(orderTarget, c.id==CMD_DGUN) || dynamic_cast<CTAAirMoveType*>(owner->moveType)) && (owner->pos-orderTarget->pos).Length2D()<owner->maxRange*0.9) || (owner->pos-orderTarget->pos).SqLength2D()<1024){
-				//					if(owner->isMoving) {
+			if((((owner->AttackUnit(orderTarget, c.id==CMD_DGUN) && owner->weapons.size() > 0
+			  && owner->weapons.front()->range > orderTarget->pos.distance(owner->pos))
+			  || dynamic_cast<CTAAirMoveType*>(owner->moveType))
+			  && (owner->pos-orderTarget->pos).Length2D()<owner->maxRange*0.9)
+			  || (owner->pos-orderTarget->pos).SqLength2D()<1024){
 				StopMove();
-				owner->moveType->KeepPointingTo(orderTarget->pos, min((double)(owner->losRadius*SQUARE_SIZE*2),owner->maxRange*0.9), true);
-				//					}
-			} else {
-				if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos)>10+orderTarget->pos.distance2D(owner->pos)*0.2)
-				{
-					float3 fix=orderTarget->pos+owner->posErrorVector*128;
-					SetGoal(fix,curPos);
-				}
+				owner->moveType->KeepPointingTo(orderTarget->pos, min((double)(owner->losRadius*SQUARE_SIZE*2),
+					owner->maxRange*0.9), true);
+			} else if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos)
+			  > 10+orderTarget->pos.distance2D(owner->pos)*0.2){
+				  float3 fix=orderTarget->pos+owner->posErrorVector*128;
+				  SetGoal(fix,curPos);
 			}
 		} else {
 			float3 pos(c.params[0],c.params[1],c.params[2]);
-			if(owner->AttackGround(pos,c.id==CMD_DGUN) || (owner->pos-pos).SqLength2D()<1024) {
+			if((owner->AttackGround(pos,c.id==CMD_DGUN) && owner->weapons.size() > 0
+			  && (owner->pos-pos).Length()< owner->weapons.front()->range) || (owner->pos-pos).SqLength2D()<1024){
 				StopMove();
 				owner->moveType->KeepPointingTo(pos, owner->maxRange*0.9, true);
-			} else {
-				if(pos.distance2D(goalPos)>10)
-					SetGoal(pos,curPos);					
+			} else if(pos.distance2D(goalPos)>10){
+				SetGoal(pos,curPos);					
 			}
 		}
 		break;
 	case CMD_GUARD:
 		if(uh->units[int(c.params[0])]!=0){
 			CUnit* guarded=uh->units[int(c.params[0])];
-			if(guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
+			if(guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum
+			  && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
 				Command nc;
 				nc.id=CMD_ATTACK;
 				nc.params.push_back(guarded->lastAttacker->id);
@@ -357,6 +378,7 @@
 			draw=true;
 			break;
 		case CMD_PATROL:
+		case CMD_FIGHT:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
 			draw=true;
@@ -424,7 +446,6 @@
 		lastUserGoal=owner->pos;
 //		info->AddLine("Reseting user goal");
 	}
-
 	CCommandAI::FinishCommand();
 }
 
@@ -471,3 +492,34 @@
 		NonMoving();
 	}
 }
+
+/**
+* @brief gets the command that keeps the unit close to the path
+* @return a Fight Command with 6 arguments, the first three being where to return to (the current position of the
+*	unit), and the second being the location of the origional command.
+* @param c the command to return to
+**/
+Command CMobileCAI::GetReturnFight(Command c){
+	Command c3;
+	c3.id = CMD_FIGHT; //keep it from being pulled too far off the path
+	float3 pos = float3(c.params[0],c.params[1],c.params[2]);
+	const float3 &curPos = this->owner->pos;
+	float3 dir = pos-curPos;
+	dir.Normalize();
+	dir*=sqrtf(abs(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize));
+	dir+=curPos;
+	c3.params.push_back(dir.x);
+	c3.params.push_back(dir.y);
+	c3.params.push_back(dir.z);
+	if(c.params.size() >= 6){
+		c3.params.push_back(c.params[3]);
+		c3.params.push_back(c.params[4]);
+		c3.params.push_back(c.params[5]);
+	} else {
+		c3.params.push_back(c.params[0]);
+		c3.params.push_back(c.params[1]);
+		c3.params.push_back(c.params[2]);
+	}
+	c3.options = c.options|INTERNAL_ORDER;
+	return c3;
+}
\ No newline at end of file
Index: rts/Sim/Units/CommandAI/MobileCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/MobileCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/MobileCAI.h	(working copy)
@@ -20,17 +20,19 @@
 	void NonMoving(void);
 	void FinishCommand(void);
 	void IdleCheck(void);
+	Command GetReturnFight(Command c);
 
 	float3 goalPos;
 	float3 patrolGoal;
 	float3 lastUserGoal;
 
-	int activeCommand;
 	int lastIdleCheck;
 	bool tempOrder;
 
-	unsigned int patrolTime;
+	int lastPC; //helps avoid infinate loops
 
+//	unsigned int patrolTime;
+
 	float maxWantedSpeed;
 
 	int lastBuggerOffTime;
Index: rts/Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/TransportCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/TransportCAI.cpp	(working copy)
@@ -334,6 +334,7 @@
 			glColor4f(0.5,1,0.5,0.4);
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
 ArcWeapon&Fight(1).patch  (39,820 bytes) 2006-07-01 10:35   Index: rts/Game/command.h
===================================================================
--- rts/Game/command.h	(revision 1536)
+++ rts/Game/command.h	(working copy)
@@ -15,6 +15,7 @@
 #define CMD_WAIT 5
 #define CMD_MOVE 10
 #define CMD_PATROL 15
+#define CMD_FIGHT 16
 #define CMD_ATTACK 20
 #define CMD_AREA_ATTACK 21
 #define CMD_GUARD 25
Index: rts/Game/UI/MouseHandler.cpp
===================================================================
--- rts/Game/UI/MouseHandler.cpp	(revision 1536)
+++ rts/Game/UI/MouseHandler.cpp	(working copy)
@@ -76,6 +76,7 @@
 	cursors["Attack"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["DGun"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["Patrol"] = new CMouseCursor("cursorpatrol", CMouseCursor::Center);
+	cursors["Fight"] = new CMouseCursor("cursorattack", CMouseCursor::Center);
 	cursors["Repair"] = new CMouseCursor("cursorrepair", CMouseCursor::Center);
 	cursors["Load units"] = new CMouseCursor("cursorpickup", CMouseCursor::Center);
 	cursors["Unload units"] = new CMouseCursor("cursorunload", CMouseCursor::Center);	
Index: rts/Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- rts/Sim/MoveTypes/groundmovetype.cpp	(revision 1536)
+++ rts/Sim/MoveTypes/groundmovetype.cpp	(working copy)
@@ -24,6 +24,7 @@
 #include "Mobility.h"
 #include "MoveMath/MoveMath.h"
 #include "Sim/Misc/GeometricObjects.h"
+#include "Sim/Weapons/Weapon.h"
 #include "Game/SelectedUnits.h"
 #include "Rendering/GroundDecalHandler.h"
 #include "ExternalAI/GlobalAIHandler.h"
@@ -90,7 +91,9 @@
 	nextDeltaSpeedUpdate(0),
 	nextObstacleAvoidanceUpdate(0),
 	oldPhysState(CSolidObject::OnGround),
-	lastTrackUpdate(0)
+	lastTrackUpdate(0),
+	mainHeadingPos(0,0,0),
+	useMainHeading(false)
 {
 	moveSquareX=(int)owner->pos.x/(SQUARE_SIZE*2);
 	moveSquareY=(int)owner->pos.z/(SQUARE_SIZE*2);
@@ -155,7 +158,6 @@
 		ChangeHeading(owner->heading+deltaHeading);
 	} else
 #endif
-	{
 	if(pathId || currentSpeed > 0.0) {	//TODO: Stop the unit from moving as a reaction on collision/explosion physics.
 		//Initial calculations.
 		currentDistanceToWaypoint = owner->pos.distance2D(waypoint);
@@ -191,8 +193,11 @@
 		//Apply obstacle avoidance.
 		float3 desiredVelocity = /*waypointDir/*/ObstacleAvoidance(waypointDir)/**/;
 
-		if(desiredVelocity != ZeroVector)
+		if(desiredVelocity != ZeroVector){
 			ChangeHeading(GetHeadingFromVector(desiredVelocity.x, desiredVelocity.z));
+		} else {
+			this->SetMainHeading();
+		}
 
 		if(nextDeltaSpeedUpdate<=gs->frameNum){
 			wantedSpeed = pathId ? requestedSpeed : 0;
@@ -203,8 +208,9 @@
 			wantedSpeed*=max(0.,std::min(1.,desiredVelocity.dot(owner->frontdir)+0.1));
 			SetDeltaSpeed();
 		}
+	} else {
+		this->SetMainHeading();
 	}
-	}
 
 	if(wantedSpeed>0 || currentSpeed>0) {
 
@@ -343,6 +349,7 @@
 	requestedSpeed = min(speed, maxSpeed*2);
 	requestedTurnRate = owner->mobility->maxTurnRate;
 	atGoal = false;
+	useMainHeading = false;
 
 	progressState = Active;
 
@@ -368,6 +375,7 @@
 
 	StopEngine();
 
+	this->useMainHeading = false;
 	if(progressState != Done)
 		progressState = Done;
 }
@@ -1411,3 +1419,52 @@
 {
 	oldPos=owner->pos+UpVector*0.001;
 }
+
+void CGroundMoveType::KeepPointingTo(float3 pos, float distance, bool aggressive){
+	this->mainHeadingPos = pos;
+	this->useMainHeading = aggressive;
+	if(this->useMainHeading && !this->owner->weapons.empty()){
+		float3 dir1 = this->owner->weapons.front()->mainDir;
+		dir1.y = 0;
+		dir1.Normalize();
+		float3 dir2 = this->mainHeadingPos-this->owner->pos;
+		dir2.y = 0;
+		dir2.Normalize();
+		if(dir2 != ZeroVector){
+			short heading = GetHeadingFromVector(dir2.x,dir2.z) - GetHeadingFromVector(dir1.x,dir1.z);
+			if(this->owner->heading != heading
+			  && !this->owner->weapons.front()->TryTarget(this->mainHeadingPos, true,0)){
+				this->progressState = Active;
+			}
+		}
+	}
+}
+
+/**
+* @breif Orients owner so that weapon[0]'s arc includes mainHeadingPos
+*/
+void CGroundMoveType::SetMainHeading(){
+	if(this->useMainHeading && !this->owner->weapons.empty()){
+		float3 dir1 = this->owner->weapons.front()->mainDir;
+		dir1.y = 0;
+		dir1.Normalize();
+		float3 dir2 = this->mainHeadingPos-this->owner->pos;
+		dir2.y = 0;
+		dir2.Normalize();
+		if(dir2 != ZeroVector){
+			short heading = GetHeadingFromVector(dir2.x,dir2.z) - GetHeadingFromVector(dir1.x,dir1.z);
+			if(this->progressState == Active && this->owner->heading == heading){
+				this->owner->cob->Call(COBFN_StopMoving);
+				this->progressState = Done;
+			} else if(this->progressState == Active){
+				this->ChangeHeading(heading);
+			} else if(this->progressState != Active
+			  && this->owner->heading != heading
+			  && !this->owner->weapons.front()->TryTarget(this->mainHeadingPos, true,0)){
+				this->progressState = Active;
+				this->owner->cob->Call(COBFN_StartMoving);
+				this->ChangeHeading(heading);
+			}
+		}
+	}
+}
Index: rts/Sim/MoveTypes/groundmovetype.h
===================================================================
--- rts/Sim/MoveTypes/groundmovetype.h	(revision 1536)
+++ rts/Sim/MoveTypes/groundmovetype.h	(working copy)
@@ -27,6 +27,8 @@
 	void StopMoving();
 
 	void ImpulseAdded(void);
+	
+	void KeepPointingTo(float3 pos, float distance, bool aggressive);
 
 	//float baseSpeed;		//Not used
 	//float maxSpeed;		//Moved to CMoveType, by Lars 04-08-23
@@ -120,6 +122,11 @@
 	bool CheckColV(int y, int x1, int x2, float zmove, int squareTestY);
 
 	static std::vector<int2> lineTable[11][11];
+	
+	float3 mainHeadingPos;
+	bool useMainHeading;
+	void SetMainHeading();
+
 public:
 	static void CreateLineTable(void);
 	void TestNewTerrainSquare(void);
Index: rts/Sim/Units/CommandAI/AirCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/AirCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/AirCAI.cpp	(working copy)
@@ -12,7 +12,7 @@
 #include "mmgr.h"
 
 CAirCAI::CAirCAI(CUnit* owner)
-: CCommandAI(owner)
+: CCommandAI(owner), lastPC1(-1), lastPC2(-1)
 {
 	CommandDescription c;
 	c.id=CMD_MOVE;
@@ -29,6 +29,13 @@
 	c.tooltip="Patrol: Sets the aircraft to patrol a path to one or more waypoints";
 	possibleCommands.push_back(c);
 
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order the aircraft to take action while moving to a position";
+	possibleCommands.push_back(c);
+
 	c.id=CMD_AREA_ATTACK;
 	c.type=CMDTYPE_ICON_AREA;
 	c.name="Area attack";
@@ -254,63 +261,99 @@
 		}
 		break;}
 	case CMD_PATROL:{
+		float3 curPos=owner->pos;
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in aircai",
+				owner->unitDef->humanName.c_str());
+			return;
+		}
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		break;}
+	case CMD_FIGHT:{
 		if(tempOrder){
 			tempOrder=false;
 			inCommand=true;
 		}
+		goalPos=float3(c.params[0],c.params[1],c.params[2]);
 		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
+			commandPos2=goalPos;
 			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			commandPos1=curPos;
-			activeCommand=1;
-			patrolTime=3;
 		}
-		Command& c=commandQue[activeCommand];
-		if(c.params.size()<3){
-			info->AddLine("Patrol command with insufficient parameters ?");
+		commandPos1=curPos;
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got fight cmd with less than 3 params on %s in aircai",
+				owner->unitDef->humanName.c_str());
 			return;
 		}
-		goalPos=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=goalPos;
-		patrolTime++;
 
+		float testRad=1000*owner->moveState;
+		CUnit* enemy = helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam);
 		if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){
-			if(myPlane->isFighter){
-				float testRad=1000*owner->moveState;
-				CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam);
-				if(enemy && !enemy->crashing){
-					if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){
-						Command nc;
-						nc.id=CMD_ATTACK;
-						nc.params.push_back(enemy->id);
-						nc.options=c.options;
-						commandQue.push_front(nc);
-						tempOrder=true;
-						inCommand=false;
-						SlowUpdate();
-						return;
-					}
+			if(myPlane->isFighter
+				&& enemy && !enemy->crashing
+				&& (owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000))
+			{
+				Command nc,c3;
+				c3.id = CMD_MOVE; //keep it from being pulled too far off the path
+				float3 dir = goalPos-curPos;
+				dir.Normalize();
+				dir*=sqrtf(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize);
+				dir+=curPos;
+				c3.params.push_back(dir.x);
+				c3.params.push_back(dir.y);
+				c3.params.push_back(dir.z);
+				c3.options = c.options|INTERNAL_ORDER;
+				nc.id=CMD_ATTACK;
+				nc.params.push_back(enemy->id);
+				nc.options=c.options|INTERNAL_ORDER;
+				commandQue.push_front(nc);
+				tempOrder=true;
+				inCommand=false;
+				if(lastPC1!=gs->frameNum){	//avoid infinite loops
+					lastPC1=gs->frameNum;
+					SlowUpdate();
 				}
-			}
-			if((!myPlane->isFighter || owner->moveState==2) && owner->maxRange>0){
+				return;
+			} else if(owner->maxRange>0){
 				float testRad=500*owner->moveState;
-				CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam);
-				if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)  && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)){
+				enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam);
+				if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)  && !enemy->crashing
+					&& (myPlane->isFighter || !enemy->unitDef->canfly))
+				{
 					if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){
-						Command nc;
+						Command nc,c3;
+						c3.id = CMD_MOVE; //keep it from being pulled too far off the path
+						float3 dir = goalPos-curPos;
+						dir.Normalize();
+						dir*=sqrtf(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize);
+						dir+=curPos;
+						c3.params.push_back(dir.x);
+						c3.params.push_back(dir.y);
+						c3.params.push_back(dir.z);
+						c3.options = c.options|INTERNAL_ORDER;
 						nc.id=CMD_ATTACK;
 						nc.params.push_back(enemy->id);
-						nc.options=c.options;
+						nc.options=c.options|INTERNAL_ORDER;
+						commandQue.push_front(c3);
 						commandQue.push_front(nc);
 						tempOrder=true;
 						inCommand=false;
-						SlowUpdate();
+						if(lastPC2!=gs->frameNum){	//avoid infinite loops
+							lastPC2=gs->frameNum;
+							SlowUpdate();
+						}
 						return;
 					}
 				}
@@ -319,18 +362,7 @@
 		myPlane->goalPos=goalPos;
 
 		if((owner->pos-goalPos).SqLength2D()<16000 || (owner->pos+owner->speed*8-goalPos).SqLength2D()<16000){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			commandPos1=commandPos2;
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
+			FinishCommand();
 		}
 		return;}
 	case CMD_ATTACK:
@@ -481,10 +513,11 @@
 			glColor4f(0.5,1,0.5,0.4);
 			glVertexf3(pos);	
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1]+curHeight,ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
-			glVertexf3(pos);	
+			glVertexf3(pos);
 			break;
 		case CMD_ATTACK:
 			if(ci->params.size()==1){
Index: rts/Sim/Units/CommandAI/AirCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/AirCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/AirCAI.h	(working copy)
@@ -31,8 +31,11 @@
 
 	int activeCommand;
 	int targetAge;
-	unsigned int patrolTime;
+//	unsigned int patrolTime;
 
+	int lastPC1;
+	int lastPC2;
+
 	float3 commandPos1;		//used to limit how far away stuff can fly from path
 	float3 commandPos2;
 };
Index: rts/Sim/Units/CommandAI/BuilderCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/BuilderCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/BuilderCAI.cpp	(working copy)
@@ -26,11 +26,12 @@
 CBuilderCAI::CBuilderCAI(CUnit* owner)
 : CMobileCAI(owner),
 	building(false),
-	commandFromPatrol(false),
 	buildPos(0,0,0),
 	cachedRadius(0),
 	cachedRadiusId(0),
-	buildRetries(0)
+	buildRetries(0),
+	lastPC1(-1),
+	lastPC2(-1)
 {
 	CommandDescription c;
 	c.id=CMD_REPAIR;
@@ -107,6 +108,7 @@
 
 	Command& c=commandQue.front();
 	CBuilder* fac=(CBuilder*)owner;
+	float3 curPos=owner->pos;
 
 	map<int,string>::iterator boi;
 	if((boi=buildOptions.find(c.id))!=buildOptions.end()){
@@ -114,7 +116,8 @@
 		if(cachedRadiusId==c.id){
 			radius=cachedRadius;
 		} else {
-			radius=modelParser->Load3DO(unitDefHandler->GetUnitByName(boi->second)->model.modelpath,1,owner->team)->radius;
+			radius=modelParser->Load3DO(
+				unitDefHandler->GetUnitByName(boi->second)->model.modelpath,1,owner->team)->radius;
 			cachedRadiusId=c.id;
 			cachedRadius=radius;
 		}
@@ -192,7 +195,7 @@
 	case CMD_REPAIR:{
 		if(c.params.size()==1){		//repair unit
 			CUnit* unit=uh->units[(int)c.params[0]];
-			if(commandFromPatrol && owner->moveState==1){		//limit how far away we go
+			if(tempOrder && owner->moveState==1){		//limit how far away we go
 				if(unit && LinePointDist(commandPos1,commandPos2,unit->pos) > 500){
 					StopMove();
 					FinishCommand();
@@ -360,7 +363,7 @@
 		} else if(c.params.size()==4){//area reclaim
 			float3 pos(c.params[0],c.params[1],c.params[2]);
 			float radius=c.params[3];
-			if(FindReclaimableFeatureAndReclaim(pos,radius,c.options)){
+			if(FindReclaimableFeatureAndReclaim(pos,radius,c.options,true)){
 				inCommand=false;
 				SlowUpdate();
 				return;
@@ -426,75 +429,81 @@
 		return;}
 	case CMD_PATROL:{
 		float3 curPos=owner->pos;
-		if(commandFromPatrol){
-			commandFromPatrol=false;
-			inCommand=true;
-			--patrolTime;		//prevent searching reclaimtargets etc directly if one of those call returned directly (infinite loop)
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in buildercai",
+				owner->unitDef->humanName.c_str());
+			return;
 		}
-		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		return;}
+	case CMD_FIGHT:{
+		if(tempOrder){
+			tempOrder=false;
 			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			activeCommand=1;
-			commandPos1=curPos;
-			patrolTime=0;
 		}
-		Command& c=commandQue[activeCommand];
-
 		if(c.params.size()<3){		//this shouldnt happen but anyway ...
 			info->AddLine("Error: got patrol cmd with less than 3 params on %s in BuilderCAI",owner->unitDef->humanName.c_str());
 			return;
 		}
+		if(c.params.size() >= 6){
+			if(!inCommand){
+				commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
+			}
+		} else {
+			commandPos1 = curPos;
+		}
 		patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=patrolGoal;
-
-		if(!(patrolTime&3) && owner->fireState==2){
-			if(FindRepairTargetAndRepair(owner->pos,300*owner->moveState,c.options,true)){
-				CUnit* target=uh->units[(int)commandQue.front().params[0]];
-				if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,target->pos) < 300){
-					commandFromPatrol=true;
-					inCommand=false;
+		if(!inCommand){
+			inCommand = true;
+			commandPos2=patrolGoal;
+		}
+		if(!(patrolGoal==goalPos)){
+			SetGoal(patrolGoal,curPos);
+		}
+		if(FindRepairTargetAndRepair(curPos,300*owner->moveState+fac->buildDistance-8,c.options,true)){
+			CUnit* target=uh->units[(int)commandQue.front().params[0]];
+			if(owner->moveState==2 || LinePointDist(commandPos1,commandPos2,target->pos) < 300){
+				tempOrder=true;
+				inCommand=false;
+				if(lastPC1!=gs->frameNum){	//avoid infinite loops
+					lastPC1=gs->frameNum;
 					SlowUpdate();
-					return;
-				} else {
-					commandQue.pop_front();
 				}
+				return;
+			} else {
+				commandQue.pop_front();
 			}
-			if(FindReclaimableFeatureAndReclaim(owner->pos,300*owner->moveState,c.options)){
-				commandFromPatrol=true;
-				inCommand=false;
+		}
+		if(FindReclaimableFeatureAndReclaim(owner->pos,300,c.options,false)){
+			tempOrder=true;
+			inCommand=false;
+			if(lastPC2!=gs->frameNum){	//avoid infinite loops
+				lastPC2=gs->frameNum;
 				SlowUpdate();
-				return;
 			}
+			return;
 		}
-		patrolTime++;
-		if(!(patrolGoal==goalPos)){
-			SetGoal(patrolGoal,curPos);
-		}
 		if((curPos-patrolGoal).SqLength2D()<4096){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
-			commandPos1=commandPos2;
+			FinishCommand();
+			return;
 		}
-		if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done)
+		if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done){
 			StopMove();
-		else if(owner->moveType->progressState!=CMoveType::Active)
+		} else if(owner->moveType->progressState!=CMoveType::Active){
 			owner->moveType->StartMoving(goalPos, 8);
-
+		}
 		return;}
 	case CMD_RESTORE:{
 		if(inCommand){
@@ -605,6 +614,7 @@
 			}
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
@@ -763,7 +773,7 @@
 	}
 }
 
-bool CBuilderCAI::FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options)
+bool CBuilderCAI::FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options, bool recAny)
 {
 	CFeature* best=0;
 	float bestDist=10000000;
@@ -771,7 +781,9 @@
 	for(std::vector<CFeature*>::iterator fi=features.begin();fi!=features.end();++fi){
 		if((*fi)->def->destructable && (*fi)->allyteam!=owner->allyteam){
 			float dist=(*fi)->pos.distance2D(owner->pos);
-			if(dist<bestDist){
+			if(dist<bestDist && (recAny
+			  ||((*fi)->def->energy > 0 && gs->Team(owner->team)->energy < gs->Team(owner->team)->energyStorage)
+			  ||((*fi)->def->metal > 0 && gs->Team(owner->team)->metal < gs->Team(owner->team)->metalStorage))){
 				bestDist=dist;
 				best=*fi;
 			}
@@ -779,6 +791,9 @@
 	}
 	if(best){
 		Command c2;
+		if(!recAny){
+			commandQue.push_front(this->GetReturnFight(commandQue.front()));
+		}
 		c2.options=options | INTERNAL_ORDER;
 		c2.id=CMD_RECLAIM;
 		c2.params.push_back(MAX_UNITS+best->id);
@@ -796,7 +811,8 @@
 	for(std::vector<CFeature*>::iterator fi=features.begin();fi!=features.end();++fi){
 		if((*fi)->def->destructable && (*fi)->createdFromUnit!=""){
 			float dist=(*fi)->pos.distance2D(owner->pos);
-			if(dist<bestDist){
+			if(dist<bestDist)
+			{
 				bestDist=dist;
 				best=*fi;
 			}
@@ -820,7 +836,7 @@
 	CMobileCAI::FinishCommand();
 }
 
-bool CBuilderCAI::FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options,bool attackEnemy)
+bool CBuilderCAI::FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options, bool attackEnemy)
 {
 	std::vector<CUnit*> cu=qf->GetUnits(pos,radius);
 	int myAllyteam=owner->allyteam;
@@ -829,6 +845,9 @@
 			if((*ui)->mobility && (*ui)->beingBuilt && owner->moveState<2)		//dont help factories produce units unless set on roam
 				continue;
 			Command nc;
+			if(attackEnemy){
+				commandQue.push_front(this->GetReturnFight(this->commandQue.front()));
+			}
 			nc.id=CMD_REPAIR;
 			nc.options=options | INTERNAL_ORDER;
 			nc.params.push_back((*ui)->id);
@@ -836,6 +855,7 @@
 			return true;
 		} else if(attackEnemy && owner->maxRange>0 && !gs->Ally(owner->allyteam,(*ui)->allyteam)){
 			Command nc;
+			commandQue.push_front(this->GetReturnFight(this->commandQue.front()));
 			nc.id=CMD_ATTACK;
 			nc.options=options | INTERNAL_ORDER;
 			nc.params.push_back((*ui)->id);
Index: rts/Sim/Units/CommandAI/BuilderCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/BuilderCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/BuilderCAI.h	(working copy)
@@ -17,13 +17,12 @@
 	void GiveCommand(Command& c);
 	void DrawQuedBuildingSquares(void);
 
-	bool FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options);
+	bool FindReclaimableFeatureAndReclaim(float3 pos, float radius,unsigned char options, bool recAny);
 	bool FindResurrectableFeatureAndResurrect(float3 pos, float radius,unsigned char options);
 	void FinishCommand(void);
 	bool FindRepairTargetAndRepair(float3 pos, float radius,unsigned char options,bool attackEnemy);
 	bool FindCaptureTargetAndCapture(float3 pos, float radius,unsigned char options);
 
-	bool commandFromPatrol;
 	map<int,string> buildOptions;
 	bool building;
 	float3 buildPos;
@@ -32,6 +31,9 @@
 	int cachedRadiusId;
 
 	int buildRetries;
+
+	int lastPC1; //helps avoid infinite loops
+	int lastPC2;
 };
 
 #endif // __BUILDER_CAI_H__
Index: rts/Sim/Units/CommandAI/CommandAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/CommandAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/CommandAI.cpp	(working copy)
@@ -295,18 +295,20 @@
 			stockpileWeapon->numStockpileQued=0;
 		UpdateStockpileIcon();
 		return; }
-	case CMD_SELFD:
+	case CMD_SELFD:{
 		if(owner->selfDCountdown){
 			owner->selfDCountdown=0;
 		} else {
 			owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1;
 		}
-		return;
+		return;}
 	}
-
+    
 	if(!(c.options & SHIFT_KEY)){
 		if(!commandQue.empty()){
-			if(commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_AREA_ATTACK || commandQue.front().id==CMD_DGUN){
+			if(commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_AREA_ATTACK
+				|| commandQue.front().id==CMD_DGUN)
+			{
 				owner->AttackUnit(0,true);
 			}
 
@@ -321,30 +323,65 @@
 			orderTarget=0;
 		}
 	}
+	if(c.id == CMD_PATROL){
+		std::deque<Command>::iterator ci = commandQue.begin();
+		for(; ci != commandQue.end() && ci->id!=CMD_PATROL; ci++);
+		if(ci==commandQue.end()){
+			if(commandQue.empty()){
+				Command c2;
+				c2.id = CMD_PATROL;
+				c2.params.push_back(owner->pos.x);
+				c2.params.push_back(owner->pos.y);
+				c2.params.push_back(owner->pos.z);
+				c2.options = c.options;
+				commandQue.push_back(c2);
+			} else {
+				do{
+					ci--;
+					if(ci->params.size() >=3){
+						Command c2;
+						c2.id = CMD_PATROL;
+						c2.params = ci->params;
+						c2.options = c.options;
+						commandQue.push_back(c2);
+						ci=commandQue.begin();
+					} else if(ci==commandQue.begin()){
+						Command c2;
+						c2.id = CMD_PATROL;
+						c2.params.push_back(owner->pos.x);
+						c2.params.push_back(owner->pos.y);
+						c2.params.push_back(owner->pos.z);
+						c2.options = c.options;
+						commandQue.push_back(c2);
+					}
+				}while(ci!=commandQue.begin());
+			}
+		}
+	}
 	std::deque<Command>::iterator ci = CCommandAI::GetCancelQueued(c);
-	if(c.id<0 && ci != this->commandQue.end()){
+	if(c.id<0 && ci != commandQue.end()){
 		do{
-			if(ci == this->commandQue.begin()){
-				this->commandQue.erase(ci);
+			if(ci == commandQue.begin()){
+				commandQue.erase(ci);
 				Command c2;
 				c2.id = CMD_STOP;
-				this->commandQue.push_front(c2);
-				this->SlowUpdate();
+				commandQue.push_front(c2);
+				SlowUpdate();
 			} else {
-				this->commandQue.erase(ci);
+				commandQue.erase(ci);
 			}
 			ci = CCommandAI::GetCancelQueued(c);
-		}while(ci != this->commandQue.end());
+		}while(ci != commandQue.end());
 		return;
-	} else if(ci != this->commandQue.end()){
-		if(ci == this->commandQue.begin()){
-			this->commandQue.erase(ci);
+	} else if(ci != commandQue.end()){
+		if(ci == commandQue.begin()){
+			commandQue.erase(ci);
 			Command c2;
 			c2.id = CMD_STOP;
-			this->commandQue.push_front(c2);
-			this->SlowUpdate();
+			commandQue.push_front(c2);
+			SlowUpdate();
 		} else {
-			this->commandQue.erase(ci);
+			commandQue.erase(ci);
 		}
 		ci = CCommandAI::GetCancelQueued(c);
 		return;
@@ -547,7 +584,7 @@
 void CCommandAI::FinishCommand(void)
 {
 	int type=commandQue.front().id;
-	if(repeatOrders && type!=CMD_STOP && !(commandQue.front().options & INTERNAL_ORDER))
+	if(repeatOrders && type!=CMD_STOP && type != CMD_PATROL && !(commandQue.front().options & INTERNAL_ORDER))
 		commandQue.push_back(commandQue.front());
 	commandQue.pop_front();
 	inCommand=false;
@@ -589,7 +626,8 @@
 	for(pci=possibleCommands.begin();pci!=possibleCommands.end();++pci){
 		if(pci->id==CMD_STOCKPILE){
 			char name[50];
-			sprintf(name,"%i/%i",stockpileWeapon->numStockpiled,stockpileWeapon->numStockpiled+stockpileWeapon->numStockpileQued);
+			sprintf(name,"%i/%i",stockpileWeapon->numStockpiled,
+				stockpileWeapon->numStockpiled+stockpileWeapon->numStockpileQued);
 			pci->name=name;
 			selectedUnits.PossibleCommandChange(owner);
 		}
@@ -598,7 +636,9 @@
 
 void CCommandAI::WeaponFired(CWeapon* weapon)
 {
-	if(weapon->weaponDef->manualfire && !weapon->weaponDef->dropped && !commandQue.empty() && (commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_DGUN) && inCommand){
+	if(weapon->weaponDef->manualfire && !weapon->weaponDef->dropped && !commandQue.empty()
+		&& (commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_DGUN) && inCommand)
+	{
 		owner->AttackUnit(0,true);
 		globalAI->WeaponFired(owner,weapon->weaponDef);
 		FinishCommand();
Index: rts/Sim/Units/CommandAI/FactoryCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/FactoryCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/FactoryCAI.cpp	(working copy)
@@ -21,12 +21,21 @@
 	c.key='M';
 	c.tooltip="Move: Order ready built units to move to a position";
 	possibleCommands.push_back(c);
+
 	c.id=CMD_PATROL;
 	c.type=CMDTYPE_ICON_MAP;
 	c.name="Patrol";
 	c.key='P';
 	c.tooltip="Patrol: Order ready built units to patrol to one or more waypoints";
 	possibleCommands.push_back(c);
+
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order ready built units to take action while moving to a position";
+	possibleCommands.push_back(c);
+
 	c.id=CMD_GUARD;
 	c.type=CMDTYPE_ICON_UNIT;
 	c.name="Guard";
@@ -220,6 +229,7 @@
 			glColor4f(0.5,1,0.5,0.4);
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1]+3,ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
Index: rts/Sim/Units/CommandAI/MobileCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/MobileCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/MobileCAI.cpp	(working copy)
@@ -17,8 +17,7 @@
 
 CMobileCAI::CMobileCAI(CUnit* owner)
 : CCommandAI(owner),
-	activeCommand(0),
-	patrolTime(0),
+//	patrolTime(0),
 	goalPos(-1,-1,-1),
 	tempOrder(false),
 	patrolGoal(1,1,1),
@@ -28,7 +27,8 @@
 	maxWantedSpeed(0),
 	lastIdleCheck(0),
 	commandPos1(ZeroVector),
-	commandPos2(ZeroVector)
+	commandPos2(ZeroVector),
+	lastPC(-1)
 {
 	lastUserGoal=owner->pos;
 
@@ -48,6 +48,15 @@
 	c.tooltip="Patrol: Order the unit to patrol to one or more waypoints";
 	possibleCommands.push_back(c);
 
+	c.params.clear();
+	c.id = CMD_FIGHT;
+	c.type = CMDTYPE_ICON_MAP;
+	c.name = "Fight";
+	c.key = 'F';
+	c.tooltip = "Fight: Order the unit to take action while moving to a position";
+	possibleCommands.push_back(c);
+
+
 	c.id=CMD_GUARD;
 	c.type=CMDTYPE_ICON_UNIT;
 	c.name="Guard";
@@ -114,7 +123,6 @@
 	}
 
 	if(!(c.options & SHIFT_KEY) && nonQueingCommands.find(c.id)==nonQueingCommands.end()){
-		activeCommand=0;
 		tempOrder=false;
 	}
 	CCommandAI::GiveCommand(c);
@@ -154,72 +162,83 @@
 		}
 		break;}
 	case CMD_PATROL:{
+		if(c.params.size()<3){		//this shouldnt happen but anyway ...
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in mobilecai",
+				owner->unitDef->humanName.c_str());
+			return;
+		}
+		Command temp;
+		temp.id = CMD_FIGHT;
+		temp.params.push_back(c.params[0]);
+		temp.params.push_back(c.params[1]);
+		temp.params.push_back(c.params[2]);
+		temp.options = c.options|INTERNAL_ORDER;
+		commandQue.push_back(c);
+		commandQue.pop_front();
+		commandQue.push_front(temp);
+		if(owner->group){
+			owner->group->CommandFinished(owner->id,CMD_PATROL);
+		}
+		SlowUpdate();
+		return;}
+	case CMD_FIGHT:{
 		if(tempOrder){
-			tempOrder=false;
-			inCommand=true;
-			patrolTime=1;
+			inCommand = true;
+			tempOrder = false;
 		}
-		if(!inCommand){
-			float3 pos(c.params[0],c.params[1],c.params[2]);
-			inCommand=true;
-			Command co;
-			co.id=CMD_PATROL;
-			co.params.push_back(curPos.x);
-			co.params.push_back(curPos.y);
-			co.params.push_back(curPos.z);
-			commandQue.push_front(co);
-			activeCommand=1;
-			commandPos1=curPos;
-			patrolTime=1;
-		}
-		Command& c=commandQue[activeCommand];
 		if(c.params.size()<3){		//this shouldnt happen but anyway ...
-			info->AddLine("Error: got patrol cmd with less than 3 params on %s in mobilecai",owner->unitDef->humanName.c_str());
+			info->AddLine("Error: got fight cmd with less than 3 params on %s in mobilecai",
+				owner->unitDef->humanName.c_str());
 			return;
 		}
-		patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-		commandPos2=patrolGoal;
-		patrolTime++;
+		if(c.params.size() >= 6){
+			if(!inCommand){
+				commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
+			}
+		} else {
+			commandPos1 = curPos;
+		}
+		float3 pos(c.params[0],c.params[1],c.params[2]);
+		if(!inCommand){
+			inCommand = true;
+			commandPos2 = pos;
+		}
+		if(pos!=goalPos){
+			SetGoal(pos,curPos);
+		}
 
-		if(!(patrolTime&1) && owner->fireState==2){
-			CUnit* enemy=helper->GetClosestEnemyUnit(curPos,owner->maxRange+100*owner->moveState*owner->moveState,owner->allyteam);
-			if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()){			//todo: make sure they dont stray to far from path
-				if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 300+owner->maxRange){
-					Command c2;
+		if(owner->fireState==2){
+			CUnit* enemy=helper->GetClosestEnemyUnit(
+				curPos, owner->maxRange+100*owner->moveState*owner->moveState, owner->allyteam);
+			if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
+			  && !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()){	//todo: make sure they dont stray to far from path
+				if(owner->moveState!=1 
+				  || LinePointDist(commandPos1,commandPos2,enemy->pos)
+				  < 300+max(owner->maxRange, (float)owner->losRadius)){
+					Command c2,c3;
+					c3 = this->GetReturnFight(c);
 					c2.id=CMD_ATTACK;
-					c2.options=c.options;
+					c2.options=c.options|INTERNAL_ORDER;
 					c2.params.push_back(enemy->id);
+					commandQue.push_front(c3);
 					commandQue.push_front(c2);
 					inCommand=false;
 					tempOrder=true;
-					SlowUpdate();				//if attack can finish immidiatly this could lead to an infinite loop so make sure it doesnt
+					if(lastPC!=gs->frameNum){	//avoid infinite loops
+						lastPC=gs->frameNum;
+						SlowUpdate();
+					}
 					return;
 				}
 			}
 		}
-		if((curPos-patrolGoal).SqLength2D()<4096 || owner->moveType->progressState==CMoveType::Failed){
-			if(owner->group)
-				owner->group->CommandFinished(owner->id,CMD_PATROL);
-
-			if((int)commandQue.size()<=activeCommand+1)
-				activeCommand=0;
-			else {
-				if(commandQue[activeCommand+1].id!=CMD_PATROL)
-					activeCommand=0;
-				else
-					activeCommand++;
-			}
-			Command& c=commandQue[activeCommand];
-			patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
-			commandPos1=commandPos2;
-			commandPos2=patrolGoal;
+		if((curPos-goalPos).SqLength2D()<4096 || owner->moveType->progressState==CMoveType::Failed){
+			FinishCommand();
 		}
-		if((patrolGoal!=goalPos)){
-			SetGoal(patrolGoal,curPos);
-		}
 		return;}
 	case CMD_DGUN:
-		if(uh->limitDgun && owner->unitDef->isCommander && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
+		if(uh->limitDgun && owner->unitDef->isCommander
+		  && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
 			StopMove();
 			FinishCommand();
 			return;
@@ -259,33 +278,35 @@
 		}
 		if(orderTarget){
 			//note that we handle aircrafts slightly differently
-			if(((owner->AttackUnit(orderTarget, c.id==CMD_DGUN) || dynamic_cast<CTAAirMoveType*>(owner->moveType)) && (owner->pos-orderTarget->pos).Length2D()<owner->maxRange*0.9) || (owner->pos-orderTarget->pos).SqLength2D()<1024){
-				//					if(owner->isMoving) {
+			if((((owner->AttackUnit(orderTarget, c.id==CMD_DGUN) && owner->weapons.size() > 0
+			  && owner->weapons.front()->range > orderTarget->pos.distance(owner->pos))
+			  || dynamic_cast<CTAAirMoveType*>(owner->moveType))
+			  && (owner->pos-orderTarget->pos).Length2D()<owner->maxRange*0.9)
+			  || (owner->pos-orderTarget->pos).SqLength2D()<1024){
 				StopMove();
-				owner->moveType->KeepPointingTo(orderTarget->pos, min((double)(owner->losRadius*SQUARE_SIZE*2),owner->maxRange*0.9), true);
-				//					}
-			} else {
-				if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos)>10+orderTarget->pos.distance2D(owner->pos)*0.2)
-				{
-					float3 fix=orderTarget->pos+owner->posErrorVector*128;
-					SetGoal(fix,curPos);
-				}
+				owner->moveType->KeepPointingTo(orderTarget->pos, min((double)(owner->losRadius*SQUARE_SIZE*2),
+					owner->maxRange*0.9), true);
+			} else if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos)
+			  > 10+orderTarget->pos.distance2D(owner->pos)*0.2){
+				  float3 fix=orderTarget->pos+owner->posErrorVector*128;
+				  SetGoal(fix,curPos);
 			}
 		} else {
 			float3 pos(c.params[0],c.params[1],c.params[2]);
-			if(owner->AttackGround(pos,c.id==CMD_DGUN) || (owner->pos-pos).SqLength2D()<1024) {
+			if((owner->AttackGround(pos,c.id==CMD_DGUN) && owner->weapons.size() > 0
+			  && (owner->pos-pos).Length()< owner->weapons.front()->range) || (owner->pos-pos).SqLength2D()<1024){
 				StopMove();
 				owner->moveType->KeepPointingTo(pos, owner->maxRange*0.9, true);
-			} else {
-				if(pos.distance2D(goalPos)>10)
-					SetGoal(pos,curPos);					
+			} else if(pos.distance2D(goalPos)>10){
+				SetGoal(pos,curPos);					
 			}
 		}
 		break;
 	case CMD_GUARD:
 		if(uh->units[int(c.params[0])]!=0){
 			CUnit* guarded=uh->units[int(c.params[0])];
-			if(guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
+			if(guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum
+			  && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
 				Command nc;
 				nc.id=CMD_ATTACK;
 				nc.params.push_back(guarded->lastAttacker->id);
@@ -357,6 +378,7 @@
 			draw=true;
 			break;
 		case CMD_PATROL:
+		case CMD_FIGHT:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
 			draw=true;
@@ -424,7 +446,6 @@
 		lastUserGoal=owner->pos;
 //		info->AddLine("Reseting user goal");
 	}
-
 	CCommandAI::FinishCommand();
 }
 
@@ -471,3 +492,34 @@
 		NonMoving();
 	}
 }
+
+/**
+* @brief gets the command that keeps the unit close to the path
+* @return a Fight Command with 6 arguments, the first three being where to return to (the current position of the
+*	unit), and the second being the location of the origional command.
+* @param c the command to return to
+**/
+Command CMobileCAI::GetReturnFight(Command c){
+	Command c3;
+	c3.id = CMD_FIGHT; //keep it from being pulled too far off the path
+	float3 pos = float3(c.params[0],c.params[1],c.params[2]);
+	const float3 &curPos = this->owner->pos;
+	float3 dir = pos-curPos;
+	dir.Normalize();
+	dir*=sqrtf(abs(1024+owner->xsize*owner->xsize+owner->ysize*owner->ysize));
+	dir+=curPos;
+	c3.params.push_back(dir.x);
+	c3.params.push_back(dir.y);
+	c3.params.push_back(dir.z);
+	if(c.params.size() >= 6){
+		c3.params.push_back(c.params[3]);
+		c3.params.push_back(c.params[4]);
+		c3.params.push_back(c.params[5]);
+	} else {
+		c3.params.push_back(c.params[0]);
+		c3.params.push_back(c.params[1]);
+		c3.params.push_back(c.params[2]);
+	}
+	c3.options = c.options|INTERNAL_ORDER;
+	return c3;
+}
\ No newline at end of file
Index: rts/Sim/Units/CommandAI/MobileCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/MobileCAI.h	(revision 1536)
+++ rts/Sim/Units/CommandAI/MobileCAI.h	(working copy)
@@ -20,17 +20,19 @@
 	void NonMoving(void);
 	void FinishCommand(void);
 	void IdleCheck(void);
+	Command GetReturnFight(Command c);
 
 	float3 goalPos;
 	float3 patrolGoal;
 	float3 lastUserGoal;
 
-	int activeCommand;
 	int lastIdleCheck;
 	bool tempOrder;
 
-	unsigned int patrolTime;
+	int lastPC; //helps avoid infinate loops
 
+//	unsigned int patrolTime;
+
 	float maxWantedSpeed;
 
 	int lastBuggerOffTime;
Index: rts/Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/TransportCAI.cpp	(revision 1536)
+++ rts/Sim/Units/CommandAI/TransportCAI.cpp	(working copy)
@@ -334,6 +334,7 @@
 			glColor4f(0.5,1,0.5,0.4);
 			draw=true;
 			break;
+		case CMD_FIGHT:
 		case CMD_PATROL:
 			pos=float3(ci->params[0],ci->params[1],ci->params[2]);
 			glColor4f(0.5,0.5,1,0.4);
 | 
|---|