Beispiel #1
0
int
ReRaceEnd(void)
{
	int curDrvIdx;
	int nCars;
	void *params = ReInfo->params;
	void *results = ReInfo->results;
	const char *sessionName = ReInfo->_reRaceName;

	ReShutdownUpdaters();

	ReUI().onRaceFinishing();
	
	ReRaceCleanup();

	if (NetGetNetwork())
		NetGetNetwork()->RaceDone();

	// If we are at the end of a qualification or practice session for a competitor,
	// select the next competitor : it is his turn for the same session.
	// If no more competitor, this is the end of the session for all the competitors.
	bool bEndOfSession = true;
	if ((ReInfo->s->_raceType == RM_TYPE_QUALIF || ReInfo->s->_raceType == RM_TYPE_PRACTICE)
		&& ReInfo->s->_totTime < 0.0f)
	{
		// Up to the next competitor now, if not the last one.
		nCars = MIN(GfParmGetEltNb(params, RM_SECT_DRIVERS),
				(int)GfParmGetNum(params, sessionName, RM_ATTR_MAX_DRV, NULL, 100));
		ReCurrDriverNr++;
		if (ReStartingOrderIdx != NULL) {
			if (ReCurrDriverNr < nCars) {curDrvIdx = ReStartingOrderIdx[ReCurrDriverNr];}
			else {curDrvIdx = nCars + 1;}
		}
		else {
			curDrvIdx = 1;
		}
		if (ReCurrDriverNr < nCars) 
			bEndOfSession = false;
		else {
			ReCurrDriverNr = 0; // Was the last one : end of session !
			curDrvIdx = 1;
		}
		GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, (tdble)curDrvIdx);
	}

	// Calculate class points if we just finished a session.
	if (bEndOfSession)
	{
		ReCalculateClassPoints (ReInfo->_reRaceName);
		if (ReStartingOrderIdx != NULL) {
			delete[] ReStartingOrderIdx;
			ReStartingOrderIdx = NULL;
		}
	}
	
	// Determine the new race state automation mode.
	const bool bGoOn = ReUI().onRaceFinished(bEndOfSession);
	
	return (bEndOfSession ? RM_NEXT_STEP : RM_NEXT_RACE) | (bGoOn ? RM_SYNC : RM_ASYNC);
}
Beispiel #2
0
void
ReUpdatePracticeCurRes(tCarElt *car, bool bForceNew)
{
	if (bForceNew)
	{
		static const char* pszTableHeader =
			"Lap     \tTime          \tBest      \tTop spd  \tMin spd  \tDamages";
		ReUI().setResultsTableHeader(pszTableHeader);
		char* t1 = GfTime2Str(car->_lastLapTime, 0, false, 3);
		char* t2 = GfTime2Str(car->_bestLapTime, 0, false, 3);
		char buf[128];

		// Cancel hightlight on first line
		if (car->_laps == 2) ReUI().setResultsTableRow(0, "");

		tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
		static int nLastLapDamages = 0;
		if (car->_laps <= 2)
			nLastLapDamages = 0;
		snprintf(buf, sizeof(buf), "%.3d  \t%-12s \t%-12s    \t%5.1f   \t%5.1f \t %.5d (%d)",
				 car->_laps - 1, t1, t2, info->topSpd * 3.6, info->botSpd * 3.6,
				 car->_dammage ? car->_dammage - nLastLapDamages : 0, car->_dammage);
		nLastLapDamages = car->_dammage;
		free(t1);
		free(t2);
		
		ReUI().addResultsTableRow(buf);
	}
	else
	{
		ReUpdateQualifCurRes(car);
	}
}
Beispiel #3
0
void
ReInitCurRes()
{
	if (ReInfo->_displayMode != RM_DISP_MODE_NORMAL)
	{
		if (ReInfo->s->_raceType == RM_TYPE_QUALIF)
		{
			ReUpdateQualifCurRes(ReInfo->s->cars[0]);
		}
		else if (ReInfo->s->_raceType == RM_TYPE_PRACTICE && ReInfo->s->_ncars > 1)
		{
			ReUpdatePracticeCurRes(ReInfo->s->cars[0]);
		}
		else
		{
			static const char* pszTableHeader = "Rank    Time     Driver               Car";
			char pszTitle[128];
			snprintf(pszTitle, sizeof(pszTitle), "%s at %s", 
					 ReInfo->_reRaceName, ReInfo->track->name);
			char pszSubTitle[128];
			snprintf(pszSubTitle, sizeof(pszSubTitle), "%s (%s)",
					 ReInfo->s->cars[0]->_name, ReInfo->s->cars[0]->_carName);
			ReUI().setResultsTableTitles(pszTitle, pszSubTitle);
			ReUI().setResultsTableHeader(pszTableHeader);
		}
	}//if displayMode != normal
}
Beispiel #4
0
int
ReRaceEventInit(void)
{
	void *mainParams = ReInfo->mainParams;
	void *params = ReInfo->params;

	const bool careerMode = strcmp(GfParmGetStr(ReInfo->mainParams, RM_SECT_SUBFILES, RM_ATTR_HASSUBFILES, RM_VAL_NO), RM_VAL_YES) == 0;
	
	/* Career mode : Look if it is necessary to open another file */
	if (strcmp(GfParmGetStr(mainParams, RM_SECT_SUBFILES, RM_ATTR_HASSUBFILES, RM_VAL_NO), RM_VAL_YES) == 0)
	{
		/* Close previous params */
		if (params != mainParams)
			GfParmReleaseHandle(params);

		/* Read the new params */
		ReInfo->params = GfParmReadFile( GfParmGetStr( ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_CUR_FILE, "" ), GFPARM_RMODE_STD );
		GfLogTrace("Career : New params file is %s (from main results file)\n",
				   GfParmGetStr( ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_CUR_FILE, ""));
		if (!ReInfo->params)
			GfLogWarning( "Career : MainResults params weren't read correctly\n" );

		/* Close previous results */
		if (ReInfo->results != ReInfo->mainResults)
		{
			GfParmWriteFile(NULL, ReInfo->results, NULL);
			GfParmReleaseHandle(ReInfo->results);
		}

		/* Read the new results */
		ReInfo->results = GfParmReadFile( GfParmGetStr( ReInfo->params, RM_SECT_SUBFILES, RM_ATTR_RESULTSUBFILE, ""), GFPARM_RMODE_STD );
		if (!ReInfo->results)
			GfLogWarning( "Career : New results weren't read correctly\n" );
	}

	// Initialize the race session name.
	ReInfo->_reRaceName = ReGetCurrentRaceName();
	GfLogInfo("Starting new event (%s session)\n", ReInfo->_reRaceName);

	ReUI().onRaceEventInitializing();
	
	ReInfo->s->_features = RmGetFeaturesList(ReInfo->params);

	ReTrackInit();
	
	ReEventInitResults();

	NoCleanupNeeded = false;

	const bool bGoOnLooping = ReUI().onRaceEventStarting(careerMode && !ReHumanInGroup());

	return (bGoOnLooping ? RM_SYNC : RM_ASYNC) | RM_NEXT_STEP;
}
Beispiel #5
0
void ReRaceAbort()
{
	ReShutdownUpdaters();

	RePhysicsEngine().shutdown();
	RaceEngine::self().unloadPhysicsEngine();

	ReUI().onRaceFinishing();

	ReRaceCleanDrivers();

	if (NetGetNetwork())
		NetGetNetwork()->Disconnect();

	FREEZ(ReInfo->_reCarInfo);
	
	if (ReInfo->params != ReInfo->mainParams)
	{
		GfParmReleaseHandle(ReInfo->params);
		ReInfo->params = ReInfo->mainParams;
	}

	// Return to race configuration step
	ReStateApply((void*)RE_STATE_CONFIG);
}
Beispiel #6
0
// Display parameter statistics at console
void TGeneticParameter::DisplayStatistik()
{
	char buf[80];
	ReLogOptim.info("%s: N=%d M=%d (%g %%)\n",Label,Tries,Changed,(100.0 * Changed)/Tries);
	snprintf(buf,sizeof(buf),"%s: N=%d M=%d (%.1f %%)",Label,Tries,Changed,(100.0 * Changed)/Tries);;
	ReUI().addOptimizationMessage(buf); 
};
Beispiel #7
0
/** Initialize the track for a race manager.
    @return <tt>0 ... </tt>Ok<br>
    <tt>-1 .. </tt>Error
*/
int
ReTrackInit(void)
{
	char buf[256];
	
	const char  *trackName;
	const char  *catName;

	const int curTrkIdx =
		(int)GfParmGetNum(ReInfo->results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1);
	snprintf(buf, sizeof(buf), "%s/%d", RM_SECT_TRACKS, curTrkIdx);
	trackName = GfParmGetStr(ReInfo->params, buf, RM_ATTR_NAME, 0);
	if (!trackName)
		return -1;

	catName = GfParmGetStr(ReInfo->params, buf, RM_ATTR_CATEGORY, 0);
	if (!catName) 
		return -1;

	snprintf(buf, sizeof(buf), "tracks/%s/%s/%s.%s", catName, trackName, trackName, TRKEXT);
	ReInfo->track = ReTrackLoader().load(buf);

	snprintf(buf, sizeof(buf), "Loading %s track", ReInfo->track->name);
	ReUI().addLoadingMessage(buf);

	reTrackInitTimeOfDay();
	reTrackInitWeather();

	reTrackDump(ReInfo->track, 0);

	return 0;
}//ReTrackInit
Beispiel #8
0
int
ReRaceStop(void)
{
	ReStop();

	ReUI().onRaceInterrupted();
	
	return RM_ASYNC | RM_NEXT_STEP;
}
Beispiel #9
0
void ReRaceRestart()
{
	ReShutdownUpdaters();

	ReUI().onRaceFinishing();
	
	ReRaceCleanup();

	ReStateApply((void*)RE_STATE_PRE_RACE);
}
Beispiel #10
0
// Race Engine Exit
int
ReExit(void)
{
	// Stop and cleanup the race engine.
	ReStop();
	StandardGame::self().cleanup();
	
	// Notify the user interface.
	ReUI().quit();

	return RM_QUIT;
}
Beispiel #11
0
void ReRaceAbandon()
{
	// Notify the UI that the race event is finishing now.
	ReUI().onRaceEventFinishing();

	// Shutdown track-physics-related stuff.
	ReTrackShutdown();

	// Cleanup needed stuff.
	FREEZ(ReInfo->_reCarInfo);

	if (ReInfo->params != ReInfo->mainParams)
	{
		GfParmReleaseHandle(ReInfo->params);
		ReInfo->params = ReInfo->mainParams;
	}

	// Return to race configuration step
	ReStateApply((void*)RE_STATE_CONFIG);
}
Beispiel #12
0
/** Dump the track segments on screen
    @param  track track to dump
    @param  verbose if set to 1 all the segments are described (long)
    @ingroup  racemantools
 */
