Пример #1
0
int CheckCollisionGround( vector<z_face> &collision, vec center, float radius, float angle, float mindist)
{
	float ground_skew = (float)cos(angle*PI180)*radius;
	vec vpold_vp = mindist*vec(0,-1,0);

	for( int i=0; i<collision.size(); i++)
	{
		vec normal = collision[i].normal;
		float distance = PlaneDistance( normal, collision[i].a);		// D = - (Ax+By+Cz)
		// ---------------------------------------------------------
		// najdeme kolidujuci bod na guli
		vec ClosestPointOnSphere;		// najblizsi bod gule k rovine aktualneho trojuholnika
		// najdeme ho ako priesecnik priamky prechadzajucej stredom gule a smerovym vektorom = normalovemu vektoru roviny (trojuholnika)
		// vypocitame ho, ale jednodusie tak, ze pripocitame (opocitame) k stredu vektor normala*radius
		
		if( PlanePointDelta( normal, distance, center) > 0 )
		{
			// center je na strane normaly, blizsi bod je v opacnom smere ako smer normaly
			ClosestPointOnSphere = -radius*normal+center;
		}
		else
		{
			// center je na opacnej strane ako normala, blizsi bod je v smere normaly
			ClosestPointOnSphere = radius*normal+center;
		}

		// ---------------------------------------------------------
		// najdeme kolidujuci bod na trojuholniku
		// najprv najdeme kolidujuci bod vzhladom na rovinu v ktorej lezi trojuholnik
		vec contactPointSphereToPlane;			// kolidujuci bod na rovine trojuholnika s gulou
		float distanceCenterToPlane;			// vzdialenost stredu gule k rovine
		// zistime ci rovina pretina gulu
		if( SpherePlaneCollision( center, 0.9999f*radius, normal, distance, &distanceCenterToPlane)==1 )
		{
			// gula pretina rovinu
			// kolidujuci bod je bod na rovine najblizsi k stredu gule
			// je vzdialeny od roviny na distanceCenterToPlane, pretoze pocitame bod na rovine pouzijeme -
			contactPointSphereToPlane = center-distanceCenterToPlane*normal;
		}
		else
		{
			// nie sme v kolizii z gulov, ak sa pohybujeme v smere od roviny, nemoze nastat ziadna kolizia
			// ak sa pohybujeme v smere kolmom na normalovy vektor roviny, tak isto kolizia nehrozi
			// kvoli nepresnosti vypoctov umoznime pohyb aj ked velmi malou castou smeruje do roviny
		//	if( DOT3( vpold_vp, center-ClosestPointOnSphere) >= 0)
			if( DOT3( vpold_vp, center-ClosestPointOnSphere) > -0.000001f)
			{
				continue;
			}
			// gula nepretina rovinu
			// kolidujuci bod je priesecnik roviny a priamky vedenej z bodu ClosestPointOnSphere
			// v smere pohybu t.j. z vpold do vp

			float t = LinePlaneIntersectionDirParameter( ClosestPointOnSphere, vpold_vp, normal, distance);
			// t > 1.f, priesecnik z rovinou je dalej ako vpold_vp od bodu ClosestPointOnSphere
			if(t>1.f)
				continue;	// za cely krok vpold_vp sa s tymto trojuholnikom nestretneme
			else if( t<-radius/vpold_vp.Length())		// priesecnik je za gulou, v smere pohybu tuto rovinu nestretneme
				continue;
			else 
				contactPointSphereToPlane = ClosestPointOnSphere+t*vpold_vp;
		}
		// najdeme kolidujuci bod na trojuholniku
		vec contactPointSphereToTriangle;
		// ak sa bod contactPointSphereToPlane nenachadza v trojuholniku 
		// najdeme najblizsi bod trojuholnika k bodu contactPointSphereToTriangle
		if( !PointInsidePolygon( contactPointSphereToPlane, collision[i].a, collision[i].b, collision[i].c) )
		{
			// najdeme najblizsi bod k contactPointSphereToPlane na hranach trojuholnika
			// z tychto vyberieme najblizi k contactPointSphereToPlane
			vec closest_ab = ClosestPointOnLine( collision[i].a, collision[i].b, contactPointSphereToPlane);
			vec closest_bc = ClosestPointOnLine( collision[i].b, collision[i].c, contactPointSphereToPlane);
			vec closest_ca = ClosestPointOnLine( collision[i].c, collision[i].a, contactPointSphereToPlane);
			
			float dist_ab = Distance2( closest_ab, contactPointSphereToPlane);
			float dist_bc = Distance2( closest_bc, contactPointSphereToPlane);
			float dist_ca = Distance2( closest_ca, contactPointSphereToPlane);
			
			if( dist_ab<dist_bc)
			{
				if(dist_ab<dist_ca)
					contactPointSphereToTriangle = closest_ab;
				else
					contactPointSphereToTriangle = closest_ca;
			}
			else
			{
				if(dist_bc<dist_ca)
					contactPointSphereToTriangle = closest_bc;
				else
					contactPointSphereToTriangle = closest_ca;
			}

			// kedze kolidujuci bod na trojuholniku je iny ako kolidujuci bod na rovine
			// zmeni sa aj kolidujuci bod na guli - ClosestPointOnSphere
			// vypocitame ho ako priesecnik gule a priamky z bodu contactPointSphereToTriangle
			// v smere pohybu t.j. z vpold do vp
			double t1,t2;

			if( LineSphereIntersectionDir( contactPointSphereToTriangle, vpold_vp, center, radius, &t1, &t2) )
			{
				if( t1<=0 && t2<0)
				{
					// gula je pred trojuholnikom
					// berieme bod s t1, lebo ten je blizsie k stene (t1>t2)
					if( t1<-1.f)continue;		// tento trojuholnik nas nezaujima lebo nekoliduje po cely tento krok
					ClosestPointOnSphere = t1*vpold_vp+contactPointSphereToTriangle;
					if( (center.y-ClosestPointOnSphere.y)>ground_skew )return 1;
					else continue;
					// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
					// kolidujuceho bodu na trojuholniku
				//	vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
				}
				else if( t1>0 && t2<0)
				{
					// gula je v stene, vratime ju von zo steny
					// berieme bod, ktory je blizsie k rovine
					vec t1point = t1*vpold_vp+contactPointSphereToTriangle;
					vec t2point = t2*vpold_vp+contactPointSphereToTriangle;

				/*	if(PlanePointDistance( normal, distance, t1point)<=PlanePointDistance( normal, distance, t2point) )
						ClosestPointOnSphere = t1point;
					else 
						ClosestPointOnSphere = t2point;
				*/
					if( ABS(t1) < ABS(t2) )
						ClosestPointOnSphere = t1point;
					else
						ClosestPointOnSphere = t2point;
				
					if( (center.y-ClosestPointOnSphere.y)>ground_skew )return 1;
					else continue;
					// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
					// kolidujuceho bodu na trojuholniku
				//	vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
				}
				else // if( t1>0 && t2>0)
				{
					// gula je za trojuholnikom, gula nekoliduje s trojuholnikom v tomto smere pohybu
					continue;
				}
			}
			else
			{
				// nie je priesecnik, gula je mimo trojuholnika
				continue;
			}
		}
		else
		{
			if( (center.y-ClosestPointOnSphere.y)>ground_skew )return 1;
			else continue;

			// bod je vnutri trojuholnika
		//	contactPointSphereToTriangle = contactPointSphereToPlane;
			
			// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
			// kolidujuceho bodu na trojuholniku
		//	vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
		}
/*			if( LineSphereIntersectionDir( contactPointSphereToTriangle, vpold_vp, center, radius, &t1, &t2) )
			{
				if( t1<=0 && t2<0)
				{
					// gula je pred trojuholnikom
					// berieme bod s t1, lebo ten je blizsie k stene (t1>t2)
					if( t1<-1.f)continue;		// tento trojuholnik nas nezaujima lebo nekoliduje po cely tento krok
					return 1;
				}
				else if( t1>0 && t2<0)
				{
					return 1;		// gula je v stene
				}
				else // if( t1>0 && t2>0)
				{
					// gula je za trojuholnikom, gula nekoliduje s trojuholnikom v tomto smere pohybu
					continue;
				}
			}
			else
			{
				// nie je priesecnik, gula je mimo trojuholnika
				continue;
			}
		}
		else
		{
			return 1;		// bod je vnutri trojuholnika
		}*/
	}
	return 0;
}
Пример #2
0
/**
* @brief Executes the Fight command c
*/
void CMobileCAI::ExecuteFight(Command& c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);

	if (c.params.size() == 1 && !owner->weapons.empty()) {
		CWeapon* w = owner->weapons.front();

		if ((orderTarget != NULL) && !w->AttackUnit(orderTarget, false)) {
			CUnit* newTarget = helper->GetClosestValidTarget(owner->pos, owner->maxRange, owner->allyteam, this);

			if ((newTarget != NULL) && w->AttackUnit(newTarget, false)) {
				c.params[0] = newTarget->id;

				inCommand = false;
			} else {
				w->AttackUnit(orderTarget, false);
			}
		}

		ExecuteAttack(c);
		return;
	}

	if (tempOrder) {
		inCommand = true;
		tempOrder = false;
	}
	if (c.params.size() < 3) {
		LOG_L(L_ERROR,
				"Received a Fight command with less than 3 params on %s in MobileCAI",
				owner->unitDef->humanName.c_str());
		return;
	}
	if (c.params.size() >= 6) {
		if (!inCommand) {
			commandPos1 = c.GetPos(3);
		}
	} else {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) {
			commandPos1 = owner->pos;
		}
	}

	float3 pos = c.GetPos(0);

	if (!inCommand) {
		inCommand = true;
		commandPos2 = pos;
		lastUserGoal = commandPos2;
	}
	if (c.params.size() >= 6) {
		pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}
	if (pos != goalPos) {
		SetGoal(pos, owner->pos);
	}

	if (owner->unitDef->canAttack && owner->fireState >= FIRESTATE_FIREATWILL && !owner->weapons.empty()) {
		const float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		const float searchRadius = owner->maxRange + 100 * owner->moveState * owner->moveState;
		CUnit* enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this);

		if (enemy != NULL) {
			PushOrUpdateReturnFight();

			// make the attack-command inherit <c>'s options
			// NOTE: see AirCAI::ExecuteFight why we do not set INTERNAL_ORDER
			Command c2(CMD_ATTACK, c.options, enemy->id);
			commandQue.push_front(c2);

			inCommand = false;
			tempOrder = true;

			// avoid infinite loops (?)
			if (lastPC != gs->frameNum) {
				lastPC = gs->frameNum;
				SlowUpdate();
			}
			return;
		}
	}

	if ((owner->pos - goalPos).SqLength2D() < (64 * 64)
			|| (owner->moveType->progressState == AMoveType::Failed)){
		FinishCommand();
	}
}
Пример #3
0
void CAirCAI::ExecuteFight(Command &c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
	AAirMoveType* myPlane = (AAirMoveType*) owner->moveType;
	if(tempOrder){
		tempOrder=false;
		inCommand=true;
	}
	if(c.params.size()<3){		//this shouldnt happen but anyway ...
		logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI",
			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 {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(127*127)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if ((owner->pos - commandPos1).SqLength2D() > (150 * 150)) {
			commandPos1 = owner->pos;
		}
	}
	goalPos = float3(c.params[0], c.params[1], c.params[2]);
	if(!inCommand){
		inCommand = true;
		commandPos2=goalPos;
	}
	if(c.params.size() >= 6){
		goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}

	// CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway...
	if (owner->unitDef->canAttack && owner->fireState >= 2
			&& owner->moveState != 0 && owner->maxRange > 0) {
		CUnit* enemy = NULL;
		if(myPlane->IsFighter()) {
			const float3 curPosOnLine = ClosestPointOnLine(
					commandPos1, commandPos2, owner->pos + owner->speed*10);
			const float searchRadius = 1000 * owner->moveState;
			enemy = helper->GetClosestEnemyAircraft(curPosOnLine, searchRadius, owner->allyteam);
		}
		if(IsValidTarget(enemy) && (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|INTERNAL_ORDER;
			commandQue.push_front(nc);
			tempOrder=true;
			inCommand=false;
			if(lastPC1!=gs->frameNum){	//avoid infinite loops
				lastPC1=gs->frameNum;
				SlowUpdate();
			}
			return;
		} else {
			const float3 curPosOnLine = ClosestPointOnLine(
					commandPos1, commandPos2, owner->pos + owner->speed * 20);
			const float searchRadius = 500 * owner->moveState;
			enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this);
			if (enemy != NULL) {
				Command nc;
				nc.id = CMD_ATTACK;
				nc.params.push_back(enemy->id);
				nc.options = c.options | INTERNAL_ORDER;
				PushOrUpdateReturnFight();
				commandQue.push_front(nc);
				tempOrder = true;
				inCommand = false;
				if(lastPC2 != gs->frameNum){	//avoid infinite loops
					lastPC2 = gs->frameNum;
					SlowUpdate();
				}
				return;
			}
		}
	}
	myPlane->goalPos = goalPos;

	CAirMoveType* airmt = dynamic_cast<CAirMoveType*>(myPlane);
	const float radius = airmt ? std::max(airmt->turnRadius + 2*SQUARE_SIZE, 128.f) : 127.f;

	// we're either circling or will get to the target in 8 frames
	if((owner->pos - goalPos).SqLength2D() < (radius * radius)
			|| (owner->pos + owner->speed*8 - goalPos).SqLength2D() < 127*127) {
		FinishCommand();
	}
	return;
}
Пример #4
0
vec CheckCollision( vector<z_face> &collision, vec vp, vec vpold, float radius)
{
	//	if(vpold_vp.Length()==0)return vpold;
	vec vpold_vp = vp-vpold;		// smer pohybu
	vec vpold_vp_povodny = vpold_vp;// smer pohybu
	int iter=0;
	float radius2 = radius*radius;

	vec newmove = vpold_vp;
	vec newClosestPointOnSphere;
	vec newContactPointSphereToTriangle;

	do
	{
		float distanceCenterPointOnTriangle=1.e+15f;
		int smykanie=0;
		for( int i=0; i<collision.size(); i++)
		{
			vec normal = collision[i].normal;
			
			vec vp_move;
			vec center = vpold;
			float distance = PlaneDistance( normal, collision[i].a);		// D = - (Ax+By+Cz)
			// ---------------------------------------------------------
			// najdeme kolidujuci bod na guli
			vec ClosestPointOnSphere;		// najblizsi bod gule k rovine aktualneho trojuholnika
			// najdeme ho ako priesecnik priamky prechadzajucej stredom gule a smerovym vektorom = normalovemu vektoru roviny (trojuholnika)
			// vypocitame ho, ale jednodusie tak, ze pripocitame (opocitame) k stredu vektor normala*radius
			
			if( PlanePointDelta( normal, distance, center) > 0 )
			{
				// center je na strane normaly, blizsi bod je v opacnom smere ako smer normaly
				ClosestPointOnSphere = -radius*normal+center;
			}
			else
			{
				// center je na opacnej strane ako normala, blizsi bod je v smere normaly
				ClosestPointOnSphere = radius*normal+center;
			}

			// ---------------------------------------------------------
			// najdeme kolidujuci bod na trojuholniku
			// najprv najdeme kolidujuci bod vzhladom na rovinu v ktorej lezi trojuholnik
			vec contactPointSphereToPlane;			// kolidujuci bod na rovine trojuholnika s gulou
			float distanceCenterToPlane;			// vzdialenost stredu gule k rovine
			// zistime ci rovina pretina gulu
			if( SpherePlaneCollision( center, 0.9999f*radius, normal, distance, &distanceCenterToPlane)==1 )
			{
				// gula pretina rovinu
				// kolidujuci bod je bod na rovine najblizsi k stredu gule
				// je vzdialeny od roviny na distanceCenterToPlane, pretoze pocitame bod na rovine pouzijeme -
				contactPointSphereToPlane = center-distanceCenterToPlane*normal;
			}
			else
			{
				// nie sme v kolizii z gulov, ak sa pohybujeme v smere od roviny, nemoze nastat ziadna kolizia
				// ak sa pohybujeme v smere kolmom na normalovy vektor roviny, tak isto kolizia nehrozi
				// kvoli nepresnosti vypoctov umoznime pohyb aj ked velmi malou castou smeruje do roviny
			//	if( DOT3( vpold_vp, center-ClosestPointOnSphere) >= 0)
				if( DOT3( vpold_vp, center-ClosestPointOnSphere) > -0.000001f)
				{
					continue;
				}
				// gula nepretina rovinu
				// kolidujuci bod je priesecnik roviny a priamky vedenej z bodu ClosestPointOnSphere
				// v smere pohybu t.j. z vpold do vp

				float t = LinePlaneIntersectionDirParameter( ClosestPointOnSphere, vpold_vp, normal, distance);
				// t > 1.f, priesecnik z rovinou je dalej ako vpold_vp od bodu ClosestPointOnSphere
				if(t>1.f)
					continue;	// za cely krok vpold_vp sa s tymto trojuholnikom nestretneme
				else if( t<-radius/vpold_vp.Length())		// priesecnik je za gulou, v smere pohybu tuto rovinu nestretneme
					continue;
				else 
					contactPointSphereToPlane = ClosestPointOnSphere+t*vpold_vp;
			}
			// najdeme kolidujuci bod na trojuholniku
			vec contactPointSphereToTriangle;
			// ak sa bod contactPointSphereToPlane nenachadza v trojuholniku 
			// najdeme najblizsi bod trojuholnika k bodu contactPointSphereToTriangle
			if( !PointInsidePolygon( contactPointSphereToPlane, collision[i].a, collision[i].b, collision[i].c) )
			{
				// najdeme najblizsi bod k contactPointSphereToPlane na hranach trojuholnika
				// z tychto vyberieme najblizi k contactPointSphereToPlane
				vec closest_ab = ClosestPointOnLine( collision[i].a, collision[i].b, contactPointSphereToPlane);
				vec closest_bc = ClosestPointOnLine( collision[i].b, collision[i].c, contactPointSphereToPlane);
				vec closest_ca = ClosestPointOnLine( collision[i].c, collision[i].a, contactPointSphereToPlane);
				
				float dist_ab = Distance2( closest_ab, contactPointSphereToPlane);
				float dist_bc = Distance2( closest_bc, contactPointSphereToPlane);
				float dist_ca = Distance2( closest_ca, contactPointSphereToPlane);
				
				if( dist_ab<dist_bc)
				{
					if(dist_ab<dist_ca)
						contactPointSphereToTriangle = closest_ab;
					else
						contactPointSphereToTriangle = closest_ca;
				}
				else
				{
					if(dist_bc<dist_ca)
						contactPointSphereToTriangle = closest_bc;
					else
						contactPointSphereToTriangle = closest_ca;
				}

				// kedze kolidujuci bod na trojuholniku je iny ako kolidujuci bod na rovine
				// zmeni sa aj kolidujuci bod na guli - ClosestPointOnSphere
				// vypocitame ho ako priesecnik gule a priamky z bodu contactPointSphereToTriangle
				// v smere pohybu t.j. z vpold do vp
				double t1,t2;

				if( LineSphereIntersectionDir( contactPointSphereToTriangle, vpold_vp, center, radius, &t1, &t2) )
				{
					if( t1<=0 && t2<0)
					{
						// gula je pred trojuholnikom
						// berieme bod s t1, lebo ten je blizsie k stene (t1>t2)
						if( t1<-1.f)continue;		// tento trojuholnik nas nezaujima lebo nekoliduje po cely tento krok
						ClosestPointOnSphere = t1*vpold_vp+contactPointSphereToTriangle;

						// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
						// kolidujuceho bodu na trojuholniku
						vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
					}
					else if( t1>0 && t2<0)
					{
						// gula je v stene, vratime ju von zo steny
						// berieme bod, ktory je blizsie k rovine
						vec t1point = t1*vpold_vp+contactPointSphereToTriangle;
						vec t2point = t2*vpold_vp+contactPointSphereToTriangle;

					/*	if(PlanePointDistance( normal, distance, t1point)<=PlanePointDistance( normal, distance, t2point) )
							ClosestPointOnSphere = t1point;
						else 
							ClosestPointOnSphere = t2point;
					*/
						if( ABS(t1) < ABS(t2) )
							ClosestPointOnSphere = t1point;
						else
							ClosestPointOnSphere = t2point;
					
						// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
						// kolidujuceho bodu na trojuholniku
						vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
					}
					else // if( t1>0 && t2>0)
					{
						// gula je za trojuholnikom, gula nekoliduje s trojuholnikom v tomto smere pohybu
						continue;
					}
				}
				else
				{
					// nie je priesecnik, gula je mimo trojuholnika
					continue;
				}
			}
			else
			{
				// bod je vnutri trojuholnika
				contactPointSphereToTriangle = contactPointSphereToPlane;
				
				// mozeme sa pohnut iba tolko pokial sa colidujuci bod na guli nedotkne 
				// kolidujuceho bodu na trojuholniku
				vp_move = contactPointSphereToTriangle - ClosestPointOnSphere;
			}

			// zistime vzdialenost kontaktneho bodu na trojuholniku ku stredu gule
			float dist = Distance2(contactPointSphereToTriangle,center);
			if(dist<radius2)		// ak je mensi ako polomer, gula je v kolizii z polygonom
			{
				if(dist<distanceCenterPointOnTriangle)	// ak vzdialenost je mensia ako ineho bodu v kolizii, nahradime ho
				{
					distanceCenterPointOnTriangle=dist;
					newmove = vp_move;
					newClosestPointOnSphere = ClosestPointOnSphere;
					newContactPointSphereToTriangle = contactPointSphereToTriangle;
				}
			}
			else
			{
				if(distanceCenterPointOnTriangle>5.e+14f)	// nenasiel sa ziaden bod vnutri gule
				{
					if( vp_move.Length2() < newmove.Length2() )		// berieme kratsi
					{
						newmove = vp_move;
						newClosestPointOnSphere = ClosestPointOnSphere;
						newContactPointSphereToTriangle = contactPointSphereToTriangle;
					}
				}
			}
			smykanie=1;
		}

		if(smykanie)
		{
			vec normal=vpold-newClosestPointOnSphere;
			float distance = PlaneDistance( normal, newContactPointSphereToTriangle);
			vec delta = LinePlaneIntersectionDir( newClosestPointOnSphere+vpold_vp, normal, normal, distance)-newContactPointSphereToTriangle;
		//	vec	newvp = newClosestPointOnSphere+vpold_vp;
		//	float distancepoint = PlanePointDelta( normal, distance, newvp);
		//	vec intersec = -distancepoint*normal+newvp;
		//	vec delta = intersec-newContactPointSphereToTriangle;

			// taky klzavy pohyb, ktory ide proti povodnemu pohybu zamietneme
			if( DOT3(vpold_vp_povodny, delta) < 0)delta.clear();

			vpold += newmove;				// posunieme sa po najblizi kolidujuci bod
			vpold += 0.000001f*normal;
			vp = vpold + delta;				// cielovy bod posunieme o deltu klzanim
			vpold_vp = vp-vpold;			// novy vektor pohybu
			newmove = vpold_vp;
			iter++;
		}
		else
		{
			vpold += newmove;
			vpold_vp.clear();
			iter=1000;
		}
	}
	while( (vpold_vp.Length2()>1.e-8f)&&(iter<10) );
	return vpold;
}
Пример #5
0
/**
* @brief Executes the Fight command c
*/
void CMobileCAI::ExecuteFight(Command &c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
	if(c.params.size() == 1) {
		if(orderTarget && !owner->weapons.empty()
				&& !owner->weapons.front()->AttackUnit(orderTarget, false)) {
			CUnit* newTarget = helper->GetClosestValidTarget(
				owner->pos, owner->maxRange, owner->allyteam, this);
			if ((newTarget != NULL) && owner->weapons.front()->AttackUnit(newTarget, false)) {
				c.params[0] = newTarget->id;
				inCommand = false;
			} else {
				owner->weapons.front()->AttackUnit(orderTarget, false);
			}
		}
		ExecuteAttack(c);
		return;
	}
	if(tempOrder){
		inCommand = true;
		tempOrder = false;
	}
	if (c.params.size() < 3) {
		logOutput.Print("Error: got fight cmd with less than 3 params on %s in MobileCAI",
			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 {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) {
			commandPos1 = owner->pos;
		}
	}
	float3 pos(c.params[0],c.params[1],c.params[2]);
	if(!inCommand){
		inCommand = true;
		commandPos2 = pos;
		lastUserGoal = commandPos2;
	}
	if(c.params.size() >= 6){
		pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}
	if(pos!=goalPos){
		SetGoal(pos, owner->pos);
	}

	if (owner->unitDef->canAttack && owner->fireState >= 2 && !owner->weapons.empty()) {
		const float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		const float searchRadius = owner->maxRange + 100 * owner->moveState * owner->moveState;
		CUnit* enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this);
		if (enemy != NULL) {
			Command c2;
			c2.id=CMD_FIGHT;
			c2.options=c.options|INTERNAL_ORDER;
			c2.params.push_back(enemy->id);
			PushOrUpdateReturnFight();
			commandQue.push_front(c2);
			inCommand=false;
			tempOrder=true;
			if(lastPC!=gs->frameNum){	//avoid infinite loops
				lastPC=gs->frameNum;
				SlowUpdate();
			}
			return;
		}
	}
	if((owner->pos - goalPos).SqLength2D() < (64 * 64)
			|| (owner->moveType->progressState == AMoveType::Failed)){
		FinishCommand();
	}
	return;
}
Пример #6
0
/**
* @brief Causes this CMobileCAI to execute the attack order c
*/
void CMobileCAI::ExecuteAttack(Command &c)
{
	assert(owner->unitDef->canAttack);

	// limit how far away we fly
	if (tempOrder && (owner->moveState < 2) && orderTarget
			&& LinePointDist(ClosestPointOnLine(commandPos1, commandPos2, owner->pos),
					commandPos2, orderTarget->pos)
			> (500 * owner->moveState + owner->maxRange)) {
		StopMove();
		FinishCommand();
		return;
	}

	// check if we are in direct command of attacker
	if (!inCommand) {
		// don't start counting until the owner->AttackGround() order is given
		owner->commandShotCount = -1;

		if (c.params.size() == 1) {
			const unsigned int targetID = (unsigned int) c.params[0];
			const bool legalTarget      = (targetID < uh->MaxUnits());
			CUnit* targetUnit           = (legalTarget)? uh->units[targetID]: 0x0;

			// check if we have valid target parameter and that we aren't attacking ourselves
			if (legalTarget && targetUnit != NULL && targetUnit != owner) {
				float3 fix = targetUnit->pos + owner->posErrorVector * 128;
				float3 diff = float3(fix - owner->pos).Normalize();

				SetGoal(fix - diff * targetUnit->radius, owner->pos);

				orderTarget = targetUnit;
				AddDeathDependence(orderTarget);
				inCommand = true;
			} else {
				// unit may not fire on itself, cancel order
				StopMove();
				FinishCommand();
				return;
			}
		}
		else {
			// user gave force-fire attack command
			float3 pos(c.params[0], c.params[1], c.params[2]);
			SetGoal(pos, owner->pos);
			inCommand = true;
		}
	}
	else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
		// the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count
		if ((commandQue.size() > 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
			StopMove();
			FinishCommand();
			return;
		}
	}

	// if our target is dead or we lost it then stop attacking
	// NOTE: unit should actually just continue to target area!
	if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
		// cancel keeppointingto
		StopMove();
		FinishCommand();
		return;
	}


	// user clicked on enemy unit (note that we handle aircrafts slightly differently)
	if (orderTarget) {
		//bool b1 = owner->AttackUnit(orderTarget, c.id == CMD_DGUN);
		bool b2 = false;
		bool b3 = false;
		bool b4 = false;
		float edgeFactor = 0.f; // percent offset to target center
		float3 diff = owner->pos - orderTarget->midPos;

		if (owner->weapons.size() > 0) {
			if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
				StopMove();
				FinishCommand();
				return;
			}
			CWeapon* w = owner->weapons.front();
			// if we have at least one weapon then check if we
			// can hit target with our first (meanest) one
			b2 = w->TryTargetRotate(orderTarget, c.id == CMD_DGUN);
			b3 = Square(w->range - (w->relWeaponPos).Length())
					> (orderTarget->pos.SqDistance(owner->pos));
			b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z),
					orderTarget->pos, orderTarget != NULL, orderTarget);
			edgeFactor = fabs(w->targetBorder);
		}

		float diffLength2d = diff.Length2D();

		// if w->AttackUnit() returned true then we are already
		// in range with our biggest weapon so stop moving
		// also make sure that we're not locked in close-in/in-range state loop
		// due to rotates invoked by in-range or out-of-range states
		if (b2) {
			if (!(tempOrder && owner->moveState == 0)
				&& (diffLength2d * 1.4f > owner->maxRange
					- orderTarget->speed.SqLength()
							/ owner->unitDef->maxAcc)
				&& b4 && diff.dot(orderTarget->speed) < 0)
			{
				SetGoal(owner->pos + (orderTarget->speed * 80), owner->pos,
						SQUARE_SIZE, orderTarget->speed.Length() * 1.1f);
			} else {
				StopMove();
				// FIXME kill magic frame number
				if (gs->frameNum > lastCloseInTry + MAX_CLOSE_IN_RETRY_TICKS) {
					owner->moveType->KeepPointingTo(orderTarget->midPos,
							std::min((float) owner->losRadius * loshandler->losDiv,
								owner->maxRange * 0.9f), true);
				}
			}
			owner->AttackUnit(orderTarget, c.id == CMD_DGUN);
		}

		// if we're on hold pos in a temporary order, then none of the close-in
		// code below should run, and the attack command is cancelled.
		else if (tempOrder && owner->moveState == 0) {
			StopMove();
			FinishCommand();
			return;
		}

		// if ((our movetype has type TAAirMoveType and length of 2D vector from us to target
		// less than 90% of our maximum range) OR squared length of 2D vector from us to target
		// less than 1024) then we are close enough
		else if(diffLength2d < (owner->maxRange * 0.9f)){
			if (dynamic_cast<CTAAirMoveType*>(owner->moveType)
					|| (diff.SqLength2D() < 1024))
			{
				StopMove();
				owner->moveType->KeepPointingTo(orderTarget->midPos,
						std::min((float) owner->losRadius * loshandler->losDiv,
							owner->maxRange * 0.9f), true);
			}

			// if (((first weapon range minus first weapon length greater than distance to target)
			// and length of 2D vector from us to target less than 90% of our maximum range)
			// then we are close enough, but need to move sideways to get a shot.
			//assumption is flawed: The unit may be aiming or otherwise unable to shoot
			else if (owner->unitDef->strafeToAttack && b3 && diffLength2d < (owner->maxRange * 0.9f))
			{
				moveDir ^= (owner->moveType->progressState == AMoveType::Failed);
				float sin = moveDir ? 3.0/5 : -3.0/5;
				float cos = 4.0/5;
				float3 goalDiff(0, 0, 0);
				goalDiff.x = diff.dot(float3(cos, 0, -sin));
				goalDiff.z = diff.dot(float3(sin, 0, cos));
				goalDiff *= (diffLength2d < (owner->maxRange * 0.3f)) ? 1/cos : cos;
				goalDiff += orderTarget->pos;
				SetGoal(goalDiff, owner->pos);
			}
		}

		// if 2D distance of (target position plus attacker error vector times 128)
		// to goal position greater than
		// (10 plus 20% of 2D distance between attacker and target) then we need to close
		// in on target more
		else if ((orderTarget->pos + owner->posErrorVector * 128).SqDistance2D(goalPos)
				> Square(10 + orderTarget->pos.distance2D(owner->pos) * 0.2f)) {
			// if the target isn't in LOS, go to its approximate position
			// otherwise try to go precisely to the target
			// this should fix issues with low range weapons (mainly melee)
			float3 fix = orderTarget->pos +
					(orderTarget->losStatus[owner->allyteam] & LOS_INLOS ?
						float3(0.f,0.f,0.f) :
						owner->posErrorVector * 128);
			float3 norm = float3(fix - owner->pos).Normalize();
			float3 goal = fix - norm*(orderTarget->radius*edgeFactor*0.8f);
			SetGoal(goal, owner->pos);
			if (lastCloseInTry < gs->frameNum + MAX_CLOSE_IN_RETRY_TICKS)
				lastCloseInTry = gs->frameNum;
		}
	}

	// user is attacking ground
	else {
		const float3 pos(c.params[0], c.params[1], c.params[2]);
		const float3 diff = owner->pos - pos;

		if (owner->weapons.size() > 0) {
			// if we have at least one weapon then check if
			// we can hit position with our first (assumed
			// to be meanest) one
			CWeapon* w = owner->weapons.front();

			// XXX hack - dgun overrides any checks
			if (c.id == CMD_DGUN) {
				float rr = owner->maxRange * owner->maxRange;

				for (vector<CWeapon*>::iterator it = owner->weapons.begin();
						it != owner->weapons.end(); ++it) {

					if (dynamic_cast<CDGunWeapon*>(*it))
						rr = (*it)->range * (*it)->range;
				}

				if (diff.SqLength() < rr) {
					StopMove();
					owner->AttackGround(pos, c.id == CMD_DGUN);
					owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
				}
			} else {
				const bool inAngle = w->TryTargetRotate(pos, c.id == CMD_DGUN);
				const bool inRange = diff.Length2D() < (w->range - (w->relWeaponPos).Length2D());

				if (inAngle || inRange) {
					StopMove();
					owner->AttackGround(pos, c.id == CMD_DGUN);
					owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
				}
			}
		}

		else if (diff.SqLength2D() < 1024) {
			StopMove();
			owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
		}

		// if we are more than 10 units distant from target position then keeping moving closer
		else if (pos.SqDistance2D(goalPos) > 100) {
			SetGoal(pos, owner->pos);
		}
	}
}
Пример #7
0
void CAirCAI::ExecuteFight(Command& c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);

	// FIXME: check owner->UsingScriptMoveType() and skip rest if true?
	AAirMoveType* myPlane = GetStrafeAirMoveType(owner);

	assert(owner == myPlane->owner);

	if (tempOrder) {
		tempOrder = false;
		inCommand = true;
	}

	if (c.params.size() < 3) {
		LOG_L(L_ERROR, "[ACAI::%s][f=%d][id=%d] CMD_FIGHT #params < 3", __FUNCTION__, gs->frameNum, owner->id);
		return;
	}

	if (c.params.size() >= 6) {
		if (!inCommand) {
			commandPos1 = c.GetPos(3);
		}
	} else {
		// HACK to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(127*127)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);

		if ((owner->pos - commandPos1).SqLength2D() > (150 * 150)) {
			commandPos1 = owner->pos;
		}
	}

	goalPos = c.GetPos(0);

	if (!inCommand) {
		inCommand = true;
		commandPos2 = goalPos;
	}
	if (c.params.size() >= 6) {
		goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}

	// CMD_FIGHT is pretty useless if !canAttack, but we try to honour the modders wishes anyway...
	if (owner->unitDef->canAttack && (owner->fireState >= FIRESTATE_FIREATWILL)
			&& (owner->moveState != MOVESTATE_HOLDPOS) && (owner->maxRange > 0))
	{
		CUnit* enemy = NULL;

		if (owner->unitDef->IsFighterAirUnit()) {
			const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed*10);
			const float R = 1000.0f * owner->moveState;

			enemy = CGameHelper::GetClosestEnemyAircraft(NULL, P, R, owner->allyteam);
		}
		if (IsValidTarget(enemy) && (owner->moveState != MOVESTATE_MANEUVER
				|| LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000))
		{
			// make the attack-command inherit <c>'s options
			// (if <c> is internal, then so are the attacks)
			//
			// this is needed because CWeapon code will not
			// fire on "internal" targets if the weapon has
			// noAutoTarget set (although the <enemy> CUnit*
			// is technically not a user-target, we treat it
			// as such) even when explicitly told to fight
			Command nc(CMD_ATTACK, c.options, enemy->id);
			commandQue.push_front(nc);

			tempOrder = true;
			inCommand = false;

			if (lastPC1 != gs->frameNum) { // avoid infinite loops
				lastPC1 = gs->frameNum;
				SlowUpdate();
			}
			return;
		} else {
			const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed * 20);
			const float R = 500.0f * owner->moveState;

			enemy = CGameHelper::GetClosestValidTarget(P, R, owner->allyteam, this);

			if (enemy != NULL) {
				PushOrUpdateReturnFight();

				// make the attack-command inherit <c>'s options
				Command nc(CMD_ATTACK, c.options, enemy->id);
				commandQue.push_front(nc);

				tempOrder = true;
				inCommand = false;

				// avoid infinite loops (?)
				if (lastPC2 != gs->frameNum) {
					lastPC2 = gs->frameNum;
					SlowUpdate();
				}
				return;
			}
		}
	}

	myPlane->goalPos = goalPos;

	const CStrafeAirMoveType* airMT = (!owner->UsingScriptMoveType())? static_cast<const CStrafeAirMoveType*>(myPlane): NULL;
	const float radius = (airMT != NULL)? std::max(airMT->turnRadius + 2*SQUARE_SIZE, 128.f) : 127.f;

	// we're either circling or will get to the target in 8 frames
	if ((owner->pos - goalPos).SqLength2D() < (radius * radius)
			|| (owner->pos + owner->speed*8 - goalPos).SqLength2D() < 127*127)
	{
		FinishCommand();
	}
}
Пример #8
0
void CBuilderCAI::ExecuteFight(Command& c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);

	if (tempOrder) {
		tempOrder = false;
		inCommand = true;
	}
	if (c.params.size() < 3) { // this shouldnt happen but anyway ...
		LOG_L(L_ERROR,
				"Received a Fight command with less than 3 params on %s in BuilderCAI",
				owner->unitDef->humanName.c_str());
		return;
	}

	if (c.params.size() >= 6) {
		if (!inCommand) {
			commandPos1 = c.GetPos(3);
		}
	} else {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if (f3SqDist(owner->pos, commandPos1) > (96 * 96)) {
			commandPos1 = owner->pos;
		}
	}

	float3 pos = c.GetPos(0);
	if (!inCommand) {
		inCommand = true;
		commandPos2 = pos;
	}

	float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	if (c.params.size() >= 6) {
		pos = curPosOnLine;
	}

	if (pos != owner->moveType->goalPos) {
		SetGoal(pos, owner->pos);
	}

	const bool resurrectMode = !!(c.options & ALT_KEY);
	const bool reclaimEnemyMode = !!(c.options & META_KEY);
	const bool reclaimEnemyOnlyMode = (c.options & CONTROL_KEY) && (c.options & META_KEY);

	ReclaimOption recopt;
	if (resurrectMode)        recopt |= REC_NONREZ;
	if (reclaimEnemyMode)     recopt |= REC_ENEMY;
	if (reclaimEnemyOnlyMode) recopt |= REC_ENEMYONLY;

	const float searchRadius = (owner->immobile ? 0 : (300 * owner->moveState)) + ownerBuilder->buildDistance;

	if (!reclaimEnemyOnlyMode && (owner->unitDef->canRepair || owner->unitDef->canAssist) && // Priority 1: Repair
	    FindRepairTargetAndRepair(curPosOnLine, searchRadius, c.options, true, resurrectMode)){
		tempOrder = true;
		inCommand = false;
		if (lastPC1 != gs->frameNum) {  //avoid infinite loops
			lastPC1 = gs->frameNum;
			SlowUpdate();
		}
		return;
	}
	if (!reclaimEnemyOnlyMode && resurrectMode && owner->unitDef->canResurrect && // Priority 2: Resurrect (optional)
	    FindResurrectableFeatureAndResurrect(curPosOnLine, searchRadius, c.options, false)) {
		tempOrder = true;
		inCommand = false;
		if (lastPC2 != gs->frameNum) {  //avoid infinite loops
			lastPC2 = gs->frameNum;
			SlowUpdate();
		}
		return;
	}
	if (owner->unitDef->canReclaim && // Priority 3: Reclaim / reclaim non resurrectable (optional) / reclaim enemy units (optional)
	    FindReclaimTargetAndReclaim(curPosOnLine, searchRadius, c.options, recopt)) {
		tempOrder = true;
		inCommand = false;
		if (lastPC3 != gs->frameNum) {  //avoid infinite loops
			lastPC3 = gs->frameNum;
			SlowUpdate();
		}
		return;
	}
	if (f3SqDist(owner->pos, pos) < (64*64)) {
		StopMoveAndFinishCommand();
		return;
	}

	if (owner->HaveTarget() && owner->moveType->progressState != AMoveType::Done) {
		StopMove();
	} else {
		SetGoal(owner->moveType->goalPos, owner->pos);
	}
}
Пример #9
0
void CBuilderCAI::ExecuteFight(Command &c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
	CBuilder* fac=(CBuilder*)owner;
	if(tempOrder){
		tempOrder=false;
		inCommand=true;
	}
	if(c.params.size()<3){		//this shouldnt happen but anyway ...
		logOutput.Print("Error: got fight 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 {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) {
			commandPos1 = owner->pos;
		}
	}
	float3 pos(c.params[0],c.params[1],c.params[2]);
	if(!inCommand){
		inCommand = true;
		commandPos2 = pos;
	}
	if(c.params.size() >= 6){
		pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}
	if(pos!=goalPos){
		SetGoal(pos, owner->pos);
	}
	float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	if ((owner->unitDef->canRepair || owner->unitDef->canAssist) &&
	    FindRepairTargetAndRepair(curPosOnLine, 300*owner->moveState+fac->buildDistance-8,c.options,true)){
		tempOrder=true;
		inCommand=false;
		if(lastPC1!=gs->frameNum){	//avoid infinite loops
			lastPC1=gs->frameNum;
			SlowUpdate();
		}
		return;
	}
	if(owner->unitDef->canReclaim && FindReclaimableFeatureAndReclaim(curPosOnLine,300,c.options,false)){
		tempOrder=true;
		inCommand=false;
		if(lastPC2!=gs->frameNum){	//avoid infinite loops
			lastPC2=gs->frameNum;
			SlowUpdate();
		}
		return;
	}
	if((owner->pos - pos).SqLength2D()<(64*64)){
		FinishCommand();
		return;
	}
	if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done){
		StopMove();
	} else if(owner->moveType->progressState!=CMoveType::Active){
		owner->moveType->StartMoving(goalPos, 8);
	}
	return;
}
Пример #10
0
void RenderScene() 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
	glLoadIdentity();									// Reset The matrix


