2019-12-10 17:24 CET

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000222Spring engineGeneralpublic2006-07-06 16:07
ReporterILMTitan 
Assigned Totvo 
PrioritynormalSeverityfeatureReproducibilityalways
StatusresolvedResolutionfixed 
Product Version 
Target VersionFixed in Version 
Summary0000222: [Patch] Smarter unit behavior for multiple weapons and those with arcs
DescriptionThis patch causes the unit to try to attack with weapon[0], moving closer and turning so limited arced weapons will hit.

This patch also includes previous Patrol-Fight changes and some additions, such as adding "Fight" as an available command in the UI.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • patch file icon 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);
    
    patch file icon ArcWeapon&Fight.patch (39,579 bytes) 2006-06-28 00:48 +
  • patch file icon 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);
    
    patch file icon ArcWeapon&Fight(1).patch (39,820 bytes) 2006-07-01 10:35 +

-Relationships
+Relationships

-Notes

~0000267

Krysole (reporter)

Updated patch file so that it doesn't include vs project file (changed to the project file have already been propagated in the svn).

~0000280

tvo (reporter)

committed, thanks
+Notes

-Issue History
Date Modified Username Field Change
2006-06-28 00:48 ILMTitan New Issue
2006-06-28 00:48 ILMTitan File Added: ArcWeapon&Fight.patch
2006-07-01 10:35 Krysole File Added: ArcWeapon&Fight(1).patch
2006-07-01 10:36 Krysole Note Added: 0000267
2006-07-06 16:07 tvo Status new => assigned
2006-07-06 16:07 tvo Assigned To => tvo
2006-07-06 16:07 tvo Status assigned => resolved
2006-07-06 16:07 tvo Resolution open => fixed
2006-07-06 16:07 tvo Note Added: 0000280
+Issue History