static void
reTrackDump(const tTrack *track, int verbose)
{
	char buf[128];
	
	snprintf(buf, sizeof(buf), "  by %s (%.0f m long, %.0f m wide) ...", 
			 track->authors, track->length, track->width);
	ReUI().addLoadingMessage(buf);

	GfLogInfo("++++++++++++ Track ++++++++++++\n");
	GfLogInfo("Name     = %s\n", track->name);
	GfLogInfo("Authors  = %s\n", track->authors);
	GfLogInfo("Filename = %s\n", track->filename);
	GfLogInfo("NSeg     = %d\n", track->nseg);
	GfLogInfo("Version  = %d\n", track->version);
	GfLogInfo("Length   = %f m\n", track->length);
	GfLogInfo("Width    = %f m\n", track->width);
	GfLogInfo("XSize    = %f m\n", track->max.x);
	GfLogInfo("YSize    = %f m\n", track->max.y);
	GfLogInfo("ZSize    = %f m\n", track->max.z);
  
	switch (track->pits.type) {
		case TR_PIT_NONE:
			GfLogInfo("Pits     = none\n");
			break;
      
		case TR_PIT_ON_TRACK_SIDE:
			GfLogInfo("Pits     = present on track side\n");
			break;
      
		case TR_PIT_ON_SEPARATE_PATH:
			GfLogInfo("Pits     = present on separate path\n");
			break;

		case TR_PIT_NO_BUILDING:
			GfLogInfo("Pits     = present, no building style\n");
			break;
    }//switch pits.type

	const int seconds = (int)track->local.timeofday;
	GfLogInfo("TimeOfDay= %02d:%02d:%02d\n", seconds / 3600, (seconds % 3600) / 60, seconds % 60);
	GfLogInfo("Sun asc. = %.1f d\n", RAD2DEG(track->local.sunascension));
	GfLogInfo("Clouds   = %d (0=none, 1=few, 2=scarce, 3=many, 4=full)\n", track->local.clouds);
	GfLogInfo("Rain     = %d (0=none, 1=little, 2=medium, 3=heavy)\n", track->local.rain);
	GfLogInfo("Water    = %d (0=none, 1=some, 2=more, 3=swampy)\n", track->local.water);

	if (verbose) {
		int i;
		tTrackSeg *seg;
#ifdef SD_DEBUG
		const char  *stype[4] = { "", "RGT", "LFT", "STR" };
#endif

		for (i = 0, seg = track->seg->next; i < track->nseg; i++, seg = seg->next) {
			GfLogTrace("  segment %d -------------- \n", seg->id);
#ifdef SD_DEBUG
			GfLogTrace("        type    %s\n", stype[seg->type]);
#endif
			GfLogTrace("        length  %f m\n", seg->length);
			GfLogTrace("  radius  %f m\n", seg->radius);
			GfLogTrace("  arc %f d Zs %f d Ze %f d Zcs %f d\n", RAD2DEG(seg->arc),
					   RAD2DEG(seg->angle[TR_ZS]),
					   RAD2DEG(seg->angle[TR_ZE]),
					   RAD2DEG(seg->angle[TR_CS]));
			GfLogTrace(" Za  %f d\n", RAD2DEG(seg->angle[TR_ZS]));
			GfLogTrace("  vertices: %-8.8f %-8.8f %-8.8f ++++ ",
					   seg->vertex[TR_SR].x,
					   seg->vertex[TR_SR].y,
					   seg->vertex[TR_SR].z);
			GfLogTrace("%-8.8f %-8.8f %-8.8f\n",
					   seg->vertex[TR_SL].x,
					   seg->vertex[TR_SL].y,
					   seg->vertex[TR_SL].z);
			GfLogTrace("  vertices: %-8.8f %-8.8f %-8.8f ++++ ",
					   seg->vertex[TR_ER].x,
					   seg->vertex[TR_ER].y,
					   seg->vertex[TR_ER].z);
			GfLogTrace("%-8.8f %-8.8f %-8.8f\n",
					   seg->vertex[TR_EL].x,
					   seg->vertex[TR_EL].y,
					   seg->vertex[TR_EL].z);
			GfLogTrace("  prev    %d\n", seg->prev->id);
			GfLogTrace("  next    %d\n", seg->next->id);
		}//for i
		GfLogTrace("From Last To First\n");
		GfLogTrace("Dx = %-8.8f  Dy = %-8.8f Dz = %-8.8f\n",
				   track->seg->next->vertex[TR_SR].x - track->seg->vertex[TR_ER].x,
				   track->seg->next->vertex[TR_SR].y - track->seg->vertex[TR_ER].y,
				   track->seg->next->vertex[TR_SR].z - track->seg->vertex[TR_ER].z);
    }//if verbose
}//reTrackDump
Beispiel #13
0
void
ReUpdateQualifCurRes(tCarElt *car)
{
	static const char* pszTableHeader = "Rank    \tTime          \tDriver                     \tCar";
	int		i;
	int		xx;
	int		nCars;
	int		nCarsReal;
	int		printed;
	int		maxLines;
	void	*carparam;
	char	*carName;
	const char	*race = ReInfo->_reRaceName;
	void	*results = ReInfo->results;
	char	*tmp_str;
	double		time_left;
	
	if (ReInfo->s->_ncars == 1)
	{
		ReUI().eraseResultsTable();
		maxLines = ReUI().getResultsTableRowCount();
		
		snprintf(buf, sizeof(buf), "cars/models/%s/%s.xml", car->_carName, car->_carName);
		carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
		carName = GfParmGetName(carparam);

		char pszTitle[128];
		snprintf(pszTitle, sizeof(pszTitle), "%s at %s", 
				 race, ReInfo->track->name);
		if (ReInfo->s->_raceType == RM_TYPE_PRACTICE || car->_laps < 1 || car->_laps > ReInfo->s->_totLaps)
			snprintf(buf, sizeof(buf), "%s (%s)", car->_name, carName);
		else
			snprintf(buf, sizeof(buf), "%s (%s) - Lap %d", car->_name, carName, car->_laps);
		ReUI().setResultsTableTitles(pszTitle, buf);
		ReUI().setResultsTableHeader(pszTableHeader);

		printed = 0;
		snprintf(path, sizeof(path), "%s/%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK);
		nCarsReal = GfParmGetEltNb(results, path);
		nCars = MIN(nCarsReal + 1, maxLines); // limit display to only those on 1st page
		for (i = 1; i < nCars; i++) {
			snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i);
			if (!printed && car->_bestLapTime != 0.0
				&& car->_bestLapTime < GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0)) {
				tmp_str = GfTime2Str(car->_bestLapTime, "  ", false, 3);
				snprintf(buf, sizeof(buf), " %2d \t%-12s  \t%-25s \t%-20s", i, tmp_str, car->_name, carName);
				free(tmp_str);
				ReUI().setResultsTableRow(i - 1, buf, /*highlight=*/true);
				printed = 1;
			}
			tmp_str = GfTime2Str(GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0), "  ", false, 3);
			snprintf(buf, sizeof(buf), " %2d \t%-12s  \t%-25s \t%-20s",
					 i + printed, tmp_str, GfParmGetStr(results, path, RE_ATTR_NAME, ""),
					 GfParmGetStr(results, path, RE_ATTR_CAR, ""));
			free (tmp_str);
			ReUI().setResultsTableRow(i - 1 + printed, buf);
		}
	
		if (!printed) {
			tmp_str = GfTime2Str(car->_bestLapTime, "  ", false, 3);
			snprintf(buf, sizeof(buf), " %2d \t%-12s  \t%-25s \t%-20s", nCarsReal + 1, tmp_str, car->_name, carName);
			free(tmp_str);
			ReUI().setResultsTableRow(i - 1, buf, /*highlight=*/true);
		}
	
		GfParmReleaseHandle(carparam);
	}
	else
	{
		nCars = ReInfo->s->_ncars;
		if (nCars > ReUI().getResultsTableRowCount())
			nCars = ReUI().getResultsTableRowCount();

		char pszTitle[128];
		snprintf(pszTitle, sizeof(pszTitle), "%s at %s", 
				 race, ReInfo->track->name);
		if (ReInfo->s->_totTime > ReInfo->s->currentTime)
		{
			time_left = ReInfo->s->_totTime - ReInfo->s->currentTime;
			snprintf( buf, sizeof(buf), "%d:%02d:%02d",
					  (int)floor( time_left / 3600.0f ), (int)floor( time_left / 60.0f ) % 60,
					  (int)floor( time_left ) % 60 );
		}
		else
		{
			snprintf( buf, sizeof(buf), "%d laps", ReInfo->s->_totLaps );
		}
		ReUI().setResultsTableTitles(pszTitle, buf);
		ReUI().setResultsTableHeader(pszTableHeader);
		
		for (xx = 0; xx < nCars; ++xx) {
			car = ReInfo->s->cars[ xx ];
			snprintf(buf, sizeof(buf), "cars/models/%s/%s.xml", car->_carName, car->_carName);
			carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
			carName = strdup(GfParmGetName(carparam));
			GfParmReleaseHandle(carparam);
			
			if (car->_state & RM_CAR_STATE_DNF) {
				snprintf(buf, sizeof(buf), "out \t               \t%-25s \t%-20s", car->_name, carName);
			} else if (car->_bestLapTime <= 0.0f) {
				snprintf(buf, sizeof(buf), " %2d \t      --:---   \t%-25s \t%-20s",
						 xx + 1, car->_name, carName);
			} else {
				if (xx == 0)
					tmp_str = GfTime2Str(car->_bestLapTime, " ", false, 3);
				else
					tmp_str = GfTime2Str(car->_bestLapTime - ReInfo->s->cars[0]->_bestLapTime,
										 "+", false, 3);
				snprintf(buf, sizeof(buf), " %2d \t%-12s  \t%-25s \t%-20s",
						 xx + 1, tmp_str, car->_name, carName);
				free(tmp_str);
			}
			ReUI().setResultsTableRow(xx, buf);
			FREEZ(carName);
		}
	}
}
Beispiel #14
0
int ReConfigure()
{
	ReUI().onRaceConfiguring();

	return RM_ASYNC | RM_NEXT_STEP;
}
Beispiel #15
0
/* return state mode */
int
ReRaceStart(void)
{
	char path[128];
	char path2[128];
	const char *sessionName = ReInfo->_reRaceName;
	void *params = ReInfo->params;
	void *results = ReInfo->results;
	int mode = 0;

	// Trace race session identification (more to say for the Carer mode).
	char pszSessionId[128];
	if (!strcmp(GfParmGetStr(ReInfo->mainParams, RM_SECT_SUBFILES, RM_ATTR_HASSUBFILES, RM_VAL_NO), RM_VAL_YES))
	{
		const char* pszGroup = GfParmGetStr(params, RM_SECT_HEADER, RM_ATTR_NAME, "<no group>");
		snprintf(pszSessionId, sizeof(pszSessionId), "%s %s %s", ReInfo->_reName, pszGroup, sessionName);
	}
	else
		snprintf(pszSessionId, sizeof(pszSessionId), "%s %s", ReInfo->_reName, sessionName);
	
	GfLogInfo("Starting %s session at %s\n", pszSessionId, ReInfo->track->name);

	// Reallocate and reset car info for the race.
	FREEZ(ReInfo->_reCarInfo);
	ReInfo->_reCarInfo =
		(tReCarInfo*)calloc(GfParmGetEltNb(params, RM_SECT_DRIVERS), sizeof(tReCarInfo));

	ReUI().onRaceInitializing();
	
	// Drivers starting order
	int nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS);
	GfParmListClean(params, RM_SECT_DRIVERS_RACING);
	if (nCars == 0)
	{
		// This may happen, when playing with the text-only mode,
		// and forgetting that human are automatically excluded then,
		// or when getting back to the GUI mode, and not reconfiguring the competitors list.
		GfLogError("No competitor in this race : cancelled.\n");
		mode = RM_ERROR;
	}
	else if ((ReInfo->s->_raceType == RM_TYPE_QUALIF || ReInfo->s->_raceType == RM_TYPE_PRACTICE)
		&& ReInfo->s->_totTime < 0.0f /* Timed session? */)
	//Checks if there is only one driver per session allowed, so practice, qualification without timed session. 
	{
		// non-timed Qualification or Practice session => 1 driver at a time = the "current" one.
		int nCurrDrvInd =
			(int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, 1);
		if (nCurrDrvInd == -1)
			return RM_ERROR;

		// Propagate competitor drivers info to the real race starting grid
		snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS, nCurrDrvInd);
		snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, 1);

		GfParmSetStr(params, path2, RM_ATTR_MODULE,
					 GfParmGetStr(params, path, RM_ATTR_MODULE, ""));
		GfParmSetNum(params, path2, RM_ATTR_IDX, NULL,
					 GfParmGetNum(params, path, RM_ATTR_IDX, NULL, 0));
		GfParmSetNum(params, path2, RM_ATTR_EXTENDED, NULL,
					 GfParmGetNum(params, path, RM_ATTR_EXTENDED, NULL, 0));
		GfParmSetNum(params, path2, RM_ATTR_SKINTARGETS, NULL,
					 GfParmGetNum(params, path, RM_ATTR_SKINTARGETS, NULL, 0));
		if (GfParmGetStr(params, path, RM_ATTR_SKINNAME, 0))
			GfParmSetStr(params, path2, RM_ATTR_SKINNAME,
						 GfParmGetStr(params, path, RM_ATTR_SKINNAME, ""));
	}
	else
	{
		// For a race, add cars to the starting grid in the order stored in ReStartingOrderIdx.
		ReUI().addLoadingMessage("Preparing Starting Grid ...");
		
		int maxCars = (int)GfParmGetNum(params, sessionName, RM_ATTR_MAX_DRV, NULL, 100);
		nCars = MIN(nCars, maxCars);
		int currDriver = -1;
		int aCars = 0;
		
		for (int i = 1; i < nCars + 1; i++)
		{
			currDriver = ReStartingOrderIdx[i-1];
			if (currDriver == -1)
				continue;
			aCars++;
			snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS, currDriver);
			snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, i);
			GfParmSetStr(params, path2, RM_ATTR_MODULE,
						 GfParmGetStr(params, path, RE_ATTR_MODULE, ""));
			GfParmSetNum(params, path2, RM_ATTR_IDX, NULL,
						 GfParmGetNum(params, path, RE_ATTR_IDX, NULL, 0));
			GfParmSetNum(params, path2, RM_ATTR_EXTENDED, NULL,
						 GfParmGetNum(params, path, RM_ATTR_EXTENDED, NULL, 0));
			GfParmSetNum(params, path2, RM_ATTR_SKINTARGETS, NULL,
						 GfParmGetNum(params, path, RM_ATTR_SKINTARGETS, NULL, 0));
			if (GfParmGetStr(params, path, RM_ATTR_SKINNAME, 0))
				GfParmSetStr(params, path2, RM_ATTR_SKINNAME,
							 GfParmGetStr(params, path, RM_ATTR_SKINNAME, ""));
		}
		
		//no valid drivers present in the list
		if (aCars == 0)
		{
			GfLogError("No competitor in this race : cancelled.\n");
			mode = RM_ERROR;
		}
	}
	
	//ReTrackUpdate();

	if (!(mode & RM_ERROR))
	{
		// According to what the UI answers, start the race right now or not.
		mode = RM_ASYNC | RM_NEXT_STEP;
		const bool bGoOn = ReUI().onRaceStarting();
		if (bGoOn)
			mode = ReRaceRealStart();
	}
	
	return mode;
}
Beispiel #16
0
/* return state mode */
int
ReRaceRealStart(void)
{
	int i, j;
	tRobotItf *robot;
	tReCarInfo *carInfo;
	char buf[128];
	int foundHuman;
	void *params = ReInfo->params;
	tSituation *s = ReInfo->s;
	tMemoryPool oldPool = NULL;
	void* carHdle;

	// Load the physics engine
	if (!RaceEngine::self().loadPhysicsEngine())
		return RM_ERROR;

	// Get the session display mode (default to "All sessions" ones, or else "normal").
	std::string strDispMode =
		GfParmGetStr(params, ReInfo->_reRaceName, RM_ATTR_DISPMODE, "");
	if (strDispMode.empty())
		strDispMode =
			GfParmGetStr(params, RM_VAL_ANYRACE, RM_ATTR_DISPMODE, RM_VAL_VISIBLE);

	if (strDispMode == RM_VAL_INVISIBLE)
		ReInfo->_displayMode = RM_DISP_MODE_NONE;
	else if (strDispMode == RM_VAL_VISIBLE)
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	else if (strDispMode == RM_VAL_SIMUSIMU)
		ReInfo->_displayMode = RM_DISP_MODE_SIMU_SIMU;
	else
	{
		GfLogError("Unsupported display mode '%s' loaded from race file ; "
				   "assuming 'normal'\n", strDispMode.c_str());
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	}

	//GfLogDebug("ReRaceRealStart: Loaded dispMode=0x%x\n", ReInfo->_displayMode);
	
	// Check if there is a human in the driver list
	foundHuman = ReHumanInGroup() ? 2 : 0;

	// Reset SimuSimu bit if any human in the race.
	// Note: Done here in order to make SimuSimu faster. 
	if ((ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU) && foundHuman)
	{
		ReInfo->_displayMode &= ~RM_DISP_MODE_SIMU_SIMU;
	}
	
	// Initialize & place cars
	// Note: if SimuSimu display mode, robot->rbNewTrack isn't called. This is a lot faster.
	if (ReInitCars())
		return RM_ERROR;

	// Check if there is a human in the current race
	// Warning: Don't move this before ReInitCars (initializes s->cars).
	for (i = 0; i < s->_ncars; i++) {
		if (s->cars[i]->_driverType == RM_DRV_HUMAN) {
			foundHuman = 1;
			break;
		}//if human
	}//for i

	// Force "normal" display mode if any human in the session
	if (foundHuman == 1)
	{
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	}
	// Force "result only" mode in Practice / Qualif. sessions without any human,
	// but at least 1 in another session (why this ?), and SimuSimu bit on.
	else if (foundHuman == 2 && (ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU)
		     && (ReInfo->s->_raceType == RM_TYPE_QUALIF
				 || ReInfo->s->_raceType == RM_TYPE_PRACTICE))
	{
		ReInfo->_displayMode = RM_DISP_MODE_NONE;
	}

	GfLogInfo("Display mode : %s\n",
			  (ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU) ? "SimuSimu" :
			  ((ReInfo->_displayMode & RM_DISP_MODE_NORMAL) ? "Normal" : "Results-only"));
	
	// Notify the UI that it's "race loading time".
	ReUI().onRaceLoadingDrivers();

	// Load drivers for the race
	for (i = 0; i < s->_ncars; i++)
	{
		snprintf(buf, sizeof(buf), "cars/%s/%s.xml",
				 s->cars[i]->_carName, s->cars[i]->_carName);
		carHdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
		snprintf(buf, sizeof(buf), "Loading %s driver (%s) ...",
				 s->cars[i]->_name, GfParmGetName(carHdle));
		
		ReUI().addLoadingMessage(buf);

		if (!(ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU))
		{
			//Tell robots they are to start a new race
			robot = s->cars[i]->robot;
			GfPoolMove( &s->cars[i]->_newRaceMemPool, &oldPool );
			robot->rbNewRace(robot->index, s->cars[i], s);
			GfPoolFreePool( &oldPool );
		}//if ! simusimu
	}//for i
	
	RtTeamManagerStart();

	// Notify the UI that the drivers have been loaded now.
	ReUI().onRaceDriversLoaded();

	// Initialize the physics engine
	RePhysicsEngine().updateSituation(s, RCM_MAX_DT_SIMU);

	carInfo = ReInfo->_reCarInfo;
	for (i = 0; i < s->_ncars; i++) {
		carInfo[i].prevTrkPos = s->cars[i]->_trkPos;
	}

	// All cars start with max brakes on
	ReUI().addLoadingMessage("Running Prestart ...");
	
	for (i = 0; i < s->_ncars; i++)
	{
		memset(&(s->cars[i]->ctrl), 0, sizeof(tCarCtrl));
		s->cars[i]->ctrl.brakeCmd = 1.0;
	}

	for (j = 0; j < (int)(1.0 / RCM_MAX_DT_SIMU); j++)
		RePhysicsEngine().updateSituation(s, RCM_MAX_DT_SIMU);

	// Initialize current result manager.
	ReInitCurRes();

	// More initializations.
	ReInfo->_reTimeMult = 1.0;
	ReInfo->_reLastRobTime = -1.0;
	if (NetGetNetwork())
		ReInfo->s->currentTime = GfTimeClock() - NetGetNetwork()->GetRaceStartTime();
	else
		ReInfo->s->currentTime = -2.0;	// We start 2 seconds before the real race start
	ReInfo->s->deltaTime = RCM_MAX_DT_SIMU;
	ReInfo->s->_raceState = RM_RACE_STARTING;

	ReInfo->_rePitRequester = 0;
	ReInfo->_reMessage = 0;
	ReInfo->_reMessageEnd = 0.0;
	ReInfo->_reBigMessage = 0;
	ReInfo->_reBigMessageEnd = 0.0;
	
	ReInitUpdaters();

	// Notify the UI that the race simulation is ready now.
	ReUI().onRaceSimulationReady();

	// Initialize the network if needed.
	if (NetGetNetwork())
	{
		ReUI().addLoadingMessage("Preparing online race ...");
		
		NetGetNetwork()->RaceInit(ReOutputSituation()->s);
		NetGetNetwork()->SetRaceActive(true);
	}

	// Notify the UI that the race is now started.
	ReUI().addLoadingMessage("Ready.");

	ReUI().onRaceStarted();

	// And go on looping the race state automaton.
	return RM_SYNC | RM_NEXT_STEP;
}//ReRaceRealStart
Beispiel #17
0
int
RePreRace(void)
{
	char path[128];
	const char *raceName;
	const char *raceType;
	void *params = ReInfo->params;
	void *results = ReInfo->results;
	int curRaceIdx;
	int timedLapsReplacement = 0;
	char *prevRaceName;
	
	raceName = ReInfo->_reRaceName = ReGetCurrentRaceName();
	
	GfParmRemoveVariable (params, "/", "humanInGroup");
	GfParmRemoveVariable (params, "/", "eventNb");
	GfParmSetVariable (params, "/", "humanInGroup", ReHumanInGroup() ? 1.0f : 0.0f);
	GfParmSetVariable (params, "/", "eventNb", GfParmGetNum (ReInfo->results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1.0 ) );
	if (!raceName) {
		return RM_ERROR;
	}

	if (strcmp(GfParmGetStr(params, raceName, RM_ATTR_ENABLED, RM_VAL_YES), RM_VAL_NO) == 0) {
		GfLogTrace( "Race %s disabled\n",  raceName);
		curRaceIdx = (int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_RACE, NULL, 1);
		if (curRaceIdx < GfParmGetEltNb(params, RM_SECT_RACES)) {
			curRaceIdx++;
			GfLogTrace( "Race %s is not the last one, but the #%d\n",  raceName, curRaceIdx);
			GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_RACE, NULL, (tdble)curRaceIdx);
	
			return RM_SYNC | RM_NEXT_RACE;
		}
	
		GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_RACE, NULL, 1);
		return RM_SYNC | RM_NEXT_RACE | RM_NEXT_STEP;
	}

	// Get session max dammages.
	ReInfo->s->_maxDammage = (int)GfParmGetNum(params, raceName, RM_ATTR_MAX_DMG, NULL, 10000);

	// Get session type (race, qualification or practice).
	raceType = GfParmGetStr(params, raceName, RM_ATTR_TYPE, RM_VAL_RACE);
	if (!strcmp(raceType, RM_VAL_RACE)) {
		ReInfo->s->_raceType = RM_TYPE_RACE;
	} else if (!strcmp(raceType, RM_VAL_QUALIF)) {
		ReInfo->s->_raceType = RM_TYPE_QUALIF;
	} else if (!strcmp(raceType, RM_VAL_PRACTICE)) {
		ReInfo->s->_raceType = RM_TYPE_PRACTICE;
	}

	// Get session duration (defaults to "All sessions" one, or else -60).
	ReInfo->s->_totTime = GfParmGetNum(params, raceName, RM_ATTR_SESSIONTIME, NULL, -1);
	if (ReInfo->s->_totTime < 0)
		ReInfo->s->_totTime = GfParmGetNum(params, RM_VAL_ANYRACE, RM_ATTR_SESSIONTIME, NULL, -60.0f);

	// Determine the actual session duration and/or number of laps.
	ReInfo->s->_extraLaps = 0; // TODO: Does this is ever needed ?
	ReInfo->s->_totLaps = 0; // Make sure it is initialized

	if (ReInfo->s->_totTime > 0 && !(ReInfo->s->_features & RM_FEATURE_TIMEDSESSION)) {
		// Timed session not supported: add 1 km for every minute in parctise or qualifying,
		// and 150 km for every hour (2.5 km for every minute) in race
		if (ReInfo->s->_raceType == RM_TYPE_RACE) {
			ReInfo->s->_totLaps = (int)floor(ReInfo->s->_totTime * 2500.0f / 60.0f / ReInfo->track->length + 0.5f);
		} else {
			ReInfo->s->_totLaps = (int)floor(ReInfo->s->_totTime * 1000.0f / 60.0f / ReInfo->track->length + 0.5f);
		}
		timedLapsReplacement = ReInfo->s->_totLaps;
		ReInfo->s->_totTime = -60.0f;
	}
	
	// Timed session doesn't exclude additional laps after the time finishes
	// Make sure that if no time set, we set far below zero
	if(ReInfo->s->_totTime <= 0.0f )
		ReInfo->s->_totTime = -60.0f;
		
	// Get session distance (defaults to "All sessions" one, or else 0).
	tdble dist = GfParmGetNum(params, raceName, RM_ATTR_DISTANCE, NULL, -1);
	if (dist < 0)
		dist = GfParmGetNum(params, RM_VAL_ANYRACE, RM_ATTR_DISTANCE, NULL, 0);
	
	// If a (> 0) session distance was specified, deduce the number of laps
	// in case the race settings don't specify it, and it is not a timed race.
	if ( (dist >= 0.001) && (ReInfo->s->_totTime < 0.0f) ) { // Why not 'if (dist > 0)' ???
		ReInfo->s->_totLaps = (int)(dist / ReInfo->track->length) + 1;
		ReInfo->s->_extraLaps = ReInfo->s->_totLaps; // Extralaps are used to find out how many laps there are after the time is up in timed sessions
	} else {dist = -1;}
	
	// Get the number of laps (defaults to "All sessions" one,
	// or else the already computed one from the session distance, or 0).
	int laps = (int)GfParmGetNum(params, raceName, RM_ATTR_LAPS, NULL, -1);
	if (laps < 0)
		laps = (int)GfParmGetNum(params, RM_VAL_ANYRACE, RM_ATTR_LAPS, NULL, 0);

	// Use lap number only when race distance is not in use.
	if ( (laps > 0) && (dist <= 0.0) && (timedLapsReplacement <= 0) ) {
		ReInfo->s->_totLaps = laps;
		ReInfo->s->_extraLaps = ReInfo->s->_totLaps; //Extralaps are used to find out how many laps there are after the time is up in timed sessions
	}

	// Make sure we have at least 1 lap race length.
	if ( (laps <= 0) && (dist <=0) && (ReInfo->s->_totTime < 0) ) {
		ReInfo->s->_totLaps = 1;
		ReInfo->s->_extraLaps = ReInfo->s->_totLaps; //Extralaps are used to find out how many laps there are after the time is up in timed sessions
	}

	// Correct extra laps (possible laps run after the winner arrived ?) :
	// during timed practice or qualification, there are none.
	if (ReInfo->s->_raceType != RM_TYPE_RACE && ReInfo->s->_totTime > 0) {
		ReInfo->s->_extraLaps = 0; //Extralaps are used to find out how many laps there are after the time is up in timed sessions
		ReInfo->s->_totLaps = 0;
	}

	GfLogInfo("Race length : time=%.0fs, laps=%d (extra=%d)\n",
			  ReInfo->s->_totTime, ReInfo->s->_totLaps, ReInfo->s->_extraLaps);
	
	// Initialize race state.
	ReInfo->s->_raceState = 0;

	// Cleanup results
	snprintf(path, sizeof(path), "%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, raceName);
	GfParmListClean(results, path);

	// Drivers starting order
	// The starting order is decided here,
	// then car indexes are stored in ReStartingOrderIdx, in the starting order.
	// The actual grid is assembled in ReRaceStart().
	// In case of a race, when all cars start at the same time,
	// cars are simply added to the starting list in the order stored in ReStartingOrderIdx.
	// If only one car is at the track at a time (not timed session qualifying or practice),
	// the race is divided into many sub-races.
	// For a sub-race, only the car pointed by results/RE_ATTR_CUR_DRIVER
	// is added to the starting grid.
	// RE_ATTR_CUR_DRIVER is refreshed after every sub-race in ReRaceEnd().
	ReCurrDriverNr = 0;
	int nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS);
	GfParmListClean(params, RM_SECT_DRIVERS_RACING);
	if (nCars == 0)
	{
		// This may happen, when playing with the text-only mode,
		// and forgetting that human are automatically excluded then,
		// or when getting back to the GUI mode, and not reconfiguring the competitors list.
		GfLogError("No competitor in this race : cancelled.\n");
		return RM_ERROR;
	}
	else
	{
		ReUI().addLoadingMessage("Determining Starting Order ...");

		const char* gridType =
			GfParmGetStr(params, raceName, RM_ATTR_START_ORDER, RM_VAL_DRV_LIST_ORDER);
		
		int maxCars = (int)GfParmGetNum(params, raceName, RM_ATTR_MAX_DRV, NULL, 100);
		nCars = MIN(nCars, maxCars);
		
		tReGridPart *GridList = NULL;
		int nGridList = 0;
		
		// Initialize the array of car indexes for starting order
		if (ReStartingOrderIdx != NULL) {
			delete[] ReStartingOrderIdx;
			ReStartingOrderIdx = NULL;
		}
		ReStartingOrderIdx = new int[nCars];
		for (int i = 0; i < nCars; i++) {
			ReStartingOrderIdx[i] = -1;
		}
		
		// Starting grid in the arrival order of the previous race (or qualification session)
		if (!strcmp(gridType, RM_VAL_LAST_RACE_ORDER))
		{
			GfLogTrace("Starting grid in the order of the last race\n");
			
			prevRaceName = ReGetPrevRaceName(/* bLoop = */false);
			if (!prevRaceName) {
				return RM_ERROR;
			}

			for (int i = 1; i < nCars + 1; i++) {
				snprintf(path, sizeof(path), "%s/%s/%s/%s/%d",
						 ReInfo->track->name, RE_SECT_RESULTS, prevRaceName, RE_SECT_RANK, i);
				ReStartingOrderIdx[i-1] = 
					ReFindDriverIdx (GfParmGetStr(results, path, RE_ATTR_MODULE, ""),
									(int)GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0));
			}
		}
		
		// Starting grid in the reversed arrival order of the previous race
		else if (!strcmp(gridType, RM_VAL_LAST_RACE_RORDER))
		{
			GfLogTrace("Starting grid in the reverse order of the last race\n");

			prevRaceName = ReGetPrevRaceName(/* bLoop = */false);
			if (!prevRaceName) {
				return RM_ERROR;
			}

			for (int i = 1; i < nCars + 1; i++) {
				snprintf(path, sizeof(path), "%s/%s/%s/%s/%d",
						ReInfo->track->name, RE_SECT_RESULTS, prevRaceName, RE_SECT_RANK, nCars - i + 1);
				ReStartingOrderIdx[i-1] = 
					ReFindDriverIdx (GfParmGetStr(results, path, RE_ATTR_MODULE, ""),
									(int)GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0));
			}
		}

		// Starting grid as a mix from the results of earlier sessions
		else if (ReParseStartingOrder(gridType, &GridList, nCars, nGridList))
		{
			GfLogTrace("Starting grid as a mix from the results of earlier sessions\n");
			
			int idx;
			int gridpos = 1;
			int carnr;
			const char *modulename;
			for (int i = 0; i < nGridList; i++) {
				if (gridpos > nCars) {break;}
				if (GridList[i].diffpos == -1) {//reversed
					for ( int j = GridList[i].startpos; j >= GridList[i].endpos; j--) {
						if (gridpos > nCars) {break;}
						snprintf(path, sizeof(path), "%s/%s/%s/%s/%d",
								ReInfo->track->name, RE_SECT_RESULTS, GridList[i].racename, RE_SECT_RANK, j);
						idx = (int)GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0);
						modulename = GfParmGetStr(results, path, RE_ATTR_MODULE, "");
						carnr = ReFindDriverIdx(modulename, idx);
						for (int k = 0; k < gridpos-1; k++) {
							if ( carnr == ReStartingOrderIdx[k] ) {
								//oops: same car twice
								GfLogWarning("The same car appears twice in the advanced grid!\n");
								carnr = -1;
								break;
							}
						}
						//adding car to the list
						if (carnr != -1) {
							ReStartingOrderIdx[gridpos-1] = carnr;
							gridpos++;
						}
					}
				} else if (GridList[i].diffpos == 1){//straight order
					for ( int j = GridList[i].startpos; j <= GridList[i].endpos; j++) {
						if (gridpos > nCars) {break;}
						snprintf(path, sizeof(path), "%s/%s/%s/%s/%d",
								ReInfo->track->name, RE_SECT_RESULTS, GridList[i].racename, RE_SECT_RANK, j);
						idx = (int)GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0);
						modulename = GfParmGetStr(results, path, RE_ATTR_MODULE, "");
						carnr = ReFindDriverIdx(modulename, idx);
						for (int k = 0; k < gridpos-1; k++) {
							if ( carnr == ReStartingOrderIdx[k] ) {
								//oops: same car twice
								GfLogWarning("The same car appears twice in the advanced grid!\n");
								carnr = -1;
								break;
							}
						}
						//adding car to the list
						if (carnr != -1) {
							ReStartingOrderIdx[gridpos-1] = carnr;
							gridpos++;
						}
					}
				}
			}
			//cleaning up memory
			if (nGridList > 0){delete[] GridList;}
		}

		// Starting grid in the drivers list order
		else
		{
			GfLogTrace("Starting grid in the order of the driver list\n");

			for (int i = 1; i < nCars + 1; i++) {
				snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS, i);
				ReStartingOrderIdx[i-1] = 
					ReFindDriverIdx (GfParmGetStr(params, path, RE_ATTR_MODULE, ""),
									(int)GfParmGetNum(params, path, RE_ATTR_IDX, NULL, 0));
			}
		}
	}
	
	ReCurrDriverNr = 0;
	GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL,
				(tdble)ReStartingOrderIdx[ReCurrDriverNr]);

	return RM_SYNC | RM_NEXT_STEP;
}
Beispiel #18
0
void
ReUpdateRaceCurRes()
{
	static const char* pszTableHeader = "Rank    \tTime          \tDriver                   \tCar";
    int ncars;
    int xx;
    void *carparam;
    char *carName;
    tCarElt *car;
    char *tmp_str;
    double time_left;

    ncars = ReInfo->s->_ncars;
    if (ncars > ReUI().getResultsTableRowCount())
    	ncars = ReUI().getResultsTableRowCount();

	char pszTitle[128];
	snprintf(pszTitle, sizeof(pszTitle), "%s at %s",
			 ReInfo->_reRaceName, ReInfo->track->name);

    if (ReInfo->s->_totTime > ReInfo->s->currentTime)
    {
    	time_left = ReInfo->s->_totTime - ReInfo->s->currentTime;
    	snprintf( buf, sizeof(buf), "%d:%02d:%02d",
				  (int)floor( time_left / 3600.0f ),
				  (int)floor( time_left / 60.0f ) % 60, (int)floor( time_left ) % 60 );
    }
    else
    {
    	snprintf( buf, sizeof(buf), "%d laps", ReInfo->s->_totLaps );
    }
	ReUI().setResultsTableTitles(pszTitle, buf);
	ReUI().setResultsTableHeader(pszTableHeader);

    for (xx = 0; xx < ncars; ++xx) {
    	car = ReInfo->s->cars[ xx ];
        snprintf(buf, sizeof(buf), "cars/models/%s/%s.xml", car->_carName, car->_carName);
        carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
        carName = strdup(GfParmGetName(carparam));
        GfParmReleaseHandle(carparam);
	
		if (car->_state & RM_CAR_STATE_DNF) {
			snprintf(buf, sizeof(buf), "out               %-20s %-20s", car->_name, carName);
		} else if (car->_timeBehindLeader == 0.0f) {
			if (xx != 0)
				snprintf(buf, sizeof(buf), " %2d     \t   --:--- \t%-25s \t%-20s",
						 xx + 1, car->_name, carName);
			else
				snprintf(buf, sizeof(buf), " %2d     \t%3d laps  \t%-25s \t%-20s",
						 xx + 1, car->_laps - 1, car->_name, carName);
		} else {
			if (xx == 0) {
				snprintf(buf, sizeof(buf), " %2d     \t%3d laps  \t%-25s \t%-20s",
						 xx + 1, car->_laps - 1, car->_name, carName);
			} else {
				if (car->_lapsBehindLeader == 0)
				{
					tmp_str = GfTime2Str(car->_timeBehindLeader, "  ", false, 3);
					snprintf(buf, sizeof(buf), " %2d \t%-12s\t%-25s \t%-20s",
							 xx + 1, tmp_str, car->_name, carName);
					free(tmp_str);
				}
				else if (car->_lapsBehindLeader == 1)
					snprintf(buf, sizeof(buf), " %2d \t       1 lap  \t%-25s \t%-20s",
							 xx + 1, car->_name, carName);
				else
					snprintf(buf, sizeof(buf), " %2d \t    %3d laps  \t%-25s \t%-20s",
							 xx + 1, car->_lapsBehindLeader, car->_name, carName);
			}
		}
		ReUI().setResultsTableRow(xx, buf);
		FREEZ(carName);
    }
}
Beispiel #19
0
int
ReRaceEventShutdown(void)
{
	char buf[64];
	int curTrkIdx;
	void *params = ReInfo->params;
	int nbTrk;
	void *results = ReInfo->results;
	int curRaceIdx;
	bool careerMode = false;
	bool first = true;

	// Notify the UI that the race event is finishing now.
	ReUI().onRaceEventFinishing();

	// Shutdown track-physics-related stuff.
	ReTrackShutdown();

	// Determine the track of the next event to come, if not the last one
	// and, if Career mode, prepare race params / results for the next event or season.
	do {
		nbTrk = GfParmGetEltNb(params, RM_SECT_TRACKS);
		curRaceIdx =(int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_RACE, NULL, 1);
		curTrkIdx = (int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1);

		if (curRaceIdx == 1) {
			if (curTrkIdx < nbTrk) {
				// Next track.
				curTrkIdx++;
			} else if (curTrkIdx >= nbTrk) {
				// Back to the beginning.
				curTrkIdx = 1;
			}
		}

		GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, (tdble)curTrkIdx);

		// Career mode.
		if (!strcmp(GfParmGetStr(ReInfo->mainParams, RM_SECT_SUBFILES, RM_ATTR_HASSUBFILES, RM_VAL_NO), RM_VAL_YES)) {
			careerMode = true;
			const bool lastRaceOfRound = strcmp(GfParmGetStr(params, RM_SECT_SUBFILES, RM_ATTR_LASTSUBFILE, RM_VAL_YES), RM_VAL_YES) == 0;

			// Previous file <= Current file.
			GfParmSetStr(ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_PREV_FILE,
						 GfParmGetStr(ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_CUR_FILE, ""));
			// Current file <= Next file.
			GfParmSetStr(ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_CUR_FILE,
						 GfParmGetStr(params, RM_SECT_SUBFILES, RM_ATTR_NEXTSUBFILE, ""));
			
			GfParmWriteFile(NULL, ReInfo->mainResults, NULL);
			
			/* Check if the next competition has a free weekend */
			if( !first ) {
				/* Close old params */
				GfParmWriteFile( NULL, results, NULL );
				GfParmReleaseHandle( results );
				GfParmReleaseHandle( params );
			}//if !first
			
			/* Open params of next race */
			params = GfParmReadFile( GfParmGetStr(ReInfo->mainResults, RE_SECT_CURRENT, RE_ATTR_CUR_FILE, "" ), GFPARM_RMODE_STD );
			if( !params )
				break;
			results = GfParmReadFile( GfParmGetStr(params, RM_SECT_SUBFILES, RM_ATTR_RESULTSUBFILE, ""), GFPARM_RMODE_STD );
			if( !results ) {
				GfParmReleaseHandle( results );
				break;
			}
	
			if (lastRaceOfRound && curTrkIdx == 1) {
				ReCareerNextSeason();
			}
			if ((int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1) == 1) {
				GfParmListClean(results, RE_SECT_STANDINGS);
				GfParmWriteFile(NULL, results, NULL);
			}
	
			/* Check if it is free */
			snprintf( buf, sizeof(buf), "%s/%d", RM_SECT_TRACKS,
					  (int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1) );
			if( !strcmp(GfParmGetStr(params, buf, RM_ATTR_NAME, "free"), "free") == 0) {
				/* Not a free weekend */
				GfParmReleaseHandle( results );
				GfParmReleaseHandle( params );
				break;
			}
			first = false;
		} else {
			// Normal mode (no subfiles, so free weekends possible, so nothing to check)
			break;
		}
	} while( true );

	// Determine new race state automaton mode.
	int mode = (curTrkIdx != 1 || careerMode) ? RM_NEXT_RACE : RM_NEXT_STEP;
	bool careerNonHumanGroup = careerMode && !ReHumanInGroup();

	mode |= ReUI().onRaceEventFinished(nbTrk != 1, careerNonHumanGroup) ? RM_SYNC : RM_ASYNC;;
	
	if (mode & RM_NEXT_STEP)
		FREEZ(ReInfo->_reCarInfo);

	return mode;
}
Beispiel #20
0
/**
 * Function to load a car.
 *
 * @param carindex The index whichs will be used as car->index for the car.
 * @param listindex The listindex in RM_SECT_DRIVERS_RACING
 * @param modindex The index of the mod; must be MAX_MOD_ITF if normal_carname is FALSE.
 * @param robotIdx The index of the robot.
 * @param normal_carname If this member is TRUE, the car is treated as an ordinary car;
 *                       if this member is FALSE, then the car used is the one given
 *                       in the xml-file, and there is no restriction on the number of instances.
 * @param cardllname The dllname of the driver
 * @return A pointer to the newly created car if successfull; NULL otherwise
 */