/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

	// Set our camera to the left a bit for a nice side view of the left hand side

		// 	    Position          View	     Up Vector
	gluLookAt(0, 1, -2,  0, 0, 0,   0, 1, 0);			// This determines where the camera's position and view is

	// Rotate the camera around our world for a 360 degree view of what is going on.
	// Yes I know... we are actually rotating the whole world, not the camera :)
	glRotatef(g_rotateY, 0, 1, 0);

	// We need a radius for our spheres, so let's create it here with 0.05f
	float radius  = 0.05f;
	float radius2 = 0.01f;
		
	// This sets our line width to %250, since 1 is %100 for normal line width
	glLineWidth(2.5f);

	// Turn of lighting so our line isn't effected by it
	glDisable(GL_LIGHTING);
	
	// Draw the line segment

	glBegin (GL_LINES);									// This is our BEGIN to draw

		glColor3ub(255, 0, 0);							// Make the Left vertex RED
		glVertex3f(g_vLine[0].x, g_vLine[0].y, g_vLine[0].z);

		glColor3ub(0, 255, 0);							// Make the Right vertex GREEN
		glVertex3f(g_vLine[1].x, g_vLine[1].y, g_vLine[1].z);
	glEnd();											// This is the END of drawing

	glEnable(GL_LIGHTING);								// Turn lighting back on

	// Instead of calculating the sphere ourselves, we are going to use quadrics.
	// Check out the tutorial on quadrics if this is confusing for you.

	// Allocate a quadric object to use as a sphere
	GLUquadricObj *pObj = gluNewQuadric();				// Get a Quadric off the stack

	// Below we create a new matrix so that when we translate the first sphere,
	// it doesn't effect the other sphere that we need to translate.

	glPushMatrix();										// Push on a new matrix

		// Move the sphere to it's center position
		glTranslatef(g_vPosition.x, g_vPosition.y, g_vPosition.z);
		
		// Draw the quadric as a sphere with the radius of .05 and a 15 by 15 detail.
		// To increase the detail of the sphere, just increase the 2 last parameters.
		gluSphere(pObj, radius, 15, 15);
	
	glPopMatrix();										// Pop off the current matrix

	// Now we need to find the closest point on the line.  We pass in the end points
	// of the line segment, and the point we want to use, which is the sphere's center position.
	// This returns the closest point to use for the center of the purple sphere.
	CVector3 vClosestPoint = ClosestPointOnLine(g_vLine[0], g_vLine[1], g_vPosition);

	// Move the closest point sphere to it's center position
	glTranslatef(vClosestPoint.x, vClosestPoint.y, vClosestPoint.z);

	// Turn the line segment sphere purple
	glColor3f(0.8f, 0, 1);

	// Draw the quadric as a sphere with the radius of .01 and a 15 by 15 detail.
	gluSphere(pObj, radius2, 15, 15);

	gluDeleteQuadric(pObj);								// Free the Quadric

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *


	SwapBuffers(g_hDC);									// Swap the backbuffers to the foreground
}
Пример #11
0
void CAirCAI::SlowUpdate()
{
	if(!commandQue.empty() && commandQue.front().timeOut<gs->frameNum){
		FinishCommand();
		return;
	}

	CAirMoveType* myPlane=(CAirMoveType*)owner->moveType;

	if(owner->unitDef->maxFuel>0){
		if(myPlane->reservedPad){
			return;
		}else{
			if(owner->currentFuel <= 0){
				owner->userAttackGround=false;
				owner->userTarget=0;
				inCommand=false;

				CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
				if(lp){
					myPlane->AddDeathDependence(lp);
					myPlane->reservedPad=lp;
					myPlane->padStatus=0;
					myPlane->oldGoalPos=myPlane->goalPos;
					return;
				}
				float3 landingPos = airBaseHandler->FindClosestAirBasePos(owner,8000,owner->unitDef->minAirBasePower);
				if(landingPos != ZeroVector && owner->pos.distance2D(landingPos) > 300){
					if(myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDED && owner->pos.distance2D(landingPos) > 800)
						myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF);	
					myPlane->goalPos=landingPos;		
				} else {
					if(myPlane->aircraftState == CAirMoveType::AIRCRAFT_FLYING)
						myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING);	
				}
				return;
			}
			if(owner->currentFuel < myPlane->repairBelowHealth*owner->unitDef->maxFuel){
				if(commandQue.empty() || commandQue.front().id==CMD_PATROL){
					CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
					if(lp){
						owner->userAttackGround=false;
						owner->userTarget=0;
						inCommand=false;
						myPlane->AddDeathDependence(lp);
						myPlane->reservedPad=lp;
						myPlane->padStatus=0;
						myPlane->oldGoalPos=myPlane->goalPos;
						if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_LANDED){
							myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF);
						}
						return;
					}		
				}
			}
		}
	}
	
	if(commandQue.empty()){
		if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_FLYING && !owner->unitDef->DontLand ())
			myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING);

		if(owner->unitDef->canAttack && 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){
					Command nc;
					nc.id=CMD_ATTACK;
					nc.params.push_back(enemy->id);
					nc.options=0;
					commandQue.push_front(nc);
					inCommand=false;
					return;
				}
			}
			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)){
				Command nc;
				nc.id=CMD_ATTACK;
				nc.params.push_back(enemy->id);
				nc.options=0;
				commandQue.push_front(nc);
				inCommand=false;
				return;
			}
		}
		return;
	}

	Command& c = commandQue.front();

	if (c.id == CMD_WAIT) {
		if ((myPlane->aircraftState == CAirMoveType::AIRCRAFT_FLYING)
		    && !owner->unitDef->DontLand()) {
			myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING);
		}
		return;
	}

	if (c.id != CMD_STOP) {
		if (myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDED) {
			myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF);
		}
		if (myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDING) {
			myPlane->SetState(CAirMoveType::AIRCRAFT_FLYING);
		}
	}

	float3 curPos=owner->pos;

	switch(c.id){
	case CMD_STOP:{
		CCommandAI::SlowUpdate();
		break;
	}
	case CMD_MOVE:{
		if(tempOrder){
			tempOrder=false;
			inCommand=true;
		}
		if(!inCommand){
			inCommand=true;
			commandPos1=myPlane->owner->pos;
		}
		float3 pos(c.params[0],c.params[1],c.params[2]);
		commandPos2=pos;
		myPlane->goalPos=pos;
		if(owner->unitDef->canAttack && !(c.options&CONTROL_KEY)){
			if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){
				if(myPlane->isFighter){
					float testRad=500*owner->moveState;
					CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*20,testRad,owner->allyteam);
					if(enemy && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){
						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 || owner->moveState==2) && owner->maxRange>0){
					float testRad=325*owner->moveState;
					CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*30,testRad,owner->allyteam);
					if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){
						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((curPos-pos).SqLength2D()<16000){
			FinishCommand();
		}
		break;}
	case CMD_PATROL:{
		assert(owner->unitDef->canPatrol);
		float3 curPos=owner->pos;
		if(c.params.size()<3){		//this shouldnt happen but anyway ...
			logOutput.Print("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:{
		assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
		if(tempOrder){
			tempOrder=false;
			inCommand=true;
		}
		if(c.params.size()<3){		//this shouldnt happen but anyway ...
			logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI", 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 {
			// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
			// rotated (only shortened) if we reach this because the previous return
			// fight command finished by the 'if((curPos-pos).SqLength2D()<(127*127)){'
			// condition, but is actually updated correctly if you click somewhere
			// outside the area close to the line (for a new command).
			commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, curPos);
			if ((curPos-commandPos1).SqLength2D()>(150*150)) {
				commandPos1 = curPos;
			}
		}
		goalPos=float3(c.params[0],c.params[1],c.params[2]);
		if(!inCommand){
			inCommand = true;
			commandPos2=goalPos;
		}

		// CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway...
		if (owner->unitDef->canAttack && owner->fireState == 2 && owner->moveState != 0 && owner->maxRange > 0) {
			float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos+owner->speed*10);
			float testRad=1000*owner->moveState;
			CUnit* enemy = helper->GetClosestEnemyAircraft(curPosOnLine,testRad,owner->allyteam);
			if(myPlane->isFighter
				&& enemy && !enemy->crashing
				&& (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|INTERNAL_ORDER;
				commandQue.push_front(nc);
				tempOrder=true;
				inCommand=false;
				if(lastPC1!=gs->frameNum){	//avoid infinite loops
					lastPC1=gs->frameNum;
					SlowUpdate();
				}
				return;
			} else {
				float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos+owner->speed*20);
				float testRad=500*owner->moveState;
				enemy=helper->GetClosestEnemyUnit(curPosOnLine,testRad,owner->allyteam);
				if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)  && !enemy->crashing
					&& (myPlane->isFighter || !enemy->unitDef->canfly))
				{
					Command nc;
					nc.id=CMD_ATTACK;
					nc.params.push_back(enemy->id);
					nc.options=c.options|INTERNAL_ORDER;
					PushOrUpdateReturnFight();
					commandQue.push_front(nc);
					tempOrder=true;
					inCommand=false;
					if(lastPC2!=gs->frameNum){	//avoid infinite loops
						lastPC2=gs->frameNum;
						SlowUpdate();
					}
					return;
				}
			}
		}
		myPlane->goalPos=goalPos;

		if((owner->pos-goalPos).SqLength2D()<(127*127) || (owner->pos+owner->speed*8-goalPos).SqLength2D()<(127*127)){
			FinishCommand();
		}
		return;}
	case CMD_ATTACK:
		assert(owner->unitDef->canAttack);
		targetAge++;
		if(tempOrder && owner->moveState==1){		//limit how far away we fly
			if(orderTarget && LinePointDist(commandPos1,commandPos2,orderTarget->pos) > 1500){
				owner->SetUserTarget(0);
				FinishCommand();
				break;
			}
		}
		if(tempOrder && myPlane->isFighter && orderTarget){
			if(owner->fireState==2 && owner->moveState!=0){
				CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*50,800,owner->allyteam);
				if(enemy && (!orderTarget->unitDef->canfly || (orderTarget->pos-owner->pos+owner->speed*50).Length()+100*gs->randFloat()*40-targetAge < (enemy->pos-owner->pos+owner->speed*50).Length())){
					c.params.clear();
					c.params.push_back(enemy->id);
					inCommand=false;
				}
			}
		}
		if(inCommand){
			if(targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)){
				FinishCommand();
				break;
			}
			if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
				owner->AttackUnit(0,true); 
				FinishCommand();
			  break;
			}
			if(orderTarget && orderTarget->unitDef->canfly && orderTarget->crashing){
				owner->SetUserTarget(0);
				FinishCommand();
				break;
			}
			if(orderTarget){
//				myPlane->goalPos=orderTarget->pos;
			} else {
//				float3 pos(c.params[0],c.params[1],c.params[2]);
//				myPlane->goalPos=pos;
			}
		} else {
			targetAge=0;
			if(c.params.size()==1){
				if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner){
					orderTarget=uh->units[int(c.params[0])];
					owner->AttackUnit(orderTarget,false);
					AddDeathDependence(orderTarget);
					inCommand=true;
				} else {
					FinishCommand();
					break;
				}
			} else {
				float3 pos(c.params[0],c.params[1],c.params[2]);
				owner->AttackGround(pos,false);
				inCommand=true;
			}
		}
		break;
	case CMD_AREA_ATTACK:{
		assert(owner->unitDef->canAttack);
		if(targetDied){
			targetDied=false;
			inCommand=false;
		}
		float3 pos(c.params[0],c.params[1],c.params[2]);
		float radius=c.params[3];
		if(inCommand){
			if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_LANDED)
				inCommand=false;
			if(orderTarget && orderTarget->pos.distance2D(pos)>radius){
				inCommand=false;
				DeleteDeathDependence(orderTarget);
				orderTarget=0;
			}
			if ((c.params.size() == 4) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
				owner->AttackUnit(0,true); 
				FinishCommand();
			}
		} else {
			if(myPlane->aircraftState!=CAirMoveType::AIRCRAFT_LANDED){
				inCommand=true;
				std::vector<int> eu;
				helper->GetEnemyUnits(pos,radius,owner->allyteam,eu);
				if(eu.empty()){
					float3 attackPos=pos+gs->randVector()*radius;
					attackPos.y=ground->GetHeight(attackPos.x,attackPos.z);
					owner->AttackGround(attackPos,false);
				} else {
					int num=(int) (gs->randFloat()*eu.size());
					orderTarget=uh->units[eu[num]];
					owner->AttackUnit(orderTarget,false);
					AddDeathDependence(orderTarget);
				}
			}
		}
		break;}
	case CMD_GUARD:
		assert(owner->unitDef->canGuard);
		if (int(c.params[0]) >= 0 && uh->units[int(c.params[0])] != NULL && UpdateTargetLostTimer(int(c.params[0]))) {
			CUnit* guarded=uh->units[int(c.params[0])];
			if(owner->unitDef->canAttack && guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum && owner->maxRange>0 && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
				Command nc;
				nc.id=CMD_ATTACK;
				nc.params.push_back(guarded->lastAttacker->id);
				nc.options=c.options;
				commandQue.push_front(nc);
				SlowUpdate();
				return;
			} else {
				Command c2;
				c2.id=CMD_MOVE;
				c2.options=c.options;
				c2.params.push_back(guarded->pos.x);
				c2.params.push_back(guarded->pos.y);
				c2.params.push_back(guarded->pos.z);
				c2.timeOut=gs->frameNum+60;
				commandQue.push_front(c2);
				return;
			}
		} else {
			FinishCommand();
		}
		break;
	default:
		CCommandAI::SlowUpdate();
		break;
	}
}