709 lines
26 KiB
C++
709 lines
26 KiB
C++
/***************************************************************************
|
|
|
|
file : raceresults.cpp
|
|
created : Thu Jan 2 12:43:10 CET 2003
|
|
copyright : (C) 2002 by Eric Espie
|
|
email : eric.espie@torcs.org
|
|
version : $Id$
|
|
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
/** @file
|
|
Results managment for all race types
|
|
@author <a href=mailto:eric.espie@torcs.org>Eric Espie</a>
|
|
@version $Id$
|
|
*/
|
|
|
|
#include <ctime>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
#include <portability.h>
|
|
#include <robot.h>
|
|
|
|
#include "raceengine.h"
|
|
|
|
#include "racesituation.h"
|
|
#include "racestate.h"
|
|
#include "raceresults.h"
|
|
|
|
|
|
static const char *aSessionTypeNames[3] = {"Practice", "Qualifications", "Race"};
|
|
|
|
static char buf[1024];
|
|
static char path[1024];
|
|
static char path2[1024];
|
|
|
|
|
|
typedef struct
|
|
{
|
|
std::string drvName;
|
|
std::string modName;
|
|
std::string carName;
|
|
int extended;
|
|
int drvIdx;
|
|
int points;
|
|
} tReStandings;
|
|
|
|
|
|
void
|
|
ReInitResults(void)
|
|
{
|
|
struct tm *stm;
|
|
time_t t;
|
|
void *results;
|
|
|
|
t = time(NULL);
|
|
stm = localtime(&t);
|
|
snprintf(buf, sizeof(buf), "%sresults/%s/results-%4d-%02d-%02d-%02d-%02d.xml",
|
|
GfLocalDir(),
|
|
ReInfo->_reFilename,
|
|
stm->tm_year+1900,
|
|
stm->tm_mon+1,
|
|
stm->tm_mday,
|
|
stm->tm_hour,
|
|
stm->tm_min);
|
|
|
|
ReInfo->results = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
|
|
ReInfo->mainResults = ReInfo->results;
|
|
results = ReInfo->results;
|
|
GfParmSetNum(results, RE_SECT_HEADER, RE_ATTR_DATE, NULL, (tdble)t);
|
|
GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_TRACK, NULL, 1);
|
|
GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_RACE, NULL, 1);
|
|
GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, 1);
|
|
}
|
|
|
|
void
|
|
ReEventInitResults(void)
|
|
{
|
|
void *results = ReInfo->results;
|
|
void *params = ReInfo->params;
|
|
|
|
const int nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS);
|
|
for (int i = 1; i < nCars + 1; i++)
|
|
{
|
|
snprintf(path, sizeof(path), "%s/%s/%d", ReInfo->track->name, RM_SECT_DRIVERS, i);
|
|
snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS, i);
|
|
GfParmSetStr(results, path, RE_ATTR_DLL_NAME,
|
|
GfParmGetStr(params, path2, RM_ATTR_MODULE, ""));
|
|
GfParmSetNum(results, path, RE_ATTR_INDEX, NULL,
|
|
GfParmGetNum(params, path2, RM_ATTR_IDX, (char*)NULL, 0));
|
|
GfParmSetNum(results, path, RM_ATTR_EXTENDED, NULL,
|
|
GfParmGetNum(params, path2, RM_ATTR_EXTENDED, (char*)NULL, 0));
|
|
//GfParmSetStr(results, path, ROB_ATTR_NAME,
|
|
// GfParmGetStr(params, path2, ROB_ATTR_NAME, ""));
|
|
//GfParmSetStr(results, path, ROB_ATTR_CAR,
|
|
// GfParmGetStr(params, path2, ROB_ATTR_CAR, ""));
|
|
}
|
|
}
|
|
|
|
|
|
//for sort()
|
|
inline bool sortByScore(const tReStandings& a, const tReStandings& b)
|
|
{
|
|
return (a.points > b.points);
|
|
}
|
|
|
|
//for find()
|
|
inline bool operator ==(const tReStandings& a, const std::string b)
|
|
{
|
|
return !a.drvName.compare(b);
|
|
}
|
|
|
|
void
|
|
ReUpdateStandings(void)
|
|
{
|
|
tReStandings st;
|
|
std::string drvName;
|
|
std::vector<tReStandings> *standings;
|
|
std::vector<tReStandings>::iterator found;
|
|
std::vector<tReStandings>::iterator it;
|
|
int runDrv, curDrv;
|
|
int i;
|
|
void *results = ReInfo->results;
|
|
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, ReInfo->_reRaceName, RE_SECT_RANK);
|
|
runDrv = GfParmGetEltNb(results, path);
|
|
curDrv = GfParmGetEltNb(results, RE_SECT_STANDINGS);
|
|
|
|
standings = new std::vector<tReStandings>;
|
|
|
|
standings->reserve(curDrv);
|
|
|
|
/* Read the current standings */
|
|
for (i = 0; i < curDrv; i++)
|
|
{
|
|
snprintf(path2, sizeof(path2), "%s/%d", RE_SECT_STANDINGS, i + 1);
|
|
st.drvName = GfParmGetStr(results, path2, RE_ATTR_NAME, 0);
|
|
st.modName = GfParmGetStr(results, path2, RE_ATTR_MODULE, 0);
|
|
st.carName = GfParmGetStr(results, path2, RE_ATTR_CAR, 0);
|
|
st.extended = (int)GfParmGetNum(results, path2, RM_ATTR_EXTENDED, NULL, 0);
|
|
st.drvIdx = (int)GfParmGetNum(results, path2, RE_ATTR_IDX, NULL, 0);
|
|
st.points = (int)GfParmGetNum(results, path2, RE_ATTR_POINTS, NULL, 0);
|
|
standings->push_back(st);
|
|
}//for i
|
|
|
|
//Void the stored results
|
|
GfParmListClean(results, RE_SECT_STANDINGS);
|
|
|
|
//Check last races' drivers and search their name in the results.
|
|
//If found there, adds recent points.
|
|
//If not found, adds the driver
|
|
for (i = 0; i < runDrv; i++) {
|
|
//Search the driver name in the standings
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, ReInfo->_reRaceName, RE_SECT_RANK, i + 1);
|
|
drvName = GfParmGetStr(results, path, RE_ATTR_NAME, 0);
|
|
found = std::find(standings->begin(), standings->end(), drvName);
|
|
|
|
if(found == standings->end()) {
|
|
//No such driver in the standings, let's add it
|
|
st.drvName = drvName;
|
|
st.modName = GfParmGetStr(results, path, RE_ATTR_MODULE, 0);
|
|
st.carName = GfParmGetStr(results, path, RE_ATTR_CAR, 0);
|
|
st.extended = (int)GfParmGetNum(results, path, RM_ATTR_EXTENDED, NULL, 0);
|
|
st.drvIdx = (int)GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0);
|
|
st.points = (int)GfParmGetNum(results, path, RE_ATTR_POINTS, NULL, 0);
|
|
standings->push_back(st);
|
|
} else {
|
|
//Driver found, add recent points
|
|
found->points += (int)GfParmGetNum(results, path, RE_ATTR_POINTS, NULL, 0);
|
|
}//if found
|
|
}//for i
|
|
|
|
//sort standings by score
|
|
std::sort(standings->begin(), standings->end(), sortByScore);
|
|
|
|
//Store the standing back
|
|
for(it = standings->begin(), i = 0; it != standings->end(); ++it, ++i) {
|
|
snprintf(path, sizeof(path), "%s/%d", RE_SECT_STANDINGS, i + 1);
|
|
GfParmSetStr(results, path, RE_ATTR_NAME, it->drvName.c_str());
|
|
GfParmSetStr(results, path, RE_ATTR_MODULE, it->modName.c_str());
|
|
GfParmSetStr(results, path, RE_ATTR_CAR, it->carName.c_str());
|
|
GfParmSetNum(results, path, RE_ATTR_IDX, NULL, (tdble)it->drvIdx);
|
|
GfParmSetNum(results, path, RE_ATTR_POINTS, NULL, (tdble)it->points);
|
|
}//for it
|
|
delete standings;
|
|
|
|
char str1[512], str2[512];
|
|
snprintf(str1, sizeof(str1), "%sconfig/params.dtd", GfDataDir());
|
|
snprintf(str2, sizeof(str2), "<?xml-stylesheet type=\"text/xsl\" href=\"file:///%sconfig/raceresults.xsl\"?>", GfDataDir());
|
|
|
|
GfParmSetDTD (results, str1, str2);
|
|
GfParmWriteFile(0, results, "Results");
|
|
}//ReUpdateStandings
|
|
|
|
void ReCalculateClassPoints(char const *race)
|
|
{
|
|
double points;
|
|
char *path3;
|
|
int rank = 1;
|
|
int count;
|
|
|
|
snprintf(buf, sizeof(buf), "%s/%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, ReInfo->_reRaceName, RE_SECT_RANK);
|
|
path3 = strdup(buf);
|
|
if (GfParmListSeekFirst(ReInfo->results, path3) != 0)
|
|
{
|
|
free(path3);
|
|
return; /* No result found */
|
|
}
|
|
count = GfParmGetEltNb(ReInfo->results, path3);
|
|
do {
|
|
snprintf( path2, sizeof(path2), "%s/%s", race, RM_SECT_CLASSPOINTS );
|
|
if (GfParmListSeekFirst( ReInfo->params, path2 ) != 0) {
|
|
GfLogDebug( "ReCalculateClassPoints: First not found in %s)\n", path2 );
|
|
continue;
|
|
}
|
|
do {
|
|
snprintf( buf, sizeof(buf), "%s/%s", path2, GfParmListGetCurEltName( ReInfo->params, path2 ) );
|
|
snprintf( path, sizeof(path), "%s/%s/%d/%d/%s", RE_SECT_CLASSPOINTS,
|
|
GfParmGetCurStr (ReInfo->results, path3, RE_ATTR_MODULE, ""),
|
|
(int)GfParmGetCurNum (ReInfo->results, path3, RM_ATTR_EXTENDED, NULL, 0),
|
|
(int)GfParmGetCurNum (ReInfo->results, path3, RE_ATTR_IDX, NULL, 0),
|
|
GfParmGetStr( ReInfo->params, buf, RM_ATTR_SUFFIX, "" ) );
|
|
points = GfParmGetNum (ReInfo->results, path, RE_ATTR_POINTS, NULL, 0);
|
|
GfParmSetVariable (ReInfo->params, buf, "pos", (tdble)rank);
|
|
GfParmSetVariable (ReInfo->params, buf, "cars", (tdble)count);
|
|
//GfLogDebug( "ReCalculateClassPoints: pos = %d; count = %d\n", rank, count);
|
|
//GfLogDebug( "ReCalculateClassPoints: GfParmGetNum (..., %s, %s, NULL, 0)\n", buf, RM_ATTR_POINTS );
|
|
points += ( GfParmGetNum (ReInfo->params, buf, RM_ATTR_POINTS, NULL, 0) /
|
|
GfParmGetNum (ReInfo->params, RM_SECT_TRACKS, RM_ATTR_NUMBER, NULL, 1) );
|
|
GfParmRemoveVariable (ReInfo->params, buf, "pos");
|
|
GfParmRemoveVariable (ReInfo->params, buf, "cars");
|
|
GfParmSetNum (ReInfo->results, path, RE_ATTR_POINTS, NULL, (tdble)points);
|
|
} while (GfParmListSeekNext( ReInfo->params, path2 ) == 0);
|
|
++rank;
|
|
} while (GfParmListSeekNext (ReInfo->results, path3) == 0);
|
|
free(path3);
|
|
}
|
|
|
|
void
|
|
ReStoreRaceResults(const char *race)
|
|
{
|
|
int i;
|
|
int nCars;
|
|
tCarElt *car;
|
|
tSituation *s = ReInfo->s;
|
|
char *carName;
|
|
void *carparam;
|
|
void *results = ReInfo->results;
|
|
void *params = ReInfo->params;
|
|
|
|
/* Store the number of laps of the race */
|
|
switch (ReInfo->s->_raceType) {
|
|
case RM_TYPE_RACE:
|
|
car = s->cars[0];
|
|
if (car->_laps > s->_totLaps) car->_laps = s->_totLaps + 1;
|
|
|
|
snprintf(path, sizeof(path), "%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, race);
|
|
GfParmListClean(results, path);
|
|
GfParmSetNum(results, path, RE_ATTR_LAPS, NULL, (tdble)(car->_laps - 1));
|
|
|
|
for (i = 0; i < s->_ncars; i++) {
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i + 1);
|
|
car = s->cars[i];
|
|
if (car->_laps > s->_totLaps)
|
|
car->_laps = s->_totLaps + 1;
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_NAME, car->_name);
|
|
|
|
snprintf(buf, sizeof(buf), "cars/%s/%s.xml", car->_carName, car->_carName);
|
|
carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
|
|
carName = GfParmGetName(carparam);
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_CAR, carName);
|
|
GfParmSetNum(results, path, RE_ATTR_INDEX, NULL, (tdble)car->index);
|
|
|
|
GfParmSetNum(results, path, RE_ATTR_LAPS, NULL, (tdble)(car->_laps - 1));
|
|
GfParmSetNum(results, path, RE_ATTR_TIME, NULL, (tdble)car->_curTime);
|
|
GfParmSetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, (tdble)car->_bestLapTime);
|
|
GfParmSetNum(results, path, RE_ATTR_TOP_SPEED, NULL, car->_topSpeed);
|
|
GfParmSetNum(results, path, RE_ATTR_DAMMAGES, NULL, (tdble)car->_dammage);
|
|
GfParmSetNum(results, path, RE_ATTR_NB_PIT_STOPS, NULL, (tdble)car->_nbPitStops);
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_MODULE, car->_modName);
|
|
GfParmSetNum(results, path, RE_ATTR_IDX, NULL, (tdble)car->_moduleIndex);
|
|
snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, car->index + 1 );
|
|
GfParmSetNum(results, path, RM_ATTR_EXTENDED, NULL,
|
|
GfParmGetNum(params, path2, RM_ATTR_EXTENDED, NULL, 0));
|
|
GfParmSetStr(results, path, ROB_ATTR_CAR, car->_carName);
|
|
snprintf(path2, sizeof(path2), "%s/%s/%d", race, RM_SECT_POINTS, i + 1);
|
|
GfParmSetNum(results, path, RE_ATTR_POINTS, NULL,
|
|
GfParmGetNum(params, path2, RE_ATTR_POINTS, NULL, 0));
|
|
if (strlen(car->_skinName) > 0)
|
|
GfParmSetStr(results, path, RM_ATTR_SKINNAME, car->_skinName);
|
|
GfParmSetNum(results, path, RM_ATTR_SKINTARGETS, NULL, (tdble)car->_skinTargets);
|
|
|
|
GfParmReleaseHandle(carparam);
|
|
}
|
|
break;
|
|
|
|
case RM_TYPE_PRACTICE:
|
|
if (s->_ncars == 1)
|
|
{
|
|
car = s->cars[0];
|
|
snprintf(path, sizeof(path), "%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, race);
|
|
GfParmSetStr(results, path, RM_ATTR_DRVNAME, car->_name);
|
|
snprintf(buf, sizeof(buf), "cars/%s/%s.xml", car->_carName, car->_carName);
|
|
carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
|
|
carName = GfParmGetName(carparam);
|
|
GfParmSetStr(results, path, RE_ATTR_CAR, carName);
|
|
GfParmReleaseHandle(carparam);
|
|
break;
|
|
}
|
|
/* Otherwise, fall through */
|
|
|
|
case RM_TYPE_QUALIF:
|
|
if (s->_ncars == 1)
|
|
{
|
|
car = s->cars[0];
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK);
|
|
nCars = GfParmGetEltNb(results, path);
|
|
for (i = nCars; i > 0; i--) {
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i);
|
|
float opponentBestLapTime = GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0);
|
|
|
|
if (car->_bestLapTime != 0.0
|
|
&& (car->_bestLapTime < opponentBestLapTime || opponentBestLapTime == 0.0))
|
|
{
|
|
/* shift */
|
|
snprintf(path2, sizeof(path2), "%s/%s/%s/%s/%d",
|
|
ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i + 1);
|
|
GfParmSetStr(results, path2, RE_ATTR_NAME,
|
|
GfParmGetStr(results, path, RE_ATTR_NAME, ""));
|
|
GfParmSetStr(results, path2, RE_ATTR_CAR,
|
|
GfParmGetStr(results, path, RE_ATTR_CAR, ""));
|
|
GfParmSetNum(results, path2, RE_ATTR_BEST_LAP_TIME, NULL,
|
|
GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0));
|
|
GfParmSetStr(results, path2, RE_ATTR_MODULE,
|
|
GfParmGetStr(results, path, RM_ATTR_MODULE, ""));
|
|
GfParmSetNum(results, path2, RE_ATTR_IDX, NULL,
|
|
GfParmGetNum(results, path, RM_ATTR_IDX, NULL, 0));
|
|
GfParmSetNum(results, path2, RM_ATTR_EXTENDED, NULL,
|
|
GfParmGetNum(results, path, RM_ATTR_EXTENDED, NULL, 0));
|
|
GfParmSetStr(results, path2, ROB_ATTR_CAR,
|
|
GfParmGetStr(results, path, ROB_ATTR_CAR, ""));
|
|
GfParmSetStr(results, path2, ROB_ATTR_NAME,
|
|
GfParmGetStr(results, path, ROB_ATTR_NAME, ""));
|
|
snprintf(path, sizeof(path), "%s/%s/%d", race, RM_SECT_POINTS, i + 1);
|
|
GfParmSetNum(results, path2, RE_ATTR_POINTS, NULL,
|
|
GfParmGetNum(params, path, RE_ATTR_POINTS, NULL, 0));
|
|
if (GfParmGetStr(results, path, RM_ATTR_SKINNAME, 0))
|
|
GfParmSetStr(results, path2, RM_ATTR_SKINNAME,
|
|
GfParmGetStr(results, path, RM_ATTR_SKINNAME, 0));
|
|
GfParmSetNum(results, path2, RM_ATTR_SKINTARGETS, NULL,
|
|
GfParmGetNum(results, path, RM_ATTR_SKINTARGETS, NULL, 0));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
/* insert after */
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i + 1);
|
|
GfParmSetStr(results, path, RE_ATTR_NAME, car->_name);
|
|
|
|
snprintf(buf, sizeof(buf), "cars/%s/%s.xml", car->_carName, car->_carName);
|
|
carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
|
|
carName = GfParmGetName(carparam);
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_CAR, carName);
|
|
GfParmSetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, (tdble)car->_bestLapTime);
|
|
GfParmSetStr(results, path, RE_ATTR_MODULE, car->_modName);
|
|
GfParmSetNum(results, path, RE_ATTR_IDX, NULL, (tdble)car->_moduleIndex);
|
|
GfParmSetStr(results, path, ROB_ATTR_CAR, car->_carName);
|
|
GfParmSetStr(results, path, ROB_ATTR_NAME, car->_name);
|
|
snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, car->index + 1 );
|
|
GfParmSetNum(results, path, RM_ATTR_EXTENDED, NULL,
|
|
GfParmGetNum(params, path2, RM_ATTR_EXTENDED, NULL, 0));
|
|
snprintf(path2, sizeof(path2), "%s/%s/%d", race, RM_SECT_POINTS, i + 1);
|
|
GfParmSetNum(results, path, RE_ATTR_POINTS, NULL,
|
|
GfParmGetNum(params, path2, RE_ATTR_POINTS, NULL, 0));
|
|
if (strlen(car->_skinName) > 0)
|
|
GfParmSetStr(results, path, RM_ATTR_SKINNAME, car->_skinName);
|
|
GfParmSetNum(results, path, RM_ATTR_SKINTARGETS, NULL, (tdble)car->_skinTargets);
|
|
|
|
GfParmReleaseHandle(carparam);
|
|
break;
|
|
} else {
|
|
car = s->cars[0];
|
|
|
|
if (s->_totTime < 0.0f)
|
|
GfLogWarning("Saving results of multicar non-race session, but it was not timed!\n" );
|
|
snprintf(path, sizeof(path), "%s/%s/%s", ReInfo->track->name, RE_SECT_RESULTS, race);
|
|
GfParmListClean(results, path);
|
|
GfParmSetNum(results, path, RE_ATTR_SESSIONTIME, NULL, (tdble)s->_totTime);
|
|
|
|
for (i = 0; i < s->_ncars; i++) {
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i + 1);
|
|
car = s->cars[i];
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_NAME, car->_name);
|
|
|
|
snprintf(buf, sizeof(buf), "cars/%s/%s.xml", car->_carName, car->_carName);
|
|
carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
|
|
carName = GfParmGetName(carparam);
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_CAR, carName);
|
|
GfParmSetNum(results, path, RE_ATTR_INDEX, NULL, (tdble)car->index);
|
|
|
|
GfParmSetNum(results, path, RE_ATTR_LAPS, NULL, (tdble)(car->_laps - 1));
|
|
GfParmSetNum(results, path, RE_ATTR_TIME, NULL, (tdble)car->_curTime);
|
|
GfParmSetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, (tdble)car->_bestLapTime);
|
|
GfParmSetNum(results, path, RE_ATTR_TOP_SPEED, NULL, car->_topSpeed);
|
|
GfParmSetNum(results, path, RE_ATTR_DAMMAGES, NULL, (tdble)car->_dammage);
|
|
GfParmSetNum(results, path, RE_ATTR_NB_PIT_STOPS, NULL, (tdble)car->_nbPitStops);
|
|
|
|
GfParmSetStr(results, path, RE_ATTR_MODULE, car->_modName);
|
|
GfParmSetNum(results, path, RE_ATTR_IDX, NULL, (tdble)car->_moduleIndex);
|
|
snprintf(path2, sizeof(path2), "%s/%d", RM_SECT_DRIVERS_RACING, car->index + 1 );
|
|
GfParmSetNum(results, path, RM_ATTR_EXTENDED, NULL,
|
|
GfParmGetNum(params, path2, RM_ATTR_EXTENDED, NULL, 0));
|
|
GfParmSetStr(results, path, ROB_ATTR_CAR, car->_carName);
|
|
snprintf(path2, sizeof(path2), "%s/%s/%d", race, RM_SECT_POINTS, i + 1);
|
|
GfParmSetNum(results, path, RE_ATTR_POINTS, NULL,
|
|
GfParmGetNum(params, path2, RE_ATTR_POINTS, NULL, 0));
|
|
if (strlen(car->_skinName) > 0)
|
|
GfParmSetStr(results, path, RM_ATTR_SKINNAME, car->_skinName);
|
|
GfParmSetNum(results, path, RM_ATTR_SKINTARGETS, NULL, (tdble)car->_skinTargets);
|
|
|
|
GfParmReleaseHandle(carparam);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (%s)",
|
|
ReInfo->s->cars[0]->_name, ReInfo->s->cars[0]->_carName);
|
|
char pszSubTitle[128];
|
|
snprintf(pszSubTitle, sizeof(pszSubTitle), "%s at %s",
|
|
aSessionTypeNames[ReInfo->s->_raceType], ReInfo->track->name);
|
|
ReUI().setResultsTableTitles(pszTitle, pszSubTitle);
|
|
ReUI().setResultsTableHeader(pszTableHeader);
|
|
}
|
|
}//if displayMode != normal
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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/%s/%s.xml", car->_carName, car->_carName);
|
|
carparam = GfParmReadFile(buf, GFPARM_RMODE_STD);
|
|
carName = GfParmGetName(carparam);
|
|
|
|
if (ReInfo->s->_raceType == RM_TYPE_PRACTICE)
|
|
snprintf(buf, sizeof(buf), "%s (%s)", car->_name, carName);
|
|
else
|
|
snprintf(buf, sizeof(buf), "%s (%s) - Lap %d", car->_name, carName, car->_laps);
|
|
char pszSubTitle[128];
|
|
snprintf(pszSubTitle, sizeof(pszSubTitle), "%s at %s",
|
|
aSessionTypeNames[ReInfo->s->_raceType], ReInfo->track->name);
|
|
ReUI().setResultsTableTitles(buf, pszSubTitle);
|
|
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();
|
|
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 );
|
|
}
|
|
char pszSubTitle[128];
|
|
snprintf(pszSubTitle, sizeof(pszSubTitle), "%s at %s",
|
|
aSessionTypeNames[ReInfo->s->_raceType], ReInfo->track->name);
|
|
ReUI().setResultsTableTitles(buf, pszSubTitle);
|
|
ReUI().setResultsTableHeader(pszTableHeader);
|
|
|
|
for (xx = 0; xx < nCars; ++xx) {
|
|
car = ReInfo->s->cars[ xx ];
|
|
snprintf(buf, sizeof(buf), "cars/%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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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();
|
|
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 );
|
|
}
|
|
char pszSubTitle[128];
|
|
snprintf(pszSubTitle, sizeof(pszSubTitle), "%s at %s",
|
|
aSessionTypeNames[ReInfo->s->_raceType], ReInfo->track->name);
|
|
ReUI().setResultsTableTitles(buf, pszSubTitle);
|
|
ReUI().setResultsTableHeader(pszTableHeader);
|
|
|
|
for (xx = 0; xx < ncars; ++xx) {
|
|
car = ReInfo->s->cars[ xx ];
|
|
snprintf(buf, sizeof(buf), "cars/%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);
|
|
}
|
|
}
|
|
|
|
void
|
|
ReSavePracticeLap(tCarElt *car)
|
|
{
|
|
void *results = ReInfo->results;
|
|
tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
|
|
|
|
snprintf(path, sizeof(path), "%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, ReInfo->_reRaceName, car->_laps - 1);
|
|
GfParmSetNum(results, path, RE_ATTR_TIME, NULL, (tdble)car->_lastLapTime);
|
|
GfParmSetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, (tdble)car->_bestLapTime);
|
|
GfParmSetNum(results, path, RE_ATTR_TOP_SPEED, NULL, info->topSpd);
|
|
GfParmSetNum(results, path, RE_ATTR_BOT_SPEED, NULL, info->botSpd);
|
|
GfParmSetNum(results, path, RE_ATTR_DAMMAGES, NULL, (tdble)car->_dammage);
|
|
}
|