Exemple #1
0
void PathRecord::Initialise( MyTrack* pTrack, tCarElt* pCar )
{
//	GfOut( "pr::init\n" );
	const int	NSEG = pTrack->GetSize();

	m_pTrack = pTrack;
	m_pCar   = pCar;

	delete [] m_pData;
	m_pData = new Rec[NSEG];

	for( int i = 0; i < NSEG; i++ )
	{
		m_pData[i].pSeg = &pTrack->GetAt(i);
		m_pData[i].avgV = 20;
		m_pData[i].avgW = pCar->_trkPos.toMiddle;
	}

	double	pos = RtGetDistFromStart(pCar);
	m_lastSeg = pTrack->IndexFromPos(pos);
	m_lastPt.x = pCar->pub.DynGCg.pos.x;
	m_lastPt.y = pCar->pub.DynGCg.pos.y;
	m_lastSpd = hypot(pCar->_speed_X, pCar->_speed_Y);
//	GfOut( "pr::init done\n" );
}
Exemple #2
0
void PathRecord::Update()
{
	const int	NSEG = m_pTrack->GetSize();

	// work out which slice the car is in.
	int		last_s = m_lastSeg;
	double	dist = RtGetDistFromStart(m_pCar);
	int		cur_s = m_pTrack->IndexFromPos(dist);

	// work out current speed and position.
	double	spd = hypot(m_pCar->_speed_X, m_pCar->_speed_Y);
	Vec2d	pt(m_pCar->pub.DynGCg.pos.x, m_pCar->pub.DynGCg.pos.y);

	if( //!m_pCar->On_pit_lane &&
		last_s >= 0 && last_s != cur_s )
	{
		// we have crossed at least one line boundary, so we need to calculate
		//	the crossing point(s), and the speed(s) at those points.

		int		next_s = (last_s + 1) % NSEG;
		while( last_s != cur_s )
		{
			const Seg&	s0 = m_pTrack->GetAt(next_s);
			double		t, w;
			if( Utils::LineCrossesLine(m_lastPt, pt - m_lastPt,
										s0.pt.GetXY(), s0.norm.GetXY(), t, w) &&
				t >= 0.0 && t <= 1.0 )
			{
				double	v = m_lastSpd + (spd - m_lastSpd) * t;

				Rec&	rec = m_pData[next_s];
				const double	gamma = 0.8;
				rec.avgW	= rec.avgW * (1 - gamma) + w * gamma;
				rec.avgV	= rec.avgV * (1 - gamma) + v * gamma;
			}

			last_s = next_s;
			next_s = (next_s + 1) % NSEG;
		}
	}

	m_lastSeg = cur_s;
	m_lastPt  = pt;
	m_lastSpd = spd;
}
Exemple #3
0
double MyTrack::CalcPos( tCarElt* car, double offset ) const
{
  double pos = RtGetDistFromStart(car) + offset;
  return NormalisePos(pos);
}
Exemple #4
0
void
ReCarsManageCar(tCarElt *car, bool& bestLapChanged)
{
	char msg[64];
	int i;
	int xx;
	tTrackSeg *sseg;
	tdble wseg;
	static const float ctrlMsgColor[] = {0.0, 0.0, 1.0, 1.0};
	tSituation *s = ReInfo->s;
	
	tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);

	// Update top speeds.
	if (car->_speed_x > car->_topSpeed)
		car->_topSpeed = car->_speed_x;

	// (practice and qualification only).
	if (car->_speed_x > info->topSpd)
		info->topSpd = car->_speed_x;
	if (car->_speed_x < info->botSpd)
		info->botSpd = car->_speed_x;
	
	// Pitstop management.
	if (car->_pit) {

		// If the driver can ask for a pit, update control messages whether slot occupied or not.
		if (car->ctrl.raceCmd & RM_CMD_PIT_ASKED) {
			// Pit already occupied?
			if (car->_pit->pitCarIndex == TR_PIT_STATE_FREE)
				snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Can Pit");
			else
				snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Pit Occupied");
			car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
			memcpy(car->ctrl.msgColor, ctrlMsgColor, sizeof(car->ctrl.msgColor));
		}

		// If pitting, check if pitting delay over, and end up with pitting process if so.
		if (car->_state & RM_CAR_STATE_PIT) {
			car->ctrl.raceCmd &= ~RM_CMD_PIT_ASKED; // clear the flag.
			// Note: Due to asynchronous behaviour of the main updater and the situation updater,
			//       we have to wait for car->_scheduledEventTime being set to smthg > 0.
			if (car->_scheduledEventTime > 0.0) {
				if (car->_scheduledEventTime < s->currentTime) {
					car->_state &= ~RM_CAR_STATE_PIT;
					car->_pit->pitCarIndex = TR_PIT_STATE_FREE;
					snprintf(msg, sizeof(msg), "%s pit stop %.1f s", car->_name, info->totalPitTime);
					msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so.
					ReSituation::self().setRaceMessage(msg, 5);
					GfLogInfo("%s exiting pit (%.1f s elapsed).\n", car->_name, info->totalPitTime);
				} else {
					snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "In pits %.1f s",
							s->currentTime - info->startPitTime);
					car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
				}
			}
			
		// If the driver asks for a pit, check if the car is in the right conditions
		// (position, speed, ...) and start up pitting process if so.
		} else if ((car->ctrl.raceCmd & RM_CMD_PIT_ASKED) &&
				   car->_pit->pitCarIndex == TR_PIT_STATE_FREE &&	
				   (s->_maxDammage == 0 || car->_dammage <= s->_maxDammage)) {
			snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Pit request");
			car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
 
			tdble lgFromStart = car->_trkPos.seg->lgfromstart;
			
			switch (car->_trkPos.seg->type) {
				case TR_STR:
					lgFromStart += car->_trkPos.toStart;
					break;
				default:
					lgFromStart += car->_trkPos.toStart * car->_trkPos.seg->radius;
					break;
			}
		
			if ((lgFromStart > car->_pit->lmin) && (lgFromStart < car->_pit->lmax)) {
				int side;
				tdble toBorder;
				if (ReInfo->track->pits.side == TR_RGT) {
					side = TR_SIDE_RGT;
					toBorder = car->_trkPos.toRight;
				} else {
					side = TR_SIDE_LFT;
					toBorder = car->_trkPos.toLeft;
				}
				
				sseg = car->_trkPos.seg->side[side];
				wseg = RtTrackGetWidth(sseg, car->_trkPos.toStart);
				if (sseg->side[side]) {
					sseg = sseg->side[side];
					wseg += RtTrackGetWidth(sseg, car->_trkPos.toStart);
				}
				if (((toBorder + wseg) < (ReInfo->track->pits.width - car->_dimension_y / 2.0)) &&
					(fabs(car->_speed_x) < 1.0) && (fabs(car->_speed_y) < 1.0))
				{
					// All conditions fullfilled => enter pitting process
					car->_state |= RM_CAR_STATE_PIT;
					car->_scheduledEventTime = 0.0; // Pit will really start when set to smthg > 0.
					car->_nbPitStops++;
					for (i = 0; i < car->_pit->freeCarIndex; i++) {
						if (car->_pit->car[i] == car) {
							car->_pit->pitCarIndex = i;
							break;
						}
					}
					info->startPitTime = s->currentTime;
					snprintf(msg, sizeof(msg), "%s in pits", car->_name);
					msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so.
					ReSituation::self().setRaceMessage(msg, 5);
					GfLogInfo("%s entering in pit slot.\n", car->_name);
					if (car->robot->rbPitCmd(car->robot->index, car, s) == ROB_PIT_MENU) {
						// the pit cmd is modified by menu.
						reCarsSchedulePitMenu(car);
					} else {
						ReCarsUpdateCarPitTime(car);
					}
				}
				else
				{   // The cars speed or offset is out of accepted range
					// Show the user/developer/robot the reason of the issue
  				    tTeamDriver* TeamDriver = RtTeamDriverByCar(car);
					if (TeamDriver)
					{
					  TeamDriver->StillToGo  = 0.0;
					  TeamDriver->MoreOffset = 0.0;
					  TeamDriver->TooFastBy  = 0.0;
					}

					float Offset = (float) ((toBorder + wseg) - (ReInfo->track->pits.width - car->_dimension_y / 2.0));
  				    if (Offset >= 0.0)
					{
						// The car's position across the track is out of accepted range 
						snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Offset: %.02f",Offset);
						car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
						if (TeamDriver)
						  TeamDriver->MoreOffset = Offset;
					}

					float TooFastBy = MAX(fabs(car->_speed_x),fabs(car->_speed_y));
  				    if (TooFastBy >= 1.0)
					{
						// The car's speed is out of accepted range 
						snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Speed: %.02f",TooFastBy);
						car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
						if (TeamDriver)
						  TeamDriver->TooFastBy = TooFastBy;
					}
				}
			}
			else
			{	// The car's position along the track is out of accepted range
				// Show the user/developer/robot the reason of the issue
				tTeamDriver* TeamDriver = RtTeamDriverByCar(car);
				if (TeamDriver)
				{
				  TeamDriver->StillToGo  = 0.0;
				  TeamDriver->MoreOffset = 0.0;
				  TeamDriver->TooFastBy  = 0.0;
				}

				if (car->_pit->lmin > lgFromStart)
				{
				  float StillToGo = car->_pit->lmin - lgFromStart;
				  snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Still to go: %0.2f m" ,StillToGo);
				  car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
				  if (TeamDriver)
				    TeamDriver->StillToGo = StillToGo;
				}
				else if (car->_pit->lmax < lgFromStart)
				{
  				  float StillToGo = lgFromStart - car->_pit->lmax;
				  snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Overrun: %0.2f m" ,StillToGo);
				  car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so.
				  if (TeamDriver)
				    TeamDriver->StillToGo = -StillToGo;
				}
			}
		}
	}

	/* Check if it is in a new sector */
	while (true)
	{
		if (car->_currentSector < ReInfo->track->numberOfSectors - 1 && car->_laps > 0 && info->lapFlag == 0)
		{
			/* Must pass at least one sector before the finish */
			if (RtGetDistFromStart(car) > ReInfo->track->sectors[car->_currentSector])
			{
				/* It is in a new sector : update split time */
				car->_curSplitTime[car->_currentSector] = car->_curLapTime;
				++car->_currentSector;
				continue;
			}
		}
		break;
	}
	
	/* Start Line Crossing */
	if (info->prevTrkPos.seg != car->_trkPos.seg) {
		
		if ((info->prevTrkPos.seg->raceInfo & TR_LAST)
			&& (car->_trkPos.seg->raceInfo & TR_START)) {
			
			if (info->lapFlag == 0) {

				// If the car has not yet finished the race :
				if (!(car->_state & RM_CAR_STATE_FINISH)) {

					// 1 more lap completed
					// (Note: lap with index 0 finishes when the car crosses the start line the 1st time,
					//        and is thus considered a real lap, whereas it is not).
					car->_laps++;

					/*if (NetGetNetwork())
						NetGetNetwork()->SendLapStatusPacket(car);*/

					car->_remainingLaps--;
					if (car->_pos == 1 && s->currentTime < s->_totTime
						&& s->_raceType == RM_TYPE_RACE)
					{
						/* First car passed finish time before the time ends: increase the number of laps for everyone */
						for (xx = 0; xx < s->_ncars; ++xx)
							++ReInfo->s->cars[xx]->_remainingLaps;
						++s->_totLaps;
					}
					
					car->_currentSector = 0;
					if (car->_laps > 1) {
						car->_lastLapTime = s->currentTime - info->sTime;
						if (car->_bestLapTime != 0) {
							car->_deltaBestLapTime = car->_lastLapTime - car->_bestLapTime;
						}
						if ((car->_lastLapTime < car->_bestLapTime) || (car->_bestLapTime == 0)) {
							car->_bestLapTime = car->_lastLapTime;
							memcpy(car->_bestSplitTime, car->_curSplitTime, sizeof(double)*(ReInfo->track->numberOfSectors - 1) );
							if (s->_raceType != RM_TYPE_RACE && s->_ncars > 1)
							{
								/* Best lap time is made better : update times behind leader */
								bestLapChanged = true;
								car->_timeBehindLeader = car->_bestLapTime - s->cars[0]->_bestLapTime;
								if (car->_pos > 1)
								{
									car->_timeBehindPrev = car->_bestLapTime - s->cars[car->_pos - 1]->_bestLapTime;
								}
								else
								{
									/* New best time for the leader : update the differences */
									for (xx = 1; xx < s->_ncars; ++xx)
									{
										if (s->cars[xx]->_bestLapTime > 0.0f)
											s->cars[xx]->_timeBehindLeader = s->cars[xx]->_bestLapTime - car->_bestLapTime;
									}
								}
								if (car->_pos + 1 < s->_ncars && s->cars[car->_pos+1]->_bestLapTime > 0.0f)
									car->_timeBeforeNext = s->cars[car->_pos + 1]->_bestLapTime - car->_bestLapTime;
								else
									car->_timeBeforeNext = 0;
							}
						}
					}
					if (car->_laps > 0) {
						car->_curTime += s->currentTime - info->sTime;
						
						if (car->_pos != 1 && s->_raceType == RM_TYPE_RACE) {
							car->_timeBehindLeader = car->_curTime - s->cars[0]->_curTime;
							car->_lapsBehindLeader = s->cars[0]->_laps - car->_laps;
							car->_timeBehindPrev = car->_curTime - s->cars[car->_pos - 2]->_curTime;
							s->cars[car->_pos - 2]->_timeBeforeNext = car->_timeBehindPrev;
						} else if (s->_raceType == RM_TYPE_RACE) {
							car->_timeBehindLeader = 0;
							car->_lapsBehindLeader = 0;
							car->_timeBehindPrev = 0;
						}
						
						info->sTime = (tdble)s->currentTime;

						if (ReInfo->s->_raceType == RM_TYPE_PRACTICE && 
								(car->_laps > 1 || s->_totLaps == 0))
							ReSavePracticeLap(car);
					}

					if (ReInfo->_displayMode == RM_DISP_MODE_NONE)
					{
						switch(s->_raceType)
						{
							case RM_TYPE_PRACTICE:
								ReUpdatePracticeCurRes(car);
								break;
							case RM_TYPE_QUALIF:
								ReUpdateQualifCurRes(car);
								break;
							case RM_TYPE_RACE:
								ReUpdateRaceCurRes();
								break;
							default:
								break;
						}
					}
	
					info->topSpd = car->_speed_x;
					info->botSpd = car->_speed_x;
					if ((car->_remainingLaps < 0 && s->currentTime > s->_totTime) || (s->_raceState == RM_RACE_FINISHING)) {
						car->_state |= RM_CAR_STATE_FINISH;
						s->_raceState = RM_RACE_FINISHING;
						if (ReInfo->s->_raceType == RM_TYPE_RACE) {
							if (car->_pos == 1) {
								snprintf(msg, sizeof(msg), "Winner %s", car->_name);
								msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so.
								ReSituation::self().setRaceMessage(msg, 10, /*big=*/true);
								if (NetGetServer())
								{
									NetGetServer()->SetFinishTime(s->currentTime+FINISHDELAY);
								}
							} else {
								const char *numSuffix = "th";
								if (abs(12 - car->_pos) > 1) { /* leave suffix as 'th' for 11 to 13 */
									switch (car->_pos % 10) {
										case 1:
											numSuffix = "st";
											break;
										case 2:
											numSuffix = "nd";
											break;
										case 3:
											numSuffix = "rd";
											break;
										default:
											break;
									}
								}
								snprintf(msg, sizeof(msg), "%s finished %d%s", car->_name, car->_pos, numSuffix);
								msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so.
								ReSituation::self().setRaceMessage(msg, 5);
							}
						}
					}
					
					// Notify the UI when a lap is completed (by the leader)
					// and race results have been updated.
					if (car->_pos == 1)
						ReUI().onLapCompleted(car->_laps - 1);

				} else {
					// Prevent infinite looping of cars around track,
					// allowing one lap after finish for the first car, but no more
					for (i = 0; i < s->_ncars; i++) {
						s->cars[i]->_state |= RM_CAR_STATE_FINISH;
					}
					return;
				}

			} else {
				info->lapFlag--;
			}
		}
		if ((info->prevTrkPos.seg->raceInfo & TR_START)
			&& (car->_trkPos.seg->raceInfo & TR_LAST)) {
			/* going backward through the start line */
			info->lapFlag++;
		}
	} // Start Line Crossing


	// Apply race rules (penalties if enabled).
	reCarsApplyRaceRules(car);

	// Update misc car info.
	info->prevTrkPos = car->_trkPos;
	car->_curLapTime = s->currentTime - info->sTime;
	car->_distFromStartLine = car->_trkPos.seg->lgfromstart +
		(car->_trkPos.seg->type == TR_STR ? car->_trkPos.toStart : car->_trkPos.toStart * car->_trkPos.seg->radius);
	car->_distRaced = (car->_laps - 1) * ReInfo->track->length + car->_distFromStartLine;
}
Exemple #5
0
void PathRecord::GetPrediction( double& w, double& v ) const
{
	double	pos = RtGetDistFromStart(m_pCar);
	GetPredictionForPos( pos, w, v );
}
Exemple #6
0
//==========================================================================*
// Calc cars position from offset
//--------------------------------------------------------------------------*
double TTrackDescription::CalcPos(tCarElt* Car, double Offset) const
{
  double Pos = RtGetDistFromStart(Car) + Offset;
  return NormalizePos(Pos);                      // Normalize to >= 0.0
}
//==========================================================================*
// State (Sequential logic system)
//--------------------------------------------------------------------------*
void TSimpleStrategy::CheckPitState(float PitScaleBrake)
{
  if (oPit == NULL)                              // No Pit no service 
    return;
  if (!oPit->HasPits())
    return;

  double TrackPos = RtGetDistFromStart(oCar);    // Distance to pit

  switch(oState)                                 // Check state
  {
	case PIT_NONE:
      // We are somewhere on the track, nothing has happend yet
	  if ((!oPit->oPitLane[0].InPitSection(TrackPos)) && oGoToPit)
	  { // if we are not parallel to the pits and get the flag,
		// let's stop in the pits.
		oState = PIT_BEFORE;
	  }
	  break;

	case PIT_BEFORE:
      // We are somewhere on the track and got the flag to go to pit
	  if (oFuelChecked && oGoToPit)
	  { // If we reache pit entry and flag is still set
	    // switch to the pitlane
		oState = PIT_PREPARE;
	  }
	  break;

	case PIT_PREPARE:
      // We are near the pit entry on the track and got the flag to go to pit
	  if (oPit->oPitLane[0].InPitSection(TrackPos) && oGoToPit)
	  { // If we reache pit entry and flag is still set
	    // switch to the pitlane
		oState = PIT_ENTER;
	  }
	  break;

	case PIT_ENTER:
      // We are on the pitlane and drive to our pit
 	  if (!oPit->oPitLane[0].CanStop(TrackPos))
	  { // We have to wait, till we reached the point to stop
	    if (oDriver->CurrSpeed() < 3)
		{
	      CarAccelCmd =                          // a little throttle
			  MAX(0.05f,CarAccelCmd);
	      CarBrakeCmd = 0.0;                     // Start braking
		  LogSimplix.debug("#PIT_ENTER: Wait %g (%g)\n",TrackPos,oDriver->CurrSpeed());
		}
		else
		  LogSimplix.debug("#PIT_ENTER: Wait %g\n",TrackPos);
		break;
	  }

	  // We reached the poit to stopp
	  oState = PIT_ASKED;
  	  LogSimplix.debug("#PIT_ENTER: %g\n",TrackPos);

 	  // falls through...

	case PIT_ASKED:
	  // We are still going to the pit
	  if (oPit->oPitLane[0].CanStop(TrackPos))
	  { // If we can stop a this position we start pit procedure
  	    LogSimplix.debug("#PIT_ASKED: CanStop %g (%g)\n",TrackPos,oDriver->CurrSpeed());
		oDriver->oStanding = true;               // For motion survey!
        oPitTicker = 0;                          // Start service timer
	    CarAccelCmd = 0;                         // release throttle
	    CarBrakeCmd = 1.0;                       // Start braking
	    CarRaceCmd = RM_CMD_PIT_ASKED;           // Tell TORCS to service us! To test oPitTicker comment out
	    oState = PIT_SERVICE;                    
	  }
	  else
	  { // We can't stop here (to early or to late)
	    if (oPit->oPitLane[0].Overrun(TrackPos))
		{ // if to late
			LogSimplix.debug("#Overrun 1: %g\n",TrackPos);
		  PitRelease();
	      oState = PIT_EXIT_WAIT;
	      // pit stop finished, need to exit pits now.
		}
		else
		{
		  LogSimplix.debug("#ToShort 1: %g\n",TrackPos);
	      if (oDriver->CurrSpeed() < 3)
		  {
	        CarAccelCmd =                        // a little throttle
			  MAX(0.05f,CarAccelCmd);
	        CarBrakeCmd = 0.0;                   // Start braking
		  }
		}
	  }
	  break;

	case PIT_SERVICE:
      // Wait to reach standstill to get service from TORCS
	  oDriver->oStanding = true;                 // Keep motion survey quiet
	  oPitTicker++;                              // Check time to start service
	  if (oPitTicker > 10)                       // Check Timer
	  { // If we have to wait
		LogSimplix.debug("#oPitTicker: %d\n",oPitTicker);
		tTeamDriver* TeamDriver = RtTeamDriverByCar(oCar); 
		short int Major = RtTeamManagerGetMajorVersion();
		short int Minor = RtTeamManagerGetMinorVersion();
		if ((TeamDriver)
		  && ((Major > NEEDED_MAJOR_VERSION) 
		    || ((Major = NEEDED_MAJOR_VERSION) && (Minor >= NEEDED_MINOR_VERSION))))
		{
			LogSimplix.debug("#Pitting issues %s\n",oDriver->GetBotName());
			LogSimplix.debug("#StillToGo : %.2f m\n",TeamDriver->StillToGo);
			LogSimplix.debug("#MoreOffset: %.2f m\n",TeamDriver->MoreOffset);
			LogSimplix.debug("#TooFastBy : %.2f m/s\n",TeamDriver->TooFastBy);

			// Learn from the response
			if (fabs(TeamDriver->StillToGo) > 0.0)
			{
	          //CarSteerCmd = 0.0;                 // Straight on
			  if (fabs(CarSpeedLong) < 1.0)
			  {
	            CarAccelCmd =                    // a little throttle
			      MAX(0.005f,CarAccelCmd);
	            CarBrakeCmd = 0.0;                 // No braking
  			    LogSimplix.debug("#Accel     : %.2f\n",CarAccelCmd);
			  }
			  else
			  {
	            CarBrakeCmd = 0.1f;              // Braking
  			    LogSimplix.debug("#Brake     : %.2f\n",CarBrakeCmd);
			  }
	          CarClutchCmd = 0.5;                // Press clutch
			  if (TeamDriver->StillToGo > 0)
	            CarGearCmd = 1;                  // First gear
			  else
	            CarGearCmd = -1;                 // reverse gear
			}
			else
			{
// 			    LogSimplix.debug("#Stopped\n");
	            CarAccelCmd = 0.0;               // Stop throttle
	            CarBrakeCmd = 1.0;               // Lock brake
	            CarClutchCmd = 0.0;              // Release clutch
	            CarGearCmd = 1;                  // First gear
			}
		}

  	    if (oPitTicker > 300)                    // Check Timer
		{ // If we have to wait too long
	      PitRelease();                          // Something went wrong, we have 
	      oState = PIT_EXIT_WAIT;                // to leave and release pit for teammate
		}
	  }
	  else if (oPit->oPitLane[0].Overrun(TrackPos))
	  { // If we couldn't stop in place
		LogSimplix.debug("#Overrun 2: %g\n",TrackPos);
	    PitRelease();                            // We have to release the pit
	    oState = PIT_EXIT_WAIT;                  // for teammate
	  }
	  else
	  { // There is nothing that hampers TORCS to service us
  	    LogSimplix.debug("#PIT_SERVICE: %g (%g)\n",TrackPos,oDriver->CurrSpeed());
		CarLightCmd = 0;                         // No lights on
        CarAccelCmd = 0;                         // No throttle
	    CarBrakeCmd = 1.0;                       // Still braking
	    CarRaceCmd = RM_CMD_PIT_ASKED;           // Tell TORCS to service us! To test oPitTicker comment out
        // oState is set to next state in PitRepair()!
		// If TORCS doesn't service us, no call to PitRepair() is done!
		// We run into timeout! (oPitTicker)
		oPitStartTicker = 600;
	  }
	  break;

	case PIT_EXIT_WAIT:
      // We are still in the box
	  oDriver->oStanding = true;                 // Keep motion survey quiet
	  if ((oMinTimeSlot < 7)                     // If start slot to short
		|| ((oMinDistBack > -7)                  // or cars aside
		&& (oMinDistBack < 5)))                  // we have to wait
	  {
        oPitStartTicker--;
        if (oPitStartTicker < 0)
		{
  		  LogSimplix.debug("#PIT_EXIT: mts%g (mdb%gm)\n",oMinTimeSlot,oMinDistBack);
	      oState = PIT_EXIT;
		}
		CarLightCmd = RM_LIGHT_HEAD2;            // Only small lights on           
		CarAccelCmd = 0.0;               
	    CarBrakeCmd = 1.0;               
	  }
	  else
	  {
		CarLightCmd = RM_LIGHT_HEAD1;             // Only big lights on           
	    oState = PIT_EXIT;
	  }
	  break;

	case PIT_EXIT:
      // We are still in the box
	  oDriver->oStanding = true;                  // Keep motion survey quiet
      oGoToPit = false;                           // Service is finished, lets go
	  CarAccelCmd = 0.5;                          // Press throttle
	  CarBrakeCmd = 0;                            // Release brake
	  PitRelease();                               // Release pit for teammate
	  if (oDriver->CurrSpeed() > 5)
	    oState = PIT_GONE;                          
	  break;

	case PIT_GONE:
      // We are on our path back to the track
	  if (!oPit->oPitLane[0].InPitSection(TrackPos))
	  { // If we reached the end of the pitlane
        CarLightCmd = RM_LIGHT_HEAD1 |           // All lights on
			RM_LIGHT_HEAD2;                      
		oState = PIT_NONE;                       // Switch to default mode 
	  }
 	  break;
  }
}
Exemple #8
0
static void common_drive(int index, tCarElt* car, tSituation *s)
{
	tdble slip;
	tdble ax0;
	tdble brake;
	tdble clutch;
	tdble throttle;
	tdble leftSteer;
	tdble rightSteer;
	int scrw, scrh, dummy;
	int idx = index - 1;
	tControlCmd	*cmd = HCtx[idx]->CmdControl;
	const int BUFSIZE = 1024;
	char sstring[BUFSIZE];


	static int firstTime = 1;

	if (firstTime) {
		if (HCtx[idx]->MouseControlUsed) {
	    	GfuiMouseShow();
	    	GfctrlMouseInitCenter();
		}
		GfuiKeyEventRegisterCurrent(onKeyAction);
		GfuiSKeyEventRegisterCurrent(onSKeyAction);
		firstTime = 0;
    }


	HCtx[idx]->distToStart = RtGetDistFromStart(car);

	HCtx[idx]->Gear = (tdble)car->_gear;	/* telemetry */

	GfScrGetSize(&scrw, &scrh, &dummy, &dummy);

	memset(&(car->ctrl), 0, sizeof(tCarCtrl));

	car->_lightCmd = HCtx[idx]->lightCmd;

	if (car->_laps != HCtx[idx]->LastPitStopLap) {
		car->_raceCmd = RM_CMD_PIT_ASKED;
	}

	if (lastKeyUpdate != s->currentTime) {
		/* Update the controls only once for all the players */
		updateKeys();

		if (joyPresent) {
			GfctrlJoyGetCurrent(joyInfo);
		}

		GfctrlMouseGetCurrent(mouseInfo);
		lastKeyUpdate = s->currentTime;
	}

	if (((cmd[CMD_ABS].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ABS].val]) ||
		((cmd[CMD_ABS].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ABS].val].edgeUp) ||
		((cmd[CMD_ABS].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ABS].val].edgeUp))
	{
		HCtx[idx]->ParamAbs = 1 - HCtx[idx]->ParamAbs;
		snprintf(sstring, BUFSIZE, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index);
		GfParmSetStr(PrefHdle, sstring, HM_ATT_ABS, Yn[1 - HCtx[idx]->ParamAbs]);
		GfParmWriteFile(NULL, PrefHdle, "Human");
	}

	if (((cmd[CMD_ASR].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ASR].val]) ||
		((cmd[CMD_ASR].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ASR].val].edgeUp) ||
		((cmd[CMD_ASR].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ASR].val].edgeUp))
	{
		HCtx[idx]->ParamAsr = 1 - HCtx[idx]->ParamAsr;
		snprintf(sstring, BUFSIZE, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index);
		GfParmSetStr(PrefHdle, sstring, HM_ATT_ASR, Yn[1 - HCtx[idx]->ParamAsr]);
		GfParmWriteFile(NULL, PrefHdle, "Human");
	}

	const int bufsize = sizeof(car->_msgCmd[0]);
	snprintf(car->_msgCmd[0], bufsize, "%s %s", (HCtx[idx]->ParamAbs ? "ABS" : ""), (HCtx[idx]->ParamAsr ? "ASR" : ""));
	memcpy(car->_msgColorCmd, color, sizeof(car->_msgColorCmd));

	if (((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_JOY_BUT) && (joyInfo->levelup[cmd[CMD_SPDLIM].val] == 1)) ||
		((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_KEYBOARD) && (keyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN)) ||
		((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_SKEYBOARD) && (skeyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN)))
	{
		speedLimiter = 1;
		snprintf(car->_msgCmd[1], bufsize, "Speed Limiter On");
	} else {
		speedLimiter = 0;
		snprintf(car->_msgCmd[1], bufsize, "Speed Limiter Off");
	}


	if (((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_LIGHT1].val]) ||
		((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_LIGHT1].val].edgeUp) ||
		((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_LIGHT1].val].edgeUp))
	{
		if (HCtx[idx]->lightCmd & RM_LIGHT_HEAD1) {
			HCtx[idx]->lightCmd &= ~(RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2);
		} else {
			HCtx[idx]->lightCmd |= RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2;
		}
	}

	switch (cmd[CMD_LEFTSTEER].type) {
		case GFCTRL_TYPE_JOY_AXIS:
			ax0 = joyInfo->ax[cmd[CMD_LEFTSTEER].val] + cmd[CMD_LEFTSTEER].deadZone;
			if (ax0 > cmd[CMD_LEFTSTEER].max) {
				ax0 = cmd[CMD_LEFTSTEER].max;
			} else if (ax0 < cmd[CMD_LEFTSTEER].min) {
				ax0 = cmd[CMD_LEFTSTEER].min;
			}
			
			// normalize ax0 to -1..0
			ax0 = (ax0 - cmd[CMD_LEFTSTEER].max) / (cmd[CMD_LEFTSTEER].max - cmd[CMD_LEFTSTEER].min);
			leftSteer = -SIGN(ax0) * cmd[CMD_LEFTSTEER].pow * pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed);
			break;
		case GFCTRL_TYPE_MOUSE_AXIS:
			ax0 = mouseInfo->ax[cmd[CMD_LEFTSTEER].val] - cmd[CMD_LEFTSTEER].deadZone; //FIXME: correct?
			if (ax0 > cmd[CMD_LEFTSTEER].max) {
				ax0 = cmd[CMD_LEFTSTEER].max;
			} else if (ax0 < cmd[CMD_LEFTSTEER].min) {
				ax0 = cmd[CMD_LEFTSTEER].min;
			}
			ax0 = ax0 * cmd[CMD_LEFTSTEER].pow;
			leftSteer = pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed / 10.0);
			break;
		case GFCTRL_TYPE_KEYBOARD:
		case GFCTRL_TYPE_SKEYBOARD:
		case GFCTRL_TYPE_JOY_BUT:
			if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_KEYBOARD) {
				ax0 = keyInfo[cmd[CMD_LEFTSTEER].val].state;
			} else if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_SKEYBOARD) {
				ax0 = skeyInfo[cmd[CMD_LEFTSTEER].val].state;
			} else {
				ax0 = joyInfo->levelup[cmd[CMD_LEFTSTEER].val];
			}
			if (ax0 == 0) {
				HCtx[idx]->prevLeftSteer = leftSteer = 0;
			} else {
				ax0 = 2 * ax0 - 1;
				leftSteer = HCtx[idx]->prevLeftSteer + ax0 * cmd[CMD_LEFTSTEER].sens * s->deltaTime / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed / 10.0);
				if (leftSteer > 1.0) leftSteer = 1.0;
				if (leftSteer < 0.0) leftSteer = 0.0;
				HCtx[idx]->prevLeftSteer = leftSteer;
			}
			break;
		default:
			leftSteer = 0;
			break;
	}

	switch (cmd[CMD_RIGHTSTEER].type) {
		case GFCTRL_TYPE_JOY_AXIS:
			ax0 = joyInfo->ax[cmd[CMD_RIGHTSTEER].val] - cmd[CMD_RIGHTSTEER].deadZone;
			if (ax0 > cmd[CMD_RIGHTSTEER].max) {
				ax0 = cmd[CMD_RIGHTSTEER].max;
			} else if (ax0 < cmd[CMD_RIGHTSTEER].min) {
				ax0 = cmd[CMD_RIGHTSTEER].min;
			}
			
			// normalize ax to 0..1
			ax0 = (ax0 - cmd[CMD_RIGHTSTEER].min) / (cmd[CMD_RIGHTSTEER].max - cmd[CMD_RIGHTSTEER].min);
			rightSteer = -SIGN(ax0) * cmd[CMD_RIGHTSTEER].pow * pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed);
			break;
		case GFCTRL_TYPE_MOUSE_AXIS:
			ax0 = mouseInfo->ax[cmd[CMD_RIGHTSTEER].val] - cmd[CMD_RIGHTSTEER].deadZone;
			if (ax0 > cmd[CMD_RIGHTSTEER].max) {
				ax0 = cmd[CMD_RIGHTSTEER].max;
			} else if (ax0 < cmd[CMD_RIGHTSTEER].min) {
				ax0 = cmd[CMD_RIGHTSTEER].min;
			}
			ax0 = ax0 * cmd[CMD_RIGHTSTEER].pow;
			rightSteer = - pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed / 10.0);
			break;
		case GFCTRL_TYPE_KEYBOARD:
		case GFCTRL_TYPE_SKEYBOARD:
		case GFCTRL_TYPE_JOY_BUT:
			if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_KEYBOARD) {
				ax0 = keyInfo[cmd[CMD_RIGHTSTEER].val].state;
			} else  if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_SKEYBOARD) {
				ax0 = skeyInfo[cmd[CMD_RIGHTSTEER].val].state;
			} else {
				ax0 = joyInfo->levelup[cmd[CMD_RIGHTSTEER].val];
			}
			if (ax0 == 0) {
				HCtx[idx]->prevRightSteer = rightSteer = 0;
			} else {
				ax0 = 2 * ax0 - 1;
				rightSteer = HCtx[idx]->prevRightSteer - ax0 * cmd[CMD_RIGHTSTEER].sens * s->deltaTime/ (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed / 10.0);
				if (rightSteer > 0.0) rightSteer = 0.0;
				if (rightSteer < -1.0) rightSteer = -1.0;
				HCtx[idx]->prevRightSteer = rightSteer;
			}
			break;
		default:
			rightSteer = 0;
			break;
	}

	car->_steerCmd = leftSteer + rightSteer;


	switch (cmd[CMD_BRAKE].type) {
		case GFCTRL_TYPE_JOY_AXIS:
			brake = joyInfo->ax[cmd[CMD_BRAKE].val];
			if (brake > cmd[CMD_BRAKE].max) {
				brake = cmd[CMD_BRAKE].max;
			} else if (brake < cmd[CMD_BRAKE].min) {
				brake = cmd[CMD_BRAKE].min;
			}
			car->_brakeCmd = fabs(cmd[CMD_BRAKE].pow *
						pow(fabs((brake - cmd[CMD_BRAKE].minVal) /
							(cmd[CMD_BRAKE].max - cmd[CMD_BRAKE].min)),
						cmd[CMD_BRAKE].sens));
			break;
		case GFCTRL_TYPE_MOUSE_AXIS:
			ax0 = mouseInfo->ax[cmd[CMD_BRAKE].val] - cmd[CMD_BRAKE].deadZone;
			if (ax0 > cmd[CMD_BRAKE].max) {
				ax0 = cmd[CMD_BRAKE].max;
			} else if (ax0 < cmd[CMD_BRAKE].min) {
				ax0 = cmd[CMD_BRAKE].min;
			}
			ax0 = ax0 * cmd[CMD_BRAKE].pow;
			car->_brakeCmd =  pow(fabs(ax0), cmd[CMD_BRAKE].sens) / (1.0 + cmd[CMD_BRAKE].spdSens * car->_speed_x / 10.0);
			break;
		case GFCTRL_TYPE_JOY_BUT:
			car->_brakeCmd = joyInfo->levelup[cmd[CMD_BRAKE].val];
			break;
		case GFCTRL_TYPE_MOUSE_BUT:
			car->_brakeCmd = mouseInfo->button[cmd[CMD_BRAKE].val];
			break;
		case GFCTRL_TYPE_KEYBOARD:
			car->_brakeCmd = keyInfo[cmd[CMD_BRAKE].val].state;
			break;
		case GFCTRL_TYPE_SKEYBOARD:
			car->_brakeCmd = skeyInfo[cmd[CMD_BRAKE].val].state;
			break;
		default:
			car->_brakeCmd = 0;
			break;
	}

	switch (cmd[CMD_CLUTCH].type) {
		case GFCTRL_TYPE_JOY_AXIS:
			clutch = joyInfo->ax[cmd[CMD_CLUTCH].val];
			if (clutch > cmd[CMD_CLUTCH].max) {
				clutch = cmd[CMD_CLUTCH].max;
			} else if (clutch < cmd[CMD_CLUTCH].min) {
				clutch = cmd[CMD_CLUTCH].min;
			}
			car->_clutchCmd = fabs(cmd[CMD_CLUTCH].pow *
						pow(fabs((clutch - cmd[CMD_CLUTCH].minVal) /
							(cmd[CMD_CLUTCH].max - cmd[CMD_CLUTCH].min)),
						cmd[CMD_CLUTCH].sens));
			break;
		case GFCTRL_TYPE_MOUSE_AXIS:
			ax0 = mouseInfo->ax[cmd[CMD_CLUTCH].val] - cmd[CMD_CLUTCH].deadZone;
			if (ax0 > cmd[CMD_CLUTCH].max) {
				ax0 = cmd[CMD_CLUTCH].max;
			} else if (ax0 < cmd[CMD_CLUTCH].min) {
				ax0 = cmd[CMD_CLUTCH].min;
			}
			ax0 = ax0 * cmd[CMD_CLUTCH].pow;
			car->_clutchCmd =  pow(fabs(ax0), cmd[CMD_CLUTCH].sens) / (1.0 + cmd[CMD_CLUTCH].spdSens * car->_speed_x / 10.0);
			break;
		case GFCTRL_TYPE_JOY_BUT:
			car->_clutchCmd = joyInfo->levelup[cmd[CMD_CLUTCH].val];
			break;
		case GFCTRL_TYPE_MOUSE_BUT:
			car->_clutchCmd = mouseInfo->button[cmd[CMD_CLUTCH].val];
			break;
		case GFCTRL_TYPE_KEYBOARD:
			car->_clutchCmd = keyInfo[cmd[CMD_CLUTCH].val].state;
			break;
		case GFCTRL_TYPE_SKEYBOARD:
			car->_clutchCmd = skeyInfo[cmd[CMD_CLUTCH].val].state;
			break;
		default:
			car->_clutchCmd = 0;
			break;
	}

	// if player's used the clutch manually then we dispense with autoClutch
	if (car->_clutchCmd != 0.0f)
		HCtx[idx]->autoClutch = 0;

	switch (cmd[CMD_THROTTLE].type) {
		case GFCTRL_TYPE_JOY_AXIS:
			throttle = joyInfo->ax[cmd[CMD_THROTTLE].val];
			if (throttle > cmd[CMD_THROTTLE].max) {
				throttle = cmd[CMD_THROTTLE].max;
			} else if (throttle < cmd[CMD_THROTTLE].min) {
				throttle = cmd[CMD_THROTTLE].min;
			}
			car->_accelCmd = fabs(cmd[CMD_THROTTLE].pow *
						pow(fabs((throttle - cmd[CMD_THROTTLE].minVal) /
								(cmd[CMD_THROTTLE].max - cmd[CMD_THROTTLE].min)),
							cmd[CMD_THROTTLE].sens));
			break;
		case GFCTRL_TYPE_MOUSE_AXIS:
			ax0 = mouseInfo->ax[cmd[CMD_THROTTLE].val] - cmd[CMD_THROTTLE].deadZone;
			if (ax0 > cmd[CMD_THROTTLE].max) {
				ax0 = cmd[CMD_THROTTLE].max;
			} else if (ax0 < cmd[CMD_THROTTLE].min) {
				ax0 = cmd[CMD_THROTTLE].min;
			}
			ax0 = ax0 * cmd[CMD_THROTTLE].pow;
			car->_accelCmd =  pow(fabs(ax0), cmd[CMD_THROTTLE].sens) / (1.0 + cmd[CMD_THROTTLE].spdSens * car->_speed_x / 10.0);
			if (isnan (car->_accelCmd)) {
				car->_accelCmd = 0;
			}
			/* printf("  axO:%f  accelCmd:%f\n", ax0, car->_accelCmd); */
			break;
		case GFCTRL_TYPE_JOY_BUT:
			car->_accelCmd = joyInfo->levelup[cmd[CMD_THROTTLE].val];
			break;
		case GFCTRL_TYPE_MOUSE_BUT:
			car->_accelCmd = mouseInfo->button[cmd[CMD_THROTTLE].val];
			break;
		case GFCTRL_TYPE_KEYBOARD:
			car->_accelCmd = keyInfo[cmd[CMD_THROTTLE].val].state;
			break;
		case GFCTRL_TYPE_SKEYBOARD:
			car->_accelCmd = skeyInfo[cmd[CMD_THROTTLE].val].state;
			break;
		default:
			car->_accelCmd = 0;
			break;
	}

	if (s->currentTime > 1.0) {
		// thanks Christos for the following: gradual accel/brake changes for on/off controls.
		const tdble inc_rate = 0.2f;
		
		if (cmd[CMD_BRAKE].type == GFCTRL_TYPE_JOY_BUT ||
		    cmd[CMD_BRAKE].type == GFCTRL_TYPE_MOUSE_BUT ||
		    cmd[CMD_BRAKE].type == GFCTRL_TYPE_KEYBOARD ||
		    cmd[CMD_BRAKE].type == GFCTRL_TYPE_SKEYBOARD)
		{
			tdble d_brake = car->_brakeCmd - HCtx[idx]->pbrake;
			if (fabs(d_brake) > inc_rate && car->_brakeCmd > HCtx[idx]->pbrake) {
				car->_brakeCmd = MIN(car->_brakeCmd, HCtx[idx]->pbrake + inc_rate*d_brake/fabs(d_brake));
			}
			HCtx[idx]->pbrake = car->_brakeCmd;
		}

		if (cmd[CMD_THROTTLE].type == GFCTRL_TYPE_JOY_BUT ||
			cmd[CMD_THROTTLE].type == GFCTRL_TYPE_MOUSE_BUT ||
			cmd[CMD_THROTTLE].type == GFCTRL_TYPE_KEYBOARD ||
			cmd[CMD_THROTTLE].type == GFCTRL_TYPE_SKEYBOARD)
		{
			tdble d_accel = car->_accelCmd - HCtx[idx]->paccel;
			if (fabs(d_accel) > inc_rate && car->_accelCmd > HCtx[idx]->paccel) {
				car->_accelCmd = MIN(car->_accelCmd, HCtx[idx]->paccel + inc_rate*d_accel/fabs(d_accel));
			}
			HCtx[idx]->paccel = car->_accelCmd;
		}
	}

	if (HCtx[idx]->AutoReverseEngaged) {
		/* swap brake and throttle */
		brake = car->_brakeCmd;
		car->_brakeCmd = car->_accelCmd;
		car->_accelCmd = brake;
	}

	if (HCtx[idx]->ParamAbs) 
	{
		if (fabs(car->_speed_x) > 10.0)
		{
			int i;

			tdble skidAng = atan2(car->_speed_Y, car->_speed_X) - car->_yaw;
			NORM_PI_PI(skidAng);

			if (car->_speed_x > 5 && fabs(skidAng) > 0.2)
				car->_brakeCmd = MIN(car->_brakeCmd, 0.10 + 0.70 * cos(skidAng));

			if (fabs(car->_steerCmd) > 0.1)
			{
				tdble decel = ((fabs(car->_steerCmd)-0.1) * (1.0 + fabs(car->_steerCmd)) * 0.6);
				car->_brakeCmd = MIN(car->_brakeCmd, MAX(0.35, 1.0 - decel));
			}

			const tdble abs_slip = 2.5;
			const tdble abs_range = 5.0;

			slip = 0;
			for (i = 0; i < 4; i++) {
				slip += car->_wheelSpinVel(i) * car->_wheelRadius(i);
			}
			slip = car->_speed_x - slip/4.0f;

			if (slip > abs_slip)
				car->_brakeCmd = car->_brakeCmd - MIN(car->_brakeCmd*0.8, (slip - abs_slip) / abs_range);
		}
	}


	if (HCtx[idx]->ParamAsr) 
	{
    	tdble trackangle = RtTrackSideTgAngleL(&(car->_trkPos));
		tdble angle = trackangle - car->_yaw;
		NORM_PI_PI(angle);

		tdble maxaccel = 0.0;
		if (car->_trkPos.seg->type == TR_STR)
			maxaccel = MIN(car->_accelCmd, 0.2);
		else if (car->_trkPos.seg->type == TR_LFT && angle < 0.0)
			maxaccel = MIN(car->_accelCmd, MIN(0.6, -angle));
		else if (car->_trkPos.seg->type == TR_RGT && angle > 0.0)
			maxaccel = MIN(car->_accelCmd, MIN(0.6, angle));

		tdble origaccel = car->_accelCmd;
		tdble skidAng = atan2(car->_speed_Y, car->_speed_X) - car->_yaw;
		NORM_PI_PI(skidAng);

		if (car->_speed_x > 5 && fabs(skidAng) > 0.2)
		{
			car->_accelCmd = MIN(car->_accelCmd, 0.15 + 0.70 * cos(skidAng));
			car->_accelCmd = MAX(car->_accelCmd, maxaccel);
		}

		if (fabs(car->_steerCmd) > 0.1)
		{
			tdble decel = ((fabs(car->_steerCmd)-0.1) * (1.0 + fabs(car->_steerCmd)) * 0.8);
			car->_accelCmd = MIN(car->_accelCmd, MAX(0.35, 1.0 - decel));
		}

		tdble drivespeed = 0.0;
		switch (HCtx[idx]->drivetrain)
		{
			case D4WD:
				drivespeed = ((car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
				              car->_wheelRadius(FRNT_LFT) +
				              (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
				              car->_wheelRadius(REAR_LFT)) / 4.0; 
				break;
			case DFWD:
				drivespeed = (car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
				              car->_wheelRadius(FRNT_LFT) / 2.0;
				break;
			default:
				drivespeed = (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
				              car->_wheelRadius(REAR_LFT) / 2.0;
				break;
		}

		tdble slip = drivespeed - fabs(car->_speed_x);
		if (slip > 2.0)
			car->_accelCmd = MIN(car->_accelCmd, origaccel - MIN(origaccel-0.1, ((slip - 2.0)/10.0)));
	}

	if (speedLimiter) {
		tdble Dv;
		if (Vtarget != 0) {
			Dv = Vtarget - car->_speed_x;
			if (Dv > 0.0) {
				car->_accelCmd = MIN(car->_accelCmd, fabs(Dv/6.0));
			} else {
				car->_brakeCmd = MAX(car->_brakeCmd, fabs(Dv/5.0));
				car->_accelCmd = 0;
			}
		}
	}


#ifndef WIN32
#ifdef TELEMETRY
	if ((car->_laps > 1) && (car->_laps < 5)) {
		if (HCtx[idx]->lap == 1) {
			RtTelemStartMonitoring("Player");
		}
		RtTelemUpdate(car->_curLapTime);
	}
	if (car->_laps == 5) {
		if (HCtx[idx]->lap == 4) {
			RtTelemShutdown();
		}
	}
#endif
#endif

	HCtx[idx]->lap = car->_laps;
}
//==========================================================================*
// Update
//
// ATTENTION oCar ist opponents car, so we can use our shortcuts!!!
//--------------------------------------------------------------------------*
void TOpponent::Update(
  const PCarElt MyCar,
  double MyDirX,
  double MyDirY,
  float &MinDistBack,
  double &MinTimeSlot)
{
  if((CarState & RM_CAR_STATE_NO_SIMU) &&        // omit cars out of race
    (CarState & RM_CAR_STATE_PIT) == 0 )         //   if not in pit
    return;

  oInfo.State.Speed = myhypot(CarSpeedX,CarSpeedY);// Speed of car

  // Track relative speed of opponents car
  TVec2d ToRight = oTrack->Normale(DistanceFromStartLine);
  oInfo.State.TrackVelLong = ToRight.x * CarSpeedY - ToRight.y * CarSpeedX;
  oInfo.State.TrackVelLat = ToRight.x * CarSpeedX + ToRight.y * CarSpeedY;

  // Track relative yaw of other car.
  oInfo.State.TrackYaw = CarYaw - TUtils::VecAngle(ToRight) - PI / 2;
  DOUBLE_NORM_PI_PI(oInfo.State.TrackYaw);

  // Average velocity of other car.
  oInfo.State.AvgVelLong = oInfo.State.AvgVelLong * AVG_KEEP + CarPubGlobVelX * AVG_CHANGE;
  oInfo.State.AvgVelLat = oInfo.State.AvgVelLat * AVG_KEEP + CarPubGlobVelY * AVG_CHANGE;
  oInfo.State.CarAvgVelLong = MyDirX * oInfo.State.AvgVelLong + MyDirY * oInfo.State.AvgVelLat;
  //oInfo.State.CarAvgVelLat = MyDirY * oInfo.State.AvgVelLong - MyDirX * oInfo.State.AvgVelLat;

  // Average acceleration of other car.
  oInfo.State.AvgAccLong = oInfo.State.AvgAccLong * AVG_KEEP + CarPubGlobAccX * AVG_CHANGE;
  oInfo.State.AvgAccLat = oInfo.State.AvgAccLat * AVG_KEEP + CarPubGlobAccY * AVG_CHANGE;
  oInfo.State.CarAvgAccLong = MyDirX * oInfo.State.AvgAccLong + MyDirY * oInfo.State.AvgAccLat;
  oInfo.State.CarAvgAccLat = MyDirY * oInfo.State.AvgAccLong - MyDirX * oInfo.State.AvgAccLat;

  // Offset from track center line.
  oInfo.State.Offset = -CarToMiddle;

  if(oCar == MyCar)
    return;

  // Car-Car relative calculations ...

  // calc other cars position, velocity relative to my car (global coords).
  double DistX = CarPubGlobPosX - MyCar->pub.DynGCg.pos.x;
  double DistY = CarPubGlobPosY - MyCar->pub.DynGCg.pos.y;
  double DiffVelX = CarSpeedX - MyCar->_speed_X;
  double DiffVelY = CarSpeedY - MyCar->_speed_Y;

  // work out relative position, velocity in local coords (coords of my car).
  oInfo.State.CarDistLong = MyDirX * DistX + MyDirY * DistY;
  oInfo.State.CarDistLat = MyDirY * DistX - MyDirX * DistY;
  oInfo.State.CarDiffVelLong = MyDirX * DiffVelX + MyDirY * DiffVelY;
  oInfo.State.CarDiffVelLat = MyDirY * DiffVelX - MyDirX * DiffVelY;

  oInfo.State.MinDistLong = (MyCar->_dimension_x + CarLength) / 2;
  oInfo.State.MinDistLat = (MyCar->_dimension_y + CarWidth) / 2;

  double MyVelAng = atan2(MyCar->_speed_Y, MyCar->_speed_X);
  double MyYaw = MyCar->_yaw - MyVelAng;
  DOUBLE_NORM_PI_PI(MyYaw);

  double OppYaw = CarYaw - MyVelAng;
  DOUBLE_NORM_PI_PI(OppYaw);

  // Additional distance needed while yawing of both cars
  double ExtSide = (oInfo.State.MinDistLong - oInfo.State.MinDistLat) *
    (fabs(sin(MyYaw)) + fabs(sin(OppYaw)));

  oInfo.State.MinDistLat += ExtSide + SIDE_MARGIN;
  oInfo.State.MinDistLong += TDriver::LengthMargin;

  // Distance of car from start of track.
  double MyPos = RtGetDistFromStart((tCarElt*)MyCar);
  double HisPos = RtGetDistFromStart((tCarElt*)oCar);
  double RelPos = HisPos - MyPos;
  double TrackLen = oTrack->Length();
  if (RelPos > TrackLen / 2)
    RelPos -= TrackLen;
  else if (RelPos < -TrackLen / 2)
    RelPos += TrackLen;

  oInfo.State.RelPos = RelPos;

  if (fabs(CarToMiddle) - oTrack->Width() > 1.0) // If opponent is outside of track
  {                                              // we assume it is in the pitlane

    if ((RelPos > MinDistBack)                   // Opponent is near
	  && (RelPos < 5))                           // and not in front
    {
      MinDistBack = (tdble) RelPos;
    }

    double T = -RelPos/oInfo.State.TrackVelLong; // Time to start out of pit
    if ((T > 0)                                  // Opponent is back or aside
	  && (T < 200))                              // and arrives within 20 sec
    {
      if (MinTimeSlot > T)
	    MinTimeSlot = T;
    }
  }
}
Exemple #10
0
void Opponent::UpdateSit(const CarElt* myCar, const TeamInfo* pTeamInfo, double myDirX, double myDirY)
{
	CarElt*	oCar = m_path.GetCar();

	if( (oCar->_state & RM_CAR_STATE_NO_SIMU) )
		return;

	// word out speed of car.
	m_info.sit.spd = hypot(oCar->_speed_X, oCar->_speed_Y);

	// work out track relative speed of other car.
	Vec2d norm = m_path.GetTrack()->CalcNormal(oCar->_distFromStartLine);
	m_info.sit.tVX = norm.x * oCar->_speed_Y - norm.y * oCar->_speed_X;
	m_info.sit.tVY = norm.x * oCar->_speed_X + norm.y * oCar->_speed_Y;

	// work out track relative yaw of other car.
	m_info.sit.tYaw = oCar->_yaw - Utils::VecAngle(norm) - PI * 0.5;
	NORM_PI_PI(m_info.sit.tYaw);

	// work out avg velocity of other car.
	m_info.sit.agVX = m_info.sit.agVX * 0.75 + oCar->pub.DynGCg.vel.x * 0.25;
	m_info.sit.agVY = m_info.sit.agVY * 0.75 + oCar->pub.DynGCg.vel.y * 0.25;
	m_info.sit.ragVX = myDirX * m_info.sit.agVX + myDirY * m_info.sit.agVY;
	m_info.sit.ragVY = myDirY * m_info.sit.agVX - myDirX * m_info.sit.agVY;

	// work out avg acceleration of other car.
	m_info.sit.agAX = m_info.sit.agAX * 0.75 + oCar->pub.DynGCg.acc.x * 0.25;
	m_info.sit.agAY = m_info.sit.agAY * 0.75 + oCar->pub.DynGCg.acc.y * 0.25;
	m_info.sit.ragAX = myDirX * m_info.sit.agAX + myDirY * m_info.sit.agAY;
	m_info.sit.ragAY = myDirY * m_info.sit.agAX - myDirX * m_info.sit.agAY;

	// work out lateral accelerations.
	double	rAX = myDirX * oCar->pub.DynGCg.acc.x + myDirY * oCar->pub.DynGCg.acc.y;
	double	rAY = myDirY * oCar->pub.DynGCg.acc.x - myDirX * oCar->pub.DynGCg.acc.y;
	m_info.sit.arAX = m_info.sit.arAX * 0.75 + rAX * 0.25;
	m_info.sit.arAY = m_info.sit.arAY * 0.75 + rAY * 0.25;

	// offset from track centre line.
	m_info.sit.offs = -oCar->_trkPos.toMiddle;

	// the rest of the calcs are car-car relative, and make no sense if both
	//	cars are the same.
	if( oCar == myCar )
		return;

	// calc other cars position, velocity relative to my car (global coords).
	double	dPX = oCar->pub.DynGCg.pos.x - myCar->pub.DynGCg.pos.x;
	double	dPY = oCar->pub.DynGCg.pos.y - myCar->pub.DynGCg.pos.y;
	double	dVX  = oCar->_speed_X - myCar->_speed_X;
	double	dVY  = oCar->_speed_Y - myCar->_speed_Y;

	// work out relative position, velocity in local coords (coords of my car).
	double	rdPX = myDirX * dPX + myDirY * dPY;
	double	rdPY = myDirY * dPX - myDirX * dPY;
	double	rdVX = myDirX * dVX + myDirY * dVY;
	double	rdVY = myDirY * dVX - myDirX * dVY;

	m_info.sit.rdPX = rdPX;
	m_info.sit.rdPY = rdPY;
	m_info.sit.rdVX = rdVX;
	m_info.sit.rdVY = rdVY;

	m_info.sit.minDX = (myCar->_dimension_x + oCar->_dimension_x) / 2;
	m_info.sit.minDY = (myCar->_dimension_y + oCar->_dimension_y) / 2;

	double	myVelAng = atan2(myCar->_speed_Y, myCar->_speed_X);
	double	myYaw = myCar->_yaw - myVelAng;
	NORM_PI_PI(myYaw);
	double	oYaw = oCar->_yaw - myVelAng;
	NORM_PI_PI(oYaw);
	double	extSide = (m_info.sit.minDX - m_info.sit.minDY) *
				(fabs(sin(myYaw)) + fabs(sin(oYaw)));
//	m_info.sit.minDY += MX(0, MN((rdPX - m_info.sit.minDY) * 0.1, 4));
	m_info.sit.minDY += extSide + 1;//0.5;
	m_info.sit.minDX += 1.0;//pTeamInfo->IsTeamMate(myCar, oCar) ? 0.5 : 1.0;

//	if( fabs(extSide) > 0.2 )
//		GfOut( "****** angDiff %.3f extSide %.2f ******\n", angDiff, extSide );

	// work out positions of car from start of track.
	double	myPos = RtGetDistFromStart((tCarElt*)myCar);
	double	hisPos = RtGetDistFromStart((tCarElt*)oCar);
	double	relPos = hisPos - myPos;
	double	trackLen = m_path.GetTrack()->GetLength();
	if( relPos > trackLen / 2 )
		relPos -= trackLen;
	else if( relPos < -trackLen / 2 )
		relPos += trackLen;

	m_info.sit.relPos = relPos;
}