static tCarElt* reLoadSingleCar( int carindex, int listindex, int modindex, int relativeRobotIdx, char normal_carname, char const *cardllname )
{
  tCarElt *elt;
  tMemoryPool oldPool;
  char path[256];
  char path2[256];
  char buf[256];
  char buf2[256];
  char const *str;
  char const *category;
  char const *subcategory;
  char const *teamname;
  std::string carname;
  tModInfoNC *curModInfo;
  tRobotItf *curRobot;
  void *robhdle;
  void *cathdle;
  void *carhdle;
  void *handle;
  int k;
  int xx;
  char isHuman;
  int robotIdx = relativeRobotIdx;

  /* good robot found */
  curModInfo = &((*(ReInfo->robModList))->modInfo[modindex]);

  subcategory = ReInfo->track->subcategory;

#if 0 //SDW
  if (replayReplay)
    GfLogInfo("Driver in car %d being driven by replay\n", carindex);
  else
#endif
    GfLogInfo("Driver's name: %s\n", curModInfo->name);

  isHuman = strcmp( cardllname, "human" ) == 0 || strcmp( cardllname, "networkhuman" ) == 0;

  /* Extended is forced for humans, so no need to increase robotIdx */
  if (!normal_carname && !isHuman) 
    robotIdx += curModInfo->index;

  /* Retrieve the driver interface (function pointers) */
  curRobot = (tRobotItf*)calloc(1, sizeof(tRobotItf));

  /* ... and initialize the driver */
#if 0 // SDW
  if (replayReplay) {
    // Register against the Replay driver (which does nothing)
    curModInfo->fctInit(carindex, (void*)(curRobot));
  } else if (!(ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU)) {
#else
  if (!(ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU)) {
#endif
    curModInfo->fctInit(robotIdx, (void*)(curRobot));
  } else {
    curRobot->rbNewTrack = NULL;
    curRobot->rbNewRace  = NULL;
    curRobot->rbResumeRace  = NULL;
    curRobot->rbDrive    = NULL;
    curRobot->rbPitCmd   = NULL;
    curRobot->rbEndRace  = NULL;
    curRobot->rbShutdown = NULL;
    curRobot->index      = 0;
  }

  /* Retrieve and load the robotXML file :
     1) from user settings dir (local dir)
     2) from installed data dir */
  snprintf(buf, sizeof(buf), "%sdrivers/%s/%s.xml", GfLocalDir(), cardllname, cardllname);
  robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
  if (!robhdle) {
    snprintf(buf, sizeof(buf), "drivers/%s/%s.xml", cardllname, cardllname);
    robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
  }

  if (normal_carname || isHuman)
    snprintf(path, sizeof(path), "%s/%s/%d", ROB_SECT_ROBOTS, ROB_LIST_INDEX, robotIdx);
  else
    snprintf(path, sizeof(path), "%s", ROB_SECT_ARBITRARY);
  
  /* Load car/driver info (in race engine data structure) */
  if (robhdle)
  {
    elt = &(ReInfo->carList[carindex]);
    GF_TAILQ_INIT(&(elt->_penaltyList));

    const std::string strDType = GfParmGetStr(robhdle, path, ROB_ATTR_TYPE, ROB_VAL_ROBOT);
    if (strDType == ROB_VAL_ROBOT){
      elt->_driverType = RM_DRV_ROBOT;
      elt->_networkPlayer = 0;
    } 
    else if (strDType == ROB_VAL_HUMAN)
    {
      elt->_driverType = RM_DRV_HUMAN;
      std::string strNetPlayer = GfParmGetStr(robhdle, path, "networkrace", "no");
      elt->_networkPlayer = (strNetPlayer == "yes") ? 1 : 0;
    }

    elt->index = carindex;
    elt->robot = curRobot;
    elt->_paramsHandle = robhdle;
    elt->_driverIndex = robotIdx;
    elt->_moduleIndex = relativeRobotIdx;
    strncpy(elt->_modName, cardllname, MAX_NAME_LEN - 1);
    elt->_modName[MAX_NAME_LEN - 1] = 0;

    //snprintf(path, sizeof(path), "%s/%s/%d", ROB_SECT_ROBOTS, ROB_LIST_INDEX, robotIdx);
    snprintf( path2, sizeof(path2), "%s/%s/%d/%d", RM_SECT_DRIVERINFO, elt->_modName, normal_carname ? 0 : 1, elt->_moduleIndex );
    if (normal_carname || elt->_driverType == RM_DRV_HUMAN) {
      strncpy(elt->_name, GfParmGetStr(robhdle, path, ROB_ATTR_NAME, "none"), MAX_NAME_LEN - 1);
      strncpy(elt->_sname, GfParmGetStr(robhdle, path, ROB_ATTR_SNAME, "none"), MAX_NAME_LEN - 1);
      strncpy(elt->_cname, GfParmGetStr(robhdle, path, ROB_ATTR_CODE, "---"), 3);
    } else {
      strncpy(elt->_name, GfParmGetStr(ReInfo->params, path2, ROB_ATTR_NAME, "none"), MAX_NAME_LEN - 1);
      strncpy(elt->_sname, GfParmGetStr(ReInfo->params, path2, ROB_ATTR_SNAME, "none"), MAX_NAME_LEN - 1);
      strncpy(elt->_cname, GfParmGetStr(ReInfo->params, path2, ROB_ATTR_CODE, "---"), 3);
    }
    elt->_name[MAX_NAME_LEN - 1] = 0;
    elt->_sname[MAX_NAME_LEN - 1] = 0;
    elt->_cname[3] = 0;

    teamname = GfParmGetStr(robhdle, path, ROB_ATTR_TEAM, "none");
    teamname = GfParmGetStr(ReInfo->params, path2, ROB_ATTR_TEAM, teamname ); //Use the name in params if it has a team name
    strncpy(elt->_teamname, teamname, MAX_NAME_LEN - 1);
    elt->_teamname[MAX_NAME_LEN - 1] = 0;

    elt->_driveSkill = GfParmGetNum(ReInfo->params, path2, RM_ATTR_SKILLLEVEL, NULL, -1.0f);

    if (normal_carname) /* Even if we get a normal_carname for humans we use it despite of forced extended mode*/
      strncpy(elt->_carName, GfParmGetStr(robhdle, path, ROB_ATTR_CAR, ""), MAX_NAME_LEN - 1);
    else
      strncpy(elt->_carName, GfParmGetStr(ReInfo->params, path2, RM_ATTR_CARNAME, ""), MAX_NAME_LEN - 1);
    elt->_carName[MAX_NAME_LEN - 1] = 0; /* XML file name */

    // Load custom skin name and targets from race info (if specified).
    snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, listindex);
    if (GfParmGetStr(ReInfo->params, path2, RM_ATTR_SKINNAME, 0))
    {
      strncpy(elt->_skinName, GfParmGetStr(ReInfo->params, path2, RM_ATTR_SKINNAME, ""), MAX_NAME_LEN - 1);
      elt->_skinName[MAX_NAME_LEN - 1] = 0; // Texture name
    }
	elt->_skinTargets = (int)GfParmGetNum(ReInfo->params, path2, RM_ATTR_SKINTARGETS, (char*)NULL, 0);
	
    // Load other data from robot descriptor.
    elt->_raceNumber = (int)GfParmGetNum(robhdle, path, ROB_ATTR_RACENUM, (char*)NULL, 0);
    if (!normal_carname && elt->_driverType != RM_DRV_HUMAN) // Increase racenumber if needed
      elt->_raceNumber += elt->_moduleIndex;
    elt->_skillLevel = 0;
    str = GfParmGetStr(robhdle, path, ROB_ATTR_LEVEL, ROB_VAL_SEMI_PRO);
    for(k = 0; k < NSkillLevels; k++) {
      if (strcmp(aPszSkillLevelNames[k], str) == 0) {
        elt->_skillLevel = k;
        break;
      }
    }
    elt->_startRank  = carindex;
    elt->_pos        = carindex+1;
    elt->_remainingLaps = ReInfo->s->_totLaps;

    elt->_newTrackMemPool = NULL;
    elt->_newRaceMemPool = NULL;
    elt->_endRaceMemPool = NULL;
    elt->_shutdownMemPool = NULL;

	carname = elt->_carName;

    GfLogTrace("Driver #%d(%d) : module='%s', name='%s', car='%s', cat='%s', skin='%s' on %x\n",
			   carindex, listindex, elt->_modName, elt->_name, elt->_carName,
			   elt->_category, elt->_skinName, elt->_skinTargets);

    if ((strncmp(carname.c_str(), "mpa1", 4) == 0))
	{
		if (strcmp(subcategory, "long") == 0)
			carname = carname+"-long";
		else if (strcmp(subcategory, "short") == 0)
			carname = carname+"-short";
		else 
			carname = carname+"-road";

		GfLogTrace("MPA... Category car = %s \n", carname.c_str());

		/* Retrieve and load car specs : merge car default specs,
		category specs and driver modifications (=> handle) */
		/* Read Car model specifications */
		snprintf(buf, sizeof(buf), "cars/models/%s/%s.xml", elt->_carName, carname.c_str());
		carhdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);

	}
	else
	{  
		/* Retrieve and load car specs : merge car default specs,
		category specs and driver modifications (=> handle) */
		/* Read Car model specifications */
		snprintf(buf, sizeof(buf), "cars/models/%s/%s.xml", elt->_carName, elt->_carName);
		carhdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
	}

    category = GfParmGetStr(carhdle, SECT_CAR, PRM_CATEGORY, NULL);
    if (category)
    {
	  GfLogTrace("Checking/Merging %s specs into %s base setup for %s ...\n",
				 category, elt->_carName, curModInfo->name);
      strncpy(elt->_category, category, MAX_NAME_LEN - 1);
      elt->_category[MAX_NAME_LEN - 1] = 0;
      /* Read Car Category specifications */
      snprintf(buf2, sizeof(buf2), "cars/categories/%s.xml", elt->_category);
      cathdle = GfParmReadFile(buf2, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
	  int errorcode = 0;

      if ((errorcode = GfParmCheckHandle(cathdle, carhdle))) 
	  {
        switch (errorcode)
		{
		  case -1:
            GfLogError("Car %s NOT in category %s (driver %s) !!!\n", elt->_carName, category, elt->_name);
		    break;

		  case -2:
            GfLogError("Parameters out of bound for car %s (driver %s)!!!\n",elt->_carName, elt->_name);
		    break;

		  case -3:
            GfLogError("Parameter not allowed for car %s (driver %s)!!!\n",elt->_carName, elt->_name);
		    break;

		  default:
            GfLogError("Unknown error for %s (driver %s)!!!\n",elt->_carName, elt->_name);
		    break;
	    } 
        return NULL;
      }

      carhdle = GfParmMergeHandles(cathdle, carhdle,
                                   GFPARM_MMODE_SRC | GFPARM_MMODE_DST | GFPARM_MMODE_RELSRC | GFPARM_MMODE_RELDST);
	  
      /* The code below stores the carnames to a separate xml-file
		 such that at newTrack it is known which car is used.
		 TODO: find a better method for this */
      snprintf (buf, sizeof(buf), "%sdrivers/curcarnames.xml", GfLocalDir());
      handle = GfParmReadFile(buf, GFPARM_RMODE_CREAT);
      if (handle) {
        snprintf(path, sizeof(path), "drivers/%s/%d", cardllname, elt->_driverIndex);
        GfParmSetStr (handle, path, RM_ATTR_CARNAME, elt->_carName);
        GfParmWriteFile (0, handle, "Car names");
        GfParmReleaseHandle (handle);
      }
      if (!(ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU))
      {
        GfPoolMove(&elt->_newTrackMemPool, &oldPool);
        curRobot->rbNewTrack(elt->_driverIndex, ReInfo->track, carhdle, &handle, ReInfo->s);
        GfPoolFreePool( &oldPool );
      }
      else
        handle = NULL;
      if (handle && !replayReplay) {
		GfLogTrace("Checking/Merging %s specific setup into %s setup.\n",
				   curModInfo->name, elt->_carName);
        if (GfParmCheckHandle(carhdle, handle)) {
          GfLogError("Bad Car parameters for driver %s\n", elt->_name);
          return NULL;
        }
        handle = GfParmMergeHandles(carhdle, handle,
                                    GFPARM_MMODE_SRC | GFPARM_MMODE_DST | GFPARM_MMODE_RELSRC | GFPARM_MMODE_RELDST);
      } else {
		GfLogTrace("Keeping %s setup as is for %s (no specific setup).\n",
				   elt->_carName, curModInfo->name);
		handle = carhdle;
      }
      elt->_carHandle = handle;

      /* Initialize sectors */
      elt->_currentSector = 0;
      elt->_curSplitTime = (double*)malloc( sizeof(double) * ( ReInfo->track->numberOfSectors - 1 ) );
      elt->_bestSplitTime = (double*)malloc( sizeof(double) * ( ReInfo->track->numberOfSectors - 1 ) );
      for (xx = 0; xx < ReInfo->track->numberOfSectors - 1; ++xx)
      {
        elt->_curSplitTime[xx] = -1.0f;
        elt->_bestSplitTime[xx] = -1.0f;
      }
    } else {
      elt->_category[ 0 ] = '\0';
      GfLogError("Bad Car category for driver %s\n", elt->_name);
      return NULL;
    }

    return elt;
  } else {
    GfLogError("No description file for robot %s\n", cardllname);
  }
  return NULL;
}


/** Initialize the cars for a race.
    The cars are positionned on the starting grid.
    @return 0 Ok, -1 Error
 */
int
ReInitCars(void)
{
  char buf[512];
  char path[512];
  int nCars;
  int index;
  int i, j;
  const char *robotModuleName;
  int robotIdx;
  void *robhdle;
  tCarElt *elt;
  //const char *focused; // Never used.
  //int focusedIdx; // Never used.
  void *params = ReInfo->params;

  /* Get the number of cars (= drivers) racing */
  nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS_RACING);
  GfLogTrace("Loading %d car(s)\n", nCars);

  FREEZ(ReInfo->carList);
  ReInfo->carList = (tCarElt*)calloc(nCars, sizeof(tCarElt));
  FREEZ(ReInfo->rules);
  ReInfo->rules = (tRmCarRules*)calloc(nCars, sizeof(tRmCarRules));
  //focused = GfParmGetStr(ReInfo->params, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, "");
  //focusedIdx = (int)GfParmGetNum(ReInfo->params, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, NULL, 0);
  index = 0;

  /* For each car/driver : */
  for (i = 1; i < nCars + 1; i++) 
  {
    /* Get the name of the module (= shared library) of the robot */
    snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS_RACING, i);
    robotModuleName = GfParmGetStr(ReInfo->params, path, RM_ATTR_MODULE, "");
    robotIdx = (int)GfParmGetNum(ReInfo->params, path, RM_ATTR_IDX, NULL, 0);

#if 0 // SDW
    if (replayReplay)
      // Register against the Replay driver
      snprintf(path, sizeof(path), "%sdrivers/replay/replay.%s", GfLibDir(), DLLEXT);
    else
#endif
      snprintf(path, sizeof(path), "%sdrivers/%s/%s.%s", GfLibDir(), robotModuleName, robotModuleName, DLLEXT);

    /* Load the robot shared library */
    if (GfModLoad(CAR_IDENT, path, ReInfo->robModList)) 
    {
      GfLogError("Failed to load robot module %s\n", path);
      continue;
    }

    /* Load the racing driver info in the race data structure */
    elt = NULL;
    snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS_RACING, i);
    if ((int)GfParmGetNum(ReInfo->params, path, RM_ATTR_EXTENDED, NULL, 0) == 0) 
    {
      /* Search for the index of the racing driver in the list of interfaces
         of the module */
      for (j = 0; j < (*(ReInfo->robModList))->modInfoSize; j++) 
      {
        if ((*(ReInfo->robModList))->modInfo[j].name && (*(ReInfo->robModList))->modInfo[j].index == robotIdx) 
        {
          /* We have the right driver : load it */
          elt = reLoadSingleCar( index, i, j, robotIdx, TRUE, robotModuleName );
          if (!elt)
		  {
            GfLogError("No descriptor file for robot %s or parameter errors (1)\n", robotModuleName);
			snprintf(buf, sizeof(buf), "Error: May be no driver, or some parameters are out of bound");
	        ReUI().addLoadingMessage(buf);
			snprintf(buf, sizeof(buf), "       Have a look at the console window for mode details about the error");
	        ReUI().addLoadingMessage(buf);
			snprintf(buf, sizeof(buf), "       Back to the config menu in 10 s ...");
	        ReUI().addLoadingMessage(buf);
			
			// Wait some time to allow the user to read the message!
            GfSleep(10.0); // 10 seconds
		  }
        }
      }
    }
    else 
    {
      GfLogTrace("Loading robot %s descriptor file\n", robotModuleName );
      snprintf(buf, sizeof(buf), "%sdrivers/%s/%s.xml", GfLocalDir(), robotModuleName, robotModuleName);
      robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
      if (!robhdle) 
      {
        snprintf(buf, sizeof(buf), "drivers/%s/%s.xml", robotModuleName, robotModuleName);
        robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
      }
      if (robhdle && ( strcmp( robotModuleName, "human" ) == 0 || strcmp( robotModuleName, "networkhuman" ) == 0 ) )
      {
        /* Human driver */
        elt = reLoadSingleCar( index, i, robotIdx - (*(ReInfo->robModList))->modInfo[0].index, robotIdx, FALSE, robotModuleName );
      }
      else if (robhdle && ( strcmp( GfParmGetStr( robhdle, ROB_SECT_ARBITRARY, ROB_ATTR_TEAM, "foo" ),
                              GfParmGetStr( robhdle, ROB_SECT_ARBITRARY, ROB_ATTR_TEAM, "bar" ) ) == 0 ) )
      {
        elt = reLoadSingleCar( index, i, (*(ReInfo->robModList))->modInfoSize, robotIdx, FALSE, robotModuleName );
      }
      else
        GfLogError("No descriptor for robot %s (2)\n", robotModuleName );
    }

    if (elt)
      ++index;
  }

  nCars = index; /* real number of cars */
  if (nCars == 0) 
  {
    GfLogError("No driver for that race ; exiting ...\n");
    return -1;
  }
  else 
  {
    GfLogInfo("%d driver(s) ready to race\n", nCars);
  }

  if (replayReplay)
    replayRecord = 0;
  else {
        char buf[1024];
	const char *replayRateSchemeName;
        snprintf(buf, sizeof(buf), "%s%s", GfLocalDir(), RACE_ENG_CFG);

        void *paramHandle = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT);
        replayRateSchemeName = GfParmGetStr(paramHandle, RM_SECT_RACE_ENGINE, RM_ATTR_REPLAY_RATE, "0");
        GfParmReleaseHandle(paramHandle);

	replayRecord = atoi(replayRateSchemeName);
  }

  if (replayRecord || replayReplay) {
#ifdef THIRD_PARTY_SQLITE3
    int result;

    result = sqlite3_open("/tmp/race.sqlite", &replayDB);
    if (result) {
      GfLogError("Replay: Unable to open Database: %s\n", sqlite3_errmsg(replayDB));
      sqlite3_close(replayDB);
      replayDB = NULL;
    } else {
      GfLogInfo("Replay: Database Opened 0x8%8.8X\n", replayDB);

      if (replayRecord)
        GfLogInfo("Replay: Record Timestep = %f\n", 1/(float)replayRecord);

      if (replayReplay)
        GfLogInfo("Replay: Playback from file\n");

      /* speed up database by turning of synchronous behaviour/etc */
      sqlite3_exec(replayDB, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
      sqlite3_exec(replayDB, "PRAGMA journal_mode = OFF", NULL, NULL, NULL);
      sqlite3_exec(replayDB, "PRAGMA count_changes = OFF", NULL, NULL, NULL);
#if 0 // This pragma seems to prevent re-opening the sqlite3 database
      sqlite3_exec(replayDB, "PRAGMA locking_mode = EXCLUSIVE", NULL, NULL, NULL);
#endif
      sqlite3_exec(replayDB, "PRAGMA default_temp_store = MEMORY", NULL, NULL, NULL);

      //replayBlobs = (sqlite3_stmt *) calloc(nCars, sizeof(void *)); //sqlite3_stmt));

      replayTimestamp = -5;
      ghostcarActive = 0;
    }
#endif
  }

  ReInfo->s->_ncars = nCars;
  FREEZ(ReInfo->s->cars);
  ReInfo->s->cars = (tCarElt **)calloc(nCars, sizeof(tCarElt *));
  for (i = 0; i < nCars; i++)
  {
    ReInfo->s->cars[i] = &(ReInfo->carList[i]);

#ifdef THIRD_PARTY_SQLITE3
    //open a table for each car
    if (replayDB) {
      char command[200];
      int result;

      if (replayRecord) {
        sprintf(command, "DROP TABLE IF EXISTS car%d", i);
        result = sqlite3_exec(replayDB, command, 0, 0, 0);
        if (result) GfLogInfo("Replay: Unable to drop table car%d: %s\n", i, sqlite3_errmsg(replayDB));
      }

      sprintf(command, "CREATE TABLE IF NOT EXISTS car%d (timestamp, lap, datablob BLOB)", i);
      result = sqlite3_exec(replayDB, command, 0, 0, 0);
      if (result) {
         GfLogInfo("Replay: Unable to create table car%d: %s\n", i, sqlite3_errmsg(replayDB));
         exit(0);
      }

      if (replayReplay) {
        // Build index to allow faster read access
        sprintf(command, "CREATE UNIQUE INDEX IF NOT EXISTS index%d ON car%d (timestamp)", i, i);
        result = sqlite3_exec(replayDB, command, 0, 0, 0);
        if (result) GfLogInfo("Replay: Unable to create index car%d: %s\n", i, sqlite3_errmsg(replayDB));
      }
    }
#endif
  }

  ReInfo->_rePitRequester = 0;

  // TODO: reconsider splitting the call into one for cars, track and maybe other objects.
  // I stuff for now anything into one call because collision detection works with the same
  // library on all objects, so it is a bit dangerous to distribute the handling to various
  // locations (because the library maintains global state like a default collision handler etc.).
  RePhysicsEngine().initialize(nCars, ReInfo->track);

  initStartingGrid();

  initPits();

  return 0;
}
Beispiel #21
0
// Resume the previously restored race from a results file
void
ReResumeRace()
{
	ReUI().onRaceResuming();
}
Beispiel #22
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;
}