cancelCommandChanges.patch (18,365 bytes) 
2006-06-12 18:41 
Index: rts/Game/UI/GuiHandler.cpp
===================================================================
--- rts/Game/UI/GuiHandler.cpp	(revision 1459)
+++ rts/Game/UI/GuiHandler.cpp	(working copy)
@@ -32,6 +32,7 @@
 #include "SDL_keysym.h"
 #include "SDL_mouse.h"
 #include "mmgr.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
 
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
@@ -717,7 +718,24 @@
 
 				for(std::vector<float3>::iterator bpi=buildPos.begin();bpi!=buildPos.end();++bpi){
 					float3 pos=*bpi;
-					if(uh->ShowUnitBuildSquare(pos,unitdef))
+					std::vector<Command> cv;
+					if(keys[SDLK_LSHIFT]){
+						Command c;
+						c.id = -unitdef->id;
+						c.params.push_back(pos.x);
+						c.params.push_back(pos.y);
+						c.params.push_back(pos.z);
+						std::vector<Command> temp;
+						std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+						for(; ui != selectedUnits.selectedUnits.end(); ui++){
+							temp = (*ui)->commandAI->GetOverlapQueued(c);
+							std::vector<Command>::iterator ti = temp.begin();
+							for(; ti != temp.end(); ti++){
+								cv.insert(cv.end(),*ti);
+							}
+						}
+					}
+					if(uh->ShowUnitBuildSquare(pos,unitdef,cv))
 						glColor4f(0.7,1,1,0.4);
 					else
 						glColor4f(1,0.5,0.5,0.4);
@@ -1300,13 +1318,32 @@
 	start=helper->Pos2BuildPos(start,unitdef);
 	end=helper->Pos2BuildPos(end,unitdef);
 
-	
-	CUnit* unit=0;
-	float dist2=helper->GuiTraceRay(camera->pos,mouse->dir,gu->viewRange*1.4,unit,20,true);
+	float3 buildPos;
+	UnitDef* unitdef2=0;
+	if(keys[SDLK_LSHIFT] && keys[SDLK_LCTRL]){
+		CUnit* unit=0;
+		float dist2=helper->GuiTraceRay(camera->pos,mouse->dir,gu->viewRange*1.4,unit,20,true);
+		if(unit){
+			unitdef2=unit->unitDef;
+			buildPos = unit->pos;
+		} else {
+			Command c = uh->GetBuildCommand(camera->pos,mouse->dir);
+			if(c.id < 0){
+				unitdef2=unitDefHandler->GetUnitByID(-c.id);
+				buildPos.x = c.params[0];
+				buildPos.y = c.params[1];
+				buildPos.z = c.params[2];
+			}
+		}
+	}
+	if(unitdef2 && keys[SDLK_LSHIFT] && keys[SDLK_LCTRL]){		//circle build around building
+		Command c;
+		c.id = -unitdef->id;
+		c.params.push_back(0);
+		c.params.push_back(0);
+		c.params.push_back(0);
 
-	if(unit && keys[SDLK_LSHIFT] && keys[SDLK_LCTRL]){		//circle build around building
-		UnitDef* unitdef2=unit->unitDef;
-		float3 pos2=unit->pos;
+		float3 pos2 = buildPos;
 		pos2=helper->Pos2BuildPos(pos2,unitdef2);
 		start=pos2;
 		end=pos2;
@@ -1321,7 +1358,19 @@
 			p2.x+=(unitdef->xsize/2)*SQUARE_SIZE;
 			p2.z-=(unitdef->ysize/2)*SQUARE_SIZE;
 			p2=helper->Pos2BuildPos(p2,unitdef);
-			ret.push_back(p2);
+			c.params[0] = p2.x;
+			c.params[1] = p2.y;
+			c.params[2] = p2.z;
+			bool cancel = false;
+			std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+			for(;ui != selectedUnits.selectedUnits.end() && !cancel; ++ui){
+				if((*ui)->commandAI->WillCancelQueued(c)){
+					cancel = true;
+				}
+			}
+			if(!cancel){
+				ret.push_back(p2);
+			}
 		}
 		pos=start;
 		pos.x=end.x;
@@ -1330,7 +1379,19 @@
 			p2.x+=(unitdef->xsize/2)*SQUARE_SIZE;
 			p2.z+=(unitdef->ysize/2)*SQUARE_SIZE;
 			p2=helper->Pos2BuildPos(p2,unitdef);
-			ret.push_back(p2);
+			c.params[0] = p2.x;
+			c.params[1] = p2.y;
+			c.params[2] = p2.z;
+			bool cancel = false;
+			std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+			for(;ui != selectedUnits.selectedUnits.end() && !cancel; ++ui){
+				if((*ui)->commandAI->WillCancelQueued(c)){
+					cancel = true;
+				}
+			}
+			if(!cancel){
+				ret.push_back(p2);
+			}
 		}
 		pos=end;
 		for(;pos.x>=start.x;pos.x-=unitdef->xsize*SQUARE_SIZE){
@@ -1338,7 +1399,19 @@
 			p2.x-=(unitdef->xsize/2)*SQUARE_SIZE;
 			p2.z+=(unitdef->ysize/2)*SQUARE_SIZE;
 			p2=helper->Pos2BuildPos(p2,unitdef);
-			ret.push_back(p2);
+			c.params[0] = p2.x;
+			c.params[1] = p2.y;
+			c.params[2] = p2.z;
+			bool cancel = false;
+			std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+			for(;ui != selectedUnits.selectedUnits.end() && !cancel; ++ui){
+				if((*ui)->commandAI->WillCancelQueued(c)){
+					cancel = true;
+				}
+			}
+			if(!cancel){
+				ret.push_back(p2);
+			}
 		}
 		pos=end;
 		pos.x=start.x;
@@ -1347,7 +1420,19 @@
 			p2.x-=(unitdef->xsize/2)*SQUARE_SIZE;
 			p2.z-=(unitdef->ysize/2)*SQUARE_SIZE;
 			p2=helper->Pos2BuildPos(p2,unitdef);
-			ret.push_back(p2);
+			c.params[0] = p2.x;
+			c.params[1] = p2.y;
+			c.params[2] = p2.z;
+			bool cancel = false;
+			std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+			for(;ui != selectedUnits.selectedUnits.end() && !cancel; ++ui){
+				if((*ui)->commandAI->WillCancelQueued(c)){
+					cancel = true;
+				}
+			}
+			if(!cancel){
+				ret.push_back(p2);
+			}
 		}
 	} else if(keys[SDLK_LALT]){			//build a rectangle
 		float xsize=unitdef->xsize*8+buildSpacing*16;
Index: rts/Sim/Units/CommandAI/BuilderCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/BuilderCAI.cpp	(revision 1459)
+++ rts/Sim/Units/CommandAI/BuilderCAI.cpp	(working copy)
@@ -447,7 +447,7 @@
 		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",owner->unitDef->humanName.c_str());
+			info->AddLine("Error: got patrol cmd with less than 3 params on %s in BuilderCAI",owner->unitDef->humanName.c_str());
 			return;
 		}
 		patrolGoal=float3(c.params[0],c.params[1],c.params[2]);
Index: rts/Sim/Units/CommandAI/CommandAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/CommandAI.cpp	(revision 1459)
+++ rts/Sim/Units/CommandAI/CommandAI.cpp	(working copy)
@@ -2,6 +2,7 @@
 #include "CommandAI.h"
 #include "Sim/Units/UnitHandler.h"
 #include "Sim/Units/Unit.h"
+#include "Sim/Units/UnitDefHandler.h"
 #include "Sim/Weapons/Weapon.h"
 #include "ExternalAI/Group.h"
 #include "Rendering/GL/myGL.h"
@@ -320,33 +321,131 @@
 			orderTarget=0;
 		}
 	}
+	std::deque<Command>::iterator ci = CCommandAI::GetCancelQueued(c);
+	if(c.id<0 && ci != this->commandQue.end()){
+		do{
+			if(ci == this->commandQue.begin()){
+				this->commandQue.erase(ci);
+				Command c2;
+				c2.id = CMD_STOP;
+				this->commandQue.push_front(c2);
+				this->SlowUpdate();
+			} else {
+				this->commandQue.erase(ci);
+			}
+			ci = CCommandAI::GetCancelQueued(c);
+		}while(ci != this->commandQue.end());
+		return;
+	} else if(ci != this->commandQue.end()){
+		if(ci == this->commandQue.begin()){
+			this->commandQue.erase(ci);
+			Command c2;
+			c2.id = CMD_STOP;
+			this->commandQue.push_front(c2);
+			this->SlowUpdate();
+		} else {
+			this->commandQue.erase(ci);
+		}
+		ci = CCommandAI::GetCancelQueued(c);
+		return;
+	}
+	if(!this->GetOverlapQueued(c).empty()){
+		return;
+	}
+	if(c.id==CMD_ATTACK && owner->weapons.empty() && owner->unitDef->canKamikaze==false)		//avoid weaponless units moving to 0 distance when given attack order
+		c.id=CMD_STOP;
+
+	commandQue.push_back(c);
+	if(commandQue.size()==1 && !owner->beingBuilt)
+		SlowUpdate();
+}
+
+/**
+* @brief Determins if c will cancel a queued command
+* @return true if c will cancel a queued command
+**/
+bool CCommandAI::WillCancelQueued(Command &c)
+{
+	return this->GetCancelQueued(c) != this->commandQue.end();
+}
+
+/**
+* @brief Finds the queued command that would be canceled by the Command c
+* @return An iterator located at the command, or commandQue.end() if no such queued command exsists
+**/
+std::deque<Command>::iterator CCommandAI::GetCancelQueued(Command &c){
 	if(!commandQue.empty()){
 		std::deque<Command>::iterator ci=commandQue.end();
-		for(--ci;ci!=commandQue.begin();--ci){							//iterate from the end and dont check the current order
+		do{
+			--ci;			//iterate from the end and dont check the current order
 			if((ci->id==c.id || (c.id<0 && ci->id<0)) && ci->params.size()==c.params.size()){
 				if(c.params.size()==1){			//we assume the param is a unit of feature id
 					if(ci->params[0]==c.params[0]){
-						commandQue.erase(ci);
-						return;
+						return ci;
 					}
 				} else if(c.params.size()>=3){		//we assume this means that the first 3 makes a position
 					float3 cpos(c.params[0],c.params[1],c.params[2]);
 					float3 cipos(ci->params[0],ci->params[1],ci->params[2]);
+					if(c.id < 0){
+						UnitDef* u1 = unitDefHandler->GetUnitByID(-c.id);
+						UnitDef* u2 = unitDefHandler->GetUnitByID(-ci->id);
+						if(u1 && u2
+							&& abs(cpos.x-cipos.x)*2 <= max(u1->xsize, u2->xsize)*SQUARE_SIZE
+							&& abs(cpos.z-cipos.z)*2 <= max(u1->ysize, u2->ysize)*SQUARE_SIZE)
+						{
+							return ci;
+						}
+					} else {
+                        if((cpos-cipos).SqLength2D()<17*17){
+							return ci;				
+						}
+					}
+				}
+			}
+		}while(ci!=commandQue.begin());
+	}
+	return commandQue.end();
+}
 
-					if((cpos-cipos).SqLength2D()<17*17){
-						commandQue.erase(ci);
-						return;				
+/**
+* @brief Returns commands that overlap c, but will not be canceled by c
+* @return a vector containing commands that overlap c
+*/
+std::vector<Command> CCommandAI::GetOverlapQueued(Command &c){
+	std::deque<Command>::iterator ci = commandQue.end();
+	std::vector<Command> v;
+	if(ci != commandQue.begin()){
+		do{
+			--ci;			//iterate from the end and dont check the current order
+			if((ci->id==c.id || (c.id<0 && ci->id<0)) && ci->params.size()==c.params.size()){
+				if(c.params.size()==1){			//we assume the param is a unit of feature id
+					if(ci->params[0]==c.params[0]){
+						v.push_back(*ci);
 					}
+				} else if(c.params.size()>=3){		//we assume this means that the first 3 makes a position
+					float3 cpos(c.params[0],c.params[1],c.params[2]);
+					float3 cipos(ci->params[0],ci->params[1],ci->params[2]);
+					if(c.id < 0){
+						UnitDef* u1 = unitDefHandler->GetUnitByID(-c.id);
+						UnitDef* u2 = unitDefHandler->GetUnitByID(-ci->id);
+						if(u1 && u2
+							&& (abs(cpos.x-cipos.x)*2 > max(u1->xsize, u2->xsize)*SQUARE_SIZE
+							|| abs(cpos.z-cipos.z)*2 > max(u1->ysize, u2->ysize)*SQUARE_SIZE)
+							&& abs(cpos.x-cipos.x)*2 < (u1->xsize + u2->xsize)*SQUARE_SIZE
+							&& abs(cpos.z-cipos.z)*2 < (u1->ysize + u2->ysize)*SQUARE_SIZE)
+						{
+							v.push_back(*ci);
+						}
+					} else {
+						if((cpos-cipos).SqLength2D()<17*17){
+							v.push_back(*ci);
+						}
+					}
 				}
 			}
-		}
+		}while(ci!=commandQue.begin());
 	}
-	if(c.id==CMD_ATTACK && owner->weapons.empty() && owner->unitDef->canKamikaze==false)		//avoid weaponless units moving to 0 distance when given attack order
-		c.id=CMD_STOP;
-
-	commandQue.push_back(c);
-	if(commandQue.size()==1 && !owner->beingBuilt)
-		SlowUpdate();
+	return v;
 }
 
 void CCommandAI::SlowUpdate()
Index: rts/Sim/Units/CommandAI/CommandAI.h
===================================================================
--- rts/Sim/Units/CommandAI/CommandAI.h	(revision 1459)
+++ rts/Sim/Units/CommandAI/CommandAI.h	(working copy)
@@ -29,6 +29,9 @@
 	virtual void WeaponFired(CWeapon* weapon);
 	virtual void BuggerOff(float3 pos, float radius);
 	virtual void LoadSave(CLoadSaveInterface* file, bool loading);
+	virtual bool WillCancelQueued(Command &c);
+	std::deque<Command>::iterator GetCancelQueued(Command &c);
+	std::vector<Command> GetOverlapQueued(Command &c);
 
 	void AddStockpileWeapon(CWeapon* weapon);
 	void StockpileChanged(CWeapon* weapon);
Index: rts/Sim/Units/CommandAI/FactoryCAI.cpp
===================================================================
--- rts/Sim/Units/CommandAI/FactoryCAI.cpp	(revision 1459)
+++ rts/Sim/Units/CommandAI/FactoryCAI.cpp	(working copy)
@@ -75,9 +75,14 @@
 		if(!(c.options & SHIFT_KEY)){
 			newUnitCommands.clear();
 		}
-		if(c.id!=CMD_STOP)
-			newUnitCommands.push_back(c);
-
+		if(c.id!=CMD_STOP){
+			std::deque<Command>::iterator ci = GetCancelQueued(c);
+			if(ci == this->newUnitCommands.end()){
+				newUnitCommands.push_back(c);
+			} else {
+				this->newUnitCommands.erase(ci);
+			}
+		}
 		return;
 	}
 	BuildOption &bo=boi->second;
@@ -243,3 +248,31 @@
 	}
 	glEnd();
 }
+
+/**
+* @brief Finds the queued command that would be canceled by the Command c
+* @return An iterator located at the command, or commandQue.end() if no such queued command exsists
+**/
+std::deque<Command>::iterator CFactoryCAI::GetCancelQueued(Command &c){
+	if(!newUnitCommands.empty()){
+		std::deque<Command>::iterator ci=newUnitCommands.end();
+		do{
+			--ci;			//iterate from the end and dont check the current order
+			if((ci->id==c.id || (c.id<0 && ci->id<0)) && ci->params.size()==c.params.size()){
+				if(c.params.size()==1){			//we assume the param is a unit of feature id
+					if(ci->params[0]==c.params[0]){
+						return ci;
+					}
+				} else if(c.params.size()>=3){		//we assume this means that the first 3 makes a position
+					float3 cpos(c.params[0],c.params[1],c.params[2]);
+					float3 cipos(ci->params[0],ci->params[1],ci->params[2]);
+
+					if((cpos-cipos).SqLength2D()<17*17){
+						return ci;
+					}
+				}
+			}
+		}while(ci!=newUnitCommands.begin());
+	}
+	return newUnitCommands.end();
+}
\ No newline at end of file
Index: rts/Sim/Units/CommandAI/FactoryCAI.h
===================================================================
--- rts/Sim/Units/CommandAI/FactoryCAI.h	(revision 1459)
+++ rts/Sim/Units/CommandAI/FactoryCAI.h	(working copy)
@@ -24,6 +24,7 @@
 	void GiveCommand(Command& c);
 	void DrawCommands(void);
 	void UpdateIconName(int id,BuildOption& bo);
+	std::deque<Command>::iterator GetCancelQueued(Command &c);
 
 	std::deque<Command> newUnitCommands;
 
Index: rts/Sim/Units/UnitHandler.cpp
===================================================================
--- rts/Sim/Units/UnitHandler.cpp	(revision 1459)
+++ rts/Sim/Units/UnitHandler.cpp	(working copy)
@@ -19,12 +19,15 @@
 #include "Game/SelectedUnits.h"
 #include "FileSystem/FileHandler.h"
 #include "Game/UI/InfoConsole.h"
+#include "Game/SelectedUnits.h"
 #include "Sim/Misc/Feature.h"
 #include "Sim/Misc/FeatureHandler.h"
+#include "Sim/Units/Unit.h"
 #include "LoadSaveInterface.h"
 #include "UnitLoader.h"
 #include "SyncTracer.h"
 #include "Game/GameSetup.h"
+#include "Game/Command.h"
 #include "Sim/Misc/AirBaseHandler.h"
 #include "mmgr.h"
 
@@ -333,12 +336,22 @@
 		return 0;
 	if(groundheight>-unitdef->minWaterDepth)
 		return 0;
+	std::set<CUnit*>::iterator ui = selectedUnits.selectedUnits.begin();
+	std::vector<Command> cv;
+	for(;ui != selectedUnits.selectedUnits.end(); ui++){
+	
+	}
 
 	return ret;
 }
 
 int CUnitHandler::ShowUnitBuildSquare(const float3& pos, const UnitDef *unitdef)
 {
+	return ShowUnitBuildSquare(pos, unitdef, std::vector<Command>());
+}
+
+int CUnitHandler::ShowUnitBuildSquare(const float3& pos, const UnitDef *unitdef, const std::vector<Command> &cv)
+{
 	glDisable(GL_DEPTH_TEST );
 	glEnable(GL_BLEND);
 	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
@@ -376,7 +389,22 @@
 			CFeature* feature=0;
 			int tbs=TestBuildSquare(float3(x,pos.y,z),unitdef,feature);
 			if(tbs){
-				if(feature || tbs==1)
+				UnitDef* ud;
+				float3 cPos;
+				std::vector<Command>::const_iterator ci = cv.begin();
+				for(;ci != cv.end() && tbs; ci++){
+					ud = unitDefHandler->GetUnitByID(-ci->id);
+					cPos.x = ci->params[0];
+					cPos.z = ci->params[2];
+					if(max(cPos.x-x-SQUARE_SIZE,x-cPos.x)*2 < ud->xsize*SQUARE_SIZE
+						&& max(cPos.z-z-SQUARE_SIZE,z-cPos.z)*2 < ud->ysize*SQUARE_SIZE){
+						tbs=0;
+					}
+				}
+				if(!tbs){
+					nobuildpos.push_back(float3(x,h,z));
+					canbuild = 0;
+				} else if(feature || tbs==1)
 					featurepos.push_back(float3(x,h,z));
 				else
 					canbuildpos.push_back(float3(x,h,z));
@@ -495,3 +523,36 @@
 	}
 	return true;
 }
+
+/**
+* returns a build Command that intersects the ray described by pos and dir from the command queues of the
+* units units on team number team
+* @breif returns a build Command that intersects the ray described by pos and dir
+* @return the build Command, or 0 if one is not found
+*/
+
+Command CUnitHandler::GetBuildCommand(float3 pos, float3 dir){
+	float3 tempF1 = pos;
+	std::list<CUnit*>::iterator ui = this->activeUnits.begin();
+	std::deque<Command>::iterator ci;
+	for(; ui != this->activeUnits.end(); ui++){
+		if((*ui)->team == gu->myTeam){
+			ci = (*ui)->commandAI->commandQue.begin();
+			for(; ci != (*ui)->commandAI->commandQue.end(); ci++){
+				if((*ci).id < 0 && (*ci).params.size() >= 3){
+					tempF1.x = (*ci).params[0];
+					tempF1.y = (*ci).params[1];
+					tempF1.z = (*ci).params[2];
+					tempF1 = pos + dir*((tempF1.y - pos.y)/dir.y) - tempF1;
+					UnitDef* ud = unitDefHandler->GetUnitByID(-(*ci).id);
+					if(ud && ud->xsize/2*SQUARE_SIZE > abs(tempF1.x) && ud->ysize/2*SQUARE_SIZE > abs(tempF1.z)){
+						return (*ci);
+					}
+				}
+			}
+		}
+	}
+	Command c;
+	c.id = 0;
+	return c;
+}
Index: rts/Sim/Units/UnitHandler.h
===================================================================
--- rts/Sim/Units/UnitHandler.h	(revision 1459)
+++ rts/Sim/Units/UnitHandler.h	(working copy)
@@ -14,6 +14,7 @@
 #include <string>
 
 #include "UnitDef.h"
+#include "Game\Command.h"
 
 class CBuilderCAI;
 class CFeature;
@@ -51,6 +52,7 @@
 	int  TestUnitBuildSquare(const float3& pos, const UnitDef *unitdef,CFeature *&feature);	//test if a unit can be built at specified position
 	int  TestUnitBuildSquare(const float3& pos, std::string unit,CFeature *&feature);	//test if a unit can be built at specified position
 	int  ShowUnitBuildSquare(const float3& pos, const UnitDef *unitdef);	//test if a unit can be built at specified position and show on the ground where it's to rough
+	int  ShowUnitBuildSquare(const float3& pos, const UnitDef *unitdef, const std::vector<Command> &cv);
 	int  TestBuildSquare(const float3& pos, const UnitDef *unitdef,CFeature *&feature);	//test a singel mapsquare for build possibility
 
 	void AddBuilderCAI(CBuilderCAI*);
@@ -58,6 +60,7 @@
 	float GetBuildHeight(float3 pos, const UnitDef* unitdef);
 
 	void LoadSaveUnits(CLoadSaveInterface* file, bool loading);
+	Command GetBuildCommand(float3 pos, float3 dir);
 
 	std::list<CUnit*> activeUnits;				//used to get all active units
 	std::deque<int> freeIDs;