/* return state mode */ int ReRaceStart(void) { int i; int nCars; int maxCars; const char *raceName = ReInfo->_reRaceName; void *params = ReInfo->params; void *results = ReInfo->results; const int BUFSIZE = 1024; char path[BUFSIZE], path2[BUFSIZE]; FREEZ(ReInfo->_reCarInfo); ReInfo->_reCarInfo = (tReCarInfo*)calloc(GfParmGetEltNb(params, RM_SECT_DRIVERS), sizeof(tReCarInfo)); /* Drivers starting order */ GfParmListClean(params, RM_SECT_DRIVERS_RACING); if (ReInfo->s->_raceType == RM_TYPE_QUALIF) { i = (int)GfParmGetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, 1); if (i == 1) { RmLoadingScreenStart(ReInfo->_reName, "data/img/splash-qrloading.png"); RmLoadingScreenSetText("Preparing Starting Grid..."); } else { RmShutdownLoadingScreen(); } snprintf(path, BUFSIZE, "%s/%d", RM_SECT_DRIVERS, i); snprintf(path2, BUFSIZE, "%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)); } else { RmLoadingScreenStart(ReInfo->_reName, "data/img/splash-qrloading.png"); RmLoadingScreenSetText("Preparing Starting Grid..."); const char* gridType = GfParmGetStr(params, raceName, RM_ATTR_START_ORDER, RM_VAL_DRV_LIST_ORDER); if (!strcmp(gridType, RM_VAL_LAST_RACE_ORDER)) { /* Starting grid in the arrival of the previous race */ nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS); maxCars = (int)GfParmGetNum(params, raceName, RM_ATTR_MAX_DRV, NULL, 100); nCars = MIN(nCars, maxCars); const char* prevRaceName = ReGetPrevRaceName(); if (!prevRaceName) { return RM_QUIT; } for (i = 1; i < nCars + 1; i++) { snprintf(path, BUFSIZE, "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, prevRaceName, RE_SECT_RANK, i); snprintf(path2, BUFSIZE, "%s/%d", RM_SECT_DRIVERS_RACING, i); GfParmSetStr(params, path2, RM_ATTR_MODULE, GfParmGetStr(results, path, RE_ATTR_MODULE, "")); GfParmSetNum(params, path2, RM_ATTR_IDX, NULL, GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0)); } } else if (!strcmp(gridType, RM_VAL_LAST_RACE_RORDER)) { /* Starting grid in the reversed arrival order of the previous race */ nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS); maxCars = (int)GfParmGetNum(params, raceName, RM_ATTR_MAX_DRV, NULL, 100); nCars = MIN(nCars, maxCars); const char* prevRaceName = ReGetPrevRaceName(); if (!prevRaceName) { return RM_QUIT; } for (i = 1; i < nCars + 1; i++) { snprintf(path, BUFSIZE, "%s/%s/%s/%s/%d", ReInfo->track->name, RE_SECT_RESULTS, prevRaceName, RE_SECT_RANK, nCars - i + 1); snprintf(path2, BUFSIZE, "%s/%d", RM_SECT_DRIVERS_RACING, i); GfParmSetStr(params, path2, RM_ATTR_MODULE, GfParmGetStr(results, path, RE_ATTR_MODULE, "")); GfParmSetNum(params, path2, RM_ATTR_IDX, NULL, GfParmGetNum(results, path, RE_ATTR_IDX, NULL, 0)); } } else { /* Starting grid in the drivers list order */ nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS); maxCars = (int)GfParmGetNum(params, raceName, RM_ATTR_MAX_DRV, NULL, 100); nCars = MIN(nCars, maxCars); for (i = 1; i < nCars + 1; i++) { snprintf(path, BUFSIZE, "%s/%d", RM_SECT_DRIVERS, i); snprintf(path2, BUFSIZE, "%s/%d", RM_SECT_DRIVERS_RACING, i); 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)); } } } if (ReInfo->_displayMode != RM_DISP_MODE_CONSOLE) { if (!strcmp(GfParmGetStr(params, ReInfo->_reRaceName, RM_ATTR_SPLASH_MENU, RM_VAL_NO), RM_VAL_YES)) { RmShutdownLoadingScreen(); RmDisplayStartRace(ReInfo, StartRaceHookInit(), AbandonRaceHookInit()); return RM_ASYNC | RM_NEXT_STEP; } } return reRaceRealStart(); }
void SimEngineConfig(tCar *car) { void *hdle = car->params; int i; tdble maxTq; tdble rpmMaxTq = 0; char idx[64]; tEngineCurveElem *data; struct tEdesc { tdble rpm; tdble tq; } *edesc; car->engine.lastInterval = 0; // Initialize interval car->engine.revsLimiter = GfParmGetNum(hdle, SECT_ENGINE, PRM_REVSLIM, (char*)NULL, 800); car->carElt->_enginerpmRedLine = car->engine.revsLimiter; car->engine.revsMax = GfParmGetNum(hdle, SECT_ENGINE, PRM_REVSMAX, (char*)NULL, 1000); car->carElt->_enginerpmMax = car->engine.revsMax; car->engine.tickover = GfParmGetNum(hdle, SECT_ENGINE, PRM_TICKOVER, (char*)NULL, 150); car->engine.I = GfParmGetNum(hdle, SECT_ENGINE, PRM_INERTIA, (char*)NULL, 0.2423f); car->engine.fuelcons = GfParmGetNum(hdle, SECT_ENGINE, PRM_FUELCONS, (char*)NULL, 0.0622f); car->engine.brakeCoeff = GfParmGetNum(hdle, SECT_ENGINE, PRM_ENGBRKCOEFF, (char*)NULL, 0.05f); car->engine.pressure = 0.0f; car->engine.exhaust_pressure = 0.0f; car->engine.exhaust_refract = 0.1f; car->engine.Tq_response = 0.0f; car->engine.I_joint = car->engine.I; sprintf(idx, "%s/%s", SECT_ENGINE, ARR_DATAPTS); car->engine.curve.nbPts = GfParmGetEltNb(hdle, idx); edesc = (struct tEdesc*)malloc((car->engine.curve.nbPts + 1) * sizeof(struct tEdesc)); for (i = 0; i < car->engine.curve.nbPts; i++) { sprintf(idx, "%s/%s/%d", SECT_ENGINE, ARR_DATAPTS, i+1); edesc[i].rpm = GfParmGetNum(hdle, idx, PRM_RPM, (char*)NULL, car->engine.revsMax); edesc[i].tq = GfParmGetNum(hdle, idx, PRM_TQ, (char*)NULL, 0); } edesc[i].rpm = edesc[i - 1].rpm; edesc[i].tq = edesc[i].tq; maxTq = 0; car->engine.curve.maxPw = 0; car->engine.curve.data = (tEngineCurveElem *)malloc(car->engine.curve.nbPts * sizeof(tEngineCurveElem)); for(i = 0; i < car->engine.curve.nbPts; i++) { data = &(car->engine.curve.data[i]); data->rads = edesc[i].rpm; if ((data->rads>=car->engine.tickover) && (edesc[i].tq > maxTq) && (data->rads < car->engine.revsLimiter)) { maxTq = edesc[i].tq; rpmMaxTq = data->rads; } if ((data->rads>=car->engine.tickover) && (data->rads * edesc[i].tq > car->engine.curve.maxPw) && (data->rads < car->engine.revsLimiter)) { car->engine.curve.TqAtMaxPw = edesc[i].tq; car->engine.curve.maxPw = data->rads * edesc[i].tq; car->engine.curve.rpmMaxPw = data->rads; } data->Tq = edesc[i].tq; } car->engine.curve.maxTq = maxTq; car->carElt->_engineMaxTq = maxTq; car->carElt->_enginerpmMaxTq = rpmMaxTq; car->carElt->_engineMaxPw = car->engine.curve.maxPw; car->carElt->_enginerpmMaxPw = car->engine.curve.rpmMaxPw; //printf ("%fNm@%frpm, %fKW@%f rpm\n", // car->carElt->_engineMaxTq, // car->carElt->_enginerpmMaxTq * (30.0 / M_PI), // car->carElt->_engineMaxPw * 0.001, // car->carElt->_enginerpmMaxPw * (30.0 / M_PI) // ); float X=urandom(); car->engine.rads = X*car->engine.tickover+(1-X)*car->engine.revsMax; /*sanity check of rev limits*/ if (car->engine.revsMax > car->engine.curve.data[car->engine.curve.nbPts-1].rads) { car->engine.revsMax = car->engine.curve.data[car->engine.curve.nbPts-1].rads; GfLogWarning("Revs maxi bigger than the maximum RPM in the curve data.\nIt is set to %g.\n",car->engine.revsMax); } if (car->engine.revsLimiter > car->engine.revsMax) { car->engine.revsLimiter = car->engine.revsMax; GfLogWarning("Revs limiter is bigger than revs maxi.\nIt is set to %g.\n",car->engine.revsLimiter); } #if 0 // TEST TORQUE FUNCTION for (float rads=1.0; rads<car->engine.revsMax; rads+=1.0) { float Tq = CalculateTorque(&(car->engine), rads); float Tq2 = CalculateTorque2(&(car->engine), rads); printf ("%f %f %f %d #TORQUE\n", 30.0*rads/M_PI, Tq, Tq2, engine->lastInterval); } #endif free(edesc); }
//==========================================================================* // Handle module entry for Speed Dreams Interface V1.00 (new fixed name scheme) //--------------------------------------------------------------------------* int moduleWelcomeV1_00 (const tModWelcomeIn* welcomeIn, tModWelcomeOut* welcomeOut) { PLogSimplix = GfLogger::instance("Simplix"); LogSimplix.debug("\n#Interface Version: %d.%d\n", welcomeIn->itfVerMajor,welcomeIn->itfVerMinor); // Get filehandle for robot's xml-file void* RobotSettings = GetFileHandle(welcomeIn->name); // Let's look what we have to provide here if (RobotSettings) { LogSimplix.debug("#Robot name : %s\n",RobName); LogSimplix.debug("#Robot directory : %s\n",RobPathDirRel); LogSimplix.debug("#Robot XML-file : %s\n",RobPathXMLRel); char Buffer[BUFSIZE]; char *Section = Buffer; // To get the number of drivers defined in the // robot team definition file we have to count // the number of sections within Robots/index! snprintf(Buffer, BUFSIZE, "%s/%s", ROB_SECT_ROBOTS, ROB_LIST_INDEX); NBBOTS = GfParmGetEltNb(RobotSettings,Buffer); LogSimplix.debug("#Nbr of drivers : %d\n",NBBOTS); DriverNames = (char *) calloc(NBBOTS,DRIVERLEN); DriverDescs = (char *) calloc(NBBOTS,DESCRPLEN); // Setup a path to the first driver section // assuming that it starts with the index 0 snprintf(Buffer, BUFSIZE, "%s/%s/%d", ROB_SECT_ROBOTS, ROB_LIST_INDEX, 0); // Try to get first driver from index 0 const char *DriverName = GfParmGetStr( RobotSettings, Section, (char *) ROB_ATTR_NAME, undefined); // Check wether index 0 is used as start index if (strncmp(DriverName,undefined,strlen(undefined)) != 0) { // Teams xml file uses index 0, 1, ..., N - 1 IndexOffset = 0; } else { // Teams xml file uses index 1, 2, ..., N IndexOffset = 1; } // Loop over all possible drivers, clear all buffers, // save defined driver names and desc. int I = 0; int N = 0; int M = 0; // for (I = 0; I < MAXNBBOTS; I++) while (N < NBBOTS) { snprintf(Section, BUFSIZE, "%s/%s/%d", ROB_SECT_ROBOTS, ROB_LIST_INDEX, I + IndexOffset ); const char *DriverName = GfParmGetStr( RobotSettings, Section, (char *) ROB_ATTR_NAME,undefined); if (strncmp(DriverName,undefined,strlen(undefined)) != 0) { // This driver is defined in robot's xml-file strncpy(&DriverNames[I*DRIVERLEN], DriverName, DRIVERLEN-1); const char *DriverDesc = GfParmGetStr(RobotSettings, Section, (char *) ROB_ATTR_DESC, defaultBotDesc[I]); strncpy(&DriverDescs[I*DESCRPLEN], DriverDesc, DESCRPLEN-1); LogSimplix.debug("#Driver %d: %s (%s)\n",I,DriverName,DriverDesc); N++; } else { // There is an index skipped in the robots team definition file // Therefore we have to get additional memory to store the data M++; DriverNames = (char *) realloc(DriverNames,(NBBOTS+M)*DRIVERLEN); memset(&DriverNames[I*DRIVERLEN], 0, DRIVERLEN); DriverDescs = (char *) realloc(DriverDescs,(NBBOTS+M)*DESCRPLEN); memset(&DriverDescs[I*DESCRPLEN], 0, DESCRPLEN); LogSimplix.debug("#Driver %d: %s (%s)\n",I,&DriverNames[I*DRIVERLEN],&DriverDescs[I*DESCRPLEN]); } I++; } GfParmReleaseHandle(RobotSettings); } else { // Handle error here LogSimplix.debug("#Robot XML-Path not found: (%s) or (%s) %s\n\n", GetLocalDir(),GetDataDir(),RobPathXMLRel); NBBOTS = 0; // But this is not considered a real failure of moduleWelcome ! } // Handle additional settings for wellknown identities if (strncmp(RobName,"simplix_trb1",strlen("simplix_trb1")) == 0) SetUpSimplix_trb1(); else if (strncmp(RobName,"simplix_sc",strlen("simplix_sc")) == 0) SetUpSimplix_sc(); else if (strncmp(RobName,"simplix_36GP",strlen("simplix_36GP")) == 0) SetUpSimplix_36GP(); else if (strncmp(RobName,"simplix_mpa1",strlen("simplix_mpa1")) == 0) SetUpSimplix_mpa1(); else if (strncmp(RobName,"simplix_ls1",strlen("simplix_ls1")) == 0) SetUpSimplix_ls1(); else if (strncmp(RobName,"simplix_ls2",strlen("simplix_ls2")) == 0) SetUpSimplix_ls2(); else if (strncmp(RobName,"simplix_mp5",strlen("simplix_mp5")) == 0) SetUpSimplix_mp5(); else if (strncmp(RobName,"simplix_lp1", strlen("simplix_lp1")) == 0) SetUpSimplix_lp1(); else if (strncmp(RobName,"simplix_ref", strlen("simplix_ref")) == 0) SetUpSimplix_ref(); else SetUpSimplix(); // Set max nb of interfaces to return. welcomeOut->maxNbItf = NBBOTS; return 0; }
static void reConfigRunState(void) { int i; int curConf; char *conf; int numOpt; char *opt; void *params = ReInfo->params; curConf = (int)GfParmGetNum(params, RM_SECT_CONF, RM_ATTR_CUR_CONF, NULL, 1); if (curConf > GfParmGetEltNb(params, RM_SECT_CONF)) { GfOut("End of configuration\n"); GfParmWriteFile(NULL, ReInfo->params, ReInfo->_reName); goto menuback; } sprintf(path, "%s/%d", RM_SECT_CONF, curConf); conf = GfParmGetStr(params, path, RM_ATTR_TYPE, 0); if (!conf) { GfOut("no %s here %s\n", RM_ATTR_TYPE, path); goto menuback; } GfOut("Configuration step %s\n", conf); if (!strcmp(conf, RM_VAL_TRACKSEL)) { /* Track Select Menu */ ts.nextScreen = reConfigHookInit(); if (curConf == 1) { ts.prevScreen = racemanMenuHdle; } else { ts.prevScreen = reConfigBackHookInit(); } ts.param = ReInfo->params; ts.trackItf = ReInfo->_reTrackItf; RmTrackSelect(&ts); } else if (!strcmp(conf, RM_VAL_DRVSEL)) { /* Drivers select menu */ ds.nextScreen = reConfigHookInit(); if (curConf == 1) { ds.prevScreen = racemanMenuHdle; } else { ds.prevScreen = reConfigBackHookInit(); } ds.param = ReInfo->params; RmDriversSelect(&ds); } else if (!strcmp(conf, RM_VAL_RACECONF)) { /* Race Options menu */ rp.nextScreen = reConfigHookInit(); if (curConf == 1) { rp.prevScreen = racemanMenuHdle; } else { rp.prevScreen = reConfigBackHookInit(); } rp.param = ReInfo->params; rp.title = GfParmGetStr(params, path, RM_ATTR_RACE, "Race"); /* Select options to configure */ rp.confMask = 0; sprintf(path, "%s/%d/%s", RM_SECT_CONF, curConf, RM_SECT_OPTIONS); numOpt = GfParmGetEltNb(params, path); for (i = 1; i < numOpt + 1; i++) { sprintf(path, "%s/%d/%s/%d", RM_SECT_CONF, curConf, RM_SECT_OPTIONS, i); opt = GfParmGetStr(params, path, RM_ATTR_TYPE, ""); if (!strcmp(opt, RM_VAL_CONFRACELEN)) { /* Configure race length */ rp.confMask |= RM_CONF_RACE_LEN; } else { if (!strcmp(opt, RM_VAL_CONFDISPMODE)) { /* Configure display mode */ rp.confMask |= RM_CONF_DISP_MODE; } } } RmRaceParamMenu(&rp); } curConf++; GfParmSetNum(params, RM_SECT_CONF, RM_ATTR_CUR_CONF, NULL, curConf); return; /* Back to the race menu */ menuback: GfuiScreenActivate(racemanMenuHdle); return; }
static void NetworkRaceInfo() { NetDriver driver; int i = 1; NetGetServer()->SetRaceXMLFile("config/raceman/networkrace.xml"); //Look up race info tRmInfo* reInfo = LmRaceEngine().inData(); reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_STD); int nCars = GfParmGetEltNb(reInfo->params, RM_SECT_DRIVERS); if (nCars == 0) { // Add all local humans if there are no drivers already specified while (GetHumanDriver(driver,i++)) { driver.client = false; driver.active = true; NetGetServer()->UpdateDriver(driver); NetGetServer()->SetDriverName(driver.name); GfLogInfo("NetworkRaceInfo: Adding default driver %s\n",driver.name); } // ensure changes writen to 'networkrace.xml' NetGetServer()->GenerateDriversForXML(); // add drivers so they show up in race config dialogue GfDrivers::self()->reload(); LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true); } else { // Add the humans which are already in the race char dname[256]; for (i = 1; i < nCars+1; i++) { sprintf(dname, "%s/%d", RM_SECT_DRIVERS, i); if(strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, "")) == 0) { if (GetHumanDriver(driver,i) > -1) { driver.client = false; driver.active = true; NetGetServer()->UpdateDriver(driver); NetGetServer()->SetDriverName(driver.name); GfLogInfo("NetworkRaceInfo: Adding default driver %s\n",driver.name); } } } } // make sure nobody is 'ready to race' NetMutexData *pNData = NetGetNetwork()->LockNetworkData(); for (unsigned int i=0; i < pNData->m_vecReadyStatus.size(); i++) pNData->m_vecReadyStatus[i] = false; NetGetNetwork()->UnlockNetworkData(); bRobotsReady = false; // ensure the system knows about 'new' network drivers reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD); reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, ""); }
/** Initialize the cars for a race. The car are positionned on the starting grid. @return 0 Ok -1 Error */ int ReInitCars(void) { int nCars; int index; int i, j, k; char *cardllname; int robotIdx; tModInfo *curModInfo; tRobotItf *curRobot; void *handle; char *category; void *cathdle; void *carhdle; void *robhdle; tCarElt *elt; char *focused; char *str; int focusedIdx; void *params = ReInfo->params; /* Get the number of cars racing */ nCars = GfParmGetEltNb(params, RM_SECT_DRIVERS_RACING); GfOut("loading %d cars\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 (i = 1; i < nCars + 1; i++) { /* Get Shared library name */ sprintf(path, "%s/%d", RM_SECT_DRIVERS_RACING, i); cardllname = GfParmGetStr(ReInfo->params, path, RM_ATTR_MODULE, ""); robotIdx = (int)GfParmGetNum(ReInfo->params, path, RM_ATTR_IDX, NULL, 0); sprintf(path, "%sdrivers/%s/%s.%s", GetLibDir (), cardllname, cardllname, DLLEXT); /* load the robot shared library */ if (GfModLoad(CAR_IDENT, path, ReInfo->modList)) { GfTrace("Pb with loading %s driver\n", path); break; } /* search for corresponding index */ for (j = 0; j < MAX_MOD_ITF; j++) { if ((*(ReInfo->modList))->modInfo[j].index == robotIdx) { /* good robot found */ curModInfo = &((*(ReInfo->modList))->modInfo[j]); GfOut("Driver's name: %s\n", curModInfo->name); /* retrieve the robot interface (function pointers) */ curRobot = (tRobotItf*)calloc(1, sizeof(tRobotItf)); curModInfo->fctInit(robotIdx, (void*)(curRobot)); sprintf(buf, "%sdrivers/%s/%s.xml", GetLocalDir(), cardllname, cardllname); robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD); if (!robhdle) { sprintf(buf, "drivers/%s/%s.xml", cardllname, cardllname); robhdle = GfParmReadFile(buf, GFPARM_RMODE_STD); } if (robhdle != NULL) { elt = &(ReInfo->carList[index]); GF_TAILQ_INIT(&(elt->_penaltyList)); elt->index = index; elt->robot = curRobot; elt->_paramsHandle = robhdle; elt->_driverIndex = robotIdx; strncpy(elt->_modName, cardllname, MAX_NAME_LEN - 1); elt->_modName[MAX_NAME_LEN - 1] = 0; sprintf(path, "%s/%s/%d", ROB_SECT_ROBOTS, ROB_LIST_INDEX, robotIdx); strncpy(elt->_name, GfParmGetStr(robhdle, path, ROB_ATTR_NAME, "<none>"), MAX_NAME_LEN - 1); elt->_name[MAX_NAME_LEN - 1] = 0; strncpy(elt->_teamname, GfParmGetStr(robhdle, path, ROB_ATTR_TEAM, "<none>"), MAX_NAME_LEN - 1); elt->_teamname[MAX_NAME_LEN - 1] = 0; strncpy(elt->_carName, GfParmGetStr(robhdle, path, ROB_ATTR_CAR, ""), MAX_NAME_LEN - 1); elt->_carName[MAX_NAME_LEN - 1] = 0; elt->_raceNumber = (int)GfParmGetNum(robhdle, path, ROB_ATTR_RACENUM, (char*)NULL, 0); if (strcmp(GfParmGetStr(robhdle, path, ROB_ATTR_TYPE, ROB_VAL_ROBOT), ROB_VAL_ROBOT)) { elt->_driverType = RM_DRV_HUMAN; } else { elt->_driverType = RM_DRV_ROBOT; } elt->_skillLevel = 0; str = GfParmGetStr(robhdle, path, ROB_ATTR_LEVEL, ROB_VAL_SEMI_PRO); for(k = 0; k < (int)(sizeof(level_str)/sizeof(char*)); k++) { if (strcmp(level_str[k], str) == 0) { elt->_skillLevel = k; break; } } elt->_startRank = index; elt->_pos = index+1; elt->_remainingLaps = ReInfo->s->_totLaps; /* handle contains the drivers modifications to the car */ /* Read Car model specifications */ sprintf(buf, "cars/%s/%s.xml", elt->_carName, elt->_carName); GfOut("Car Specification: %s\n", buf); carhdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); category = GfParmGetStr(carhdle, SECT_CAR, PRM_CATEGORY, NULL); sprintf(buf, "Loading Driver %-20s... Car: %s", curModInfo->name, elt->_carName); RmLoadingScreenSetText(buf); if (category != 0) { strncpy(elt->_category, category, MAX_NAME_LEN - 1); elt->_category[MAX_NAME_LEN - 1] = '\0'; /* Read Car Category specifications */ sprintf(buf, "categories/%s.xml", category); GfOut("Category Specification: %s\n", buf); cathdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); if (GfParmCheckHandle(cathdle, carhdle)) { GfTrace("Car %s not in Category %s (driver %s) !!!\n", elt->_carName, category, elt->_name); break; } carhdle = GfParmMergeHandles(cathdle, carhdle, GFPARM_MMODE_SRC | GFPARM_MMODE_DST | GFPARM_MMODE_RELSRC | GFPARM_MMODE_RELDST); curRobot->rbNewTrack(robotIdx, ReInfo->track, carhdle, &handle, ReInfo->s); if (handle != NULL) { if (GfParmCheckHandle(carhdle, handle)) { GfTrace("Bad Car parameters for driver %s\n", elt->_name); break; } handle = GfParmMergeHandles(carhdle, handle, GFPARM_MMODE_SRC | GFPARM_MMODE_DST | GFPARM_MMODE_RELSRC | GFPARM_MMODE_RELDST); } else { handle = carhdle; } elt->_carHandle = handle; //GfParmWriteFile("toto.xml", handle, "toto"); } else { elt->_category[0] = '\0'; GfTrace("Bad Car category for driver %s\n", elt->_name); break; } index ++; } else { GfTrace("Pb No description file for driver %s\n", cardllname); } break; } } } nCars = index; /* real number of cars */ if (nCars == 0) { GfTrace("No driver for that race...\n"); return -1; } else { GfOut("%d drivers ready to race\n", nCars); } 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]); } // 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.). ReInfo->_reSimItf.init(nCars, ReInfo->track); initStartingGrid(); initPits(); return 0; }
/* * Function * GetTrackHeader * * Description * Get the header of the track file * in order to know the number of segments * Parameters * * * Return * * * Remarks * */ static void GetTrackHeader(void *TrackHandle) { // Read header theTrack->name = GfParmGetStr(TrackHandle, TRK_SECT_HDR, TRK_ATT_NAME, "no name"); theTrack->descr = GfParmGetStr(TrackHandle, TRK_SECT_HDR, TRK_ATT_DESCR, "no description"); theTrack->version = (int)GfParmGetNum(TrackHandle, TRK_SECT_HDR, TRK_ATT_VERSION, (char*)NULL, 0); theTrack->width = GfParmGetNum(TrackHandle, TRK_SECT_MAIN, TRK_ATT_WIDTH, (char*)NULL, 15.0); theTrack->authors = GfParmGetStr(TrackHandle, TRK_SECT_HDR, TRK_ATT_AUTHOR, "none"); theTrack->category = GfParmGetStr(TrackHandle, TRK_SECT_HDR, TRK_ATT_CAT, "road"); theTrack->subcategory = GfParmGetStr(TrackHandle, TRK_SECT_HDR, TRK_ATT_SUBCAT, "none"); // Read Local Info section tTrackLocalInfo *local = &theTrack->local; local->station = GfParmGetStr(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_STATION, "LFPG"); local->timezone = (int)GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_TIMEZONE, (char*)NULL, 0); local->anyrainlkhood = GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_ANYRAINLKHD, (char*)NULL, 0); local->littlerainlkhood = GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_LITTLERAINLKHD, (char*)NULL, 0); local->mediumrainlkhood = GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_MEDIUMRAINLKHD, (char*)NULL, 0); local->timeofday = GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_TIMEOFDAY, (char*)NULL, (tdble)(15 * 3600 + 0 * 60 + 0)); // 15:00:00 local->sunascension = GfParmGetNum(TrackHandle, TRK_SECT_LOCAL, TRK_ATT_SUN_ASCENSION, (char*)NULL, 0.0f); // Read Graphic section tTrackGraphicInfo *graphic = &theTrack->graphic; graphic->model3d = GfParmGetStr(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_3DDESC, 0); graphic->background = GfParmGetStr(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_BKGRND, "background.png"); graphic->bgtype = (int)GfParmGetNum(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_BGTYPE, (char*)NULL, 0.0); graphic->bgColor[0] = (float)GfParmGetNum(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_BGCLR_R, (char*)NULL, 0.0f); graphic->bgColor[1] = (float)GfParmGetNum(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_BGCLR_G, (char*)NULL, 0.0f); graphic->bgColor[2] = (float)GfParmGetNum(TrackHandle, TRK_SECT_GRAPH, TRK_ATT_BGCLR_B, (char*)NULL, 0.1f); // Environment map images char buf[256]; sprintf(buf, "%s/%s", TRK_SECT_GRAPH, TRK_LST_ENV); graphic->envnb = GfParmGetEltNb(TrackHandle, buf); if (graphic->envnb < 1) graphic->envnb = 1; graphic->env = (const char**)calloc(graphic->envnb, sizeof(const char*)); const char **env = graphic->env; for (int i = 1; i <= graphic->envnb; ++i) { sprintf(buf, "%s/%s/%d", TRK_SECT_GRAPH, TRK_LST_ENV, i); *env = GfParmGetStr(TrackHandle, buf, TRK_ATT_ENVNAME, "env.png"); ++env; } // Track lights graphic->nb_lights = GfParmGetEltNb(TrackHandle, TRK_SECT_TRACKLIGHTS ); GfLogDebug( "Number of lights: %d\n", graphic->nb_lights ); if (graphic->nb_lights > 0 ) { graphic->lights = (tGraphicLightInfo*)malloc( sizeof( tGraphicLightInfo ) * graphic->nb_lights ); for (int i = 0; i < graphic->nb_lights; ++i) { sprintf(buf, "%s/%d/%s", TRK_SECT_TRACKLIGHTS, i + 1, TRK_SECT_TOPLEFT); graphic->lights[ i ].topleft.x = GfParmGetNum(TrackHandle, buf, TRK_ATT_X, (char*)NULL, 0.0f); graphic->lights[ i ].topleft.y = GfParmGetNum(TrackHandle, buf, TRK_ATT_Y, (char*)NULL, 0.0f); graphic->lights[ i ].topleft.z = GfParmGetNum(TrackHandle, buf, TRK_ATT_Z, (char*)NULL, 0.0f); sprintf(buf, "%s/%d/%s", TRK_SECT_TRACKLIGHTS, i + 1, TRK_SECT_BOTTOMRIGHT); graphic->lights[ i ].bottomright.x = GfParmGetNum(TrackHandle, buf, TRK_ATT_X, (char*)NULL, 0.0f); graphic->lights[ i ].bottomright.y = GfParmGetNum(TrackHandle, buf, TRK_ATT_Y, (char*)NULL, 0.0f); graphic->lights[ i ].bottomright.z = GfParmGetNum(TrackHandle, buf, TRK_ATT_Z, (char*)NULL, 0.0f); sprintf(buf, "%s/%d", TRK_SECT_TRACKLIGHTS, i + 1); graphic->lights[ i ].onTexture = strdup(GfParmGetStr(TrackHandle, buf, TRK_ATT_TEXTURE_ON, "")); graphic->lights[ i ].offTexture = strdup(GfParmGetStr(TrackHandle, buf, TRK_ATT_TEXTURE_OFF, "")); graphic->lights[ i ].index = (int)GfParmGetNum(TrackHandle, buf, TRK_ATT_INDEX, (char*)NULL, 0.0f); graphic->lights[ i ].role = 0; if( strcmp( GfParmGetStr(TrackHandle, buf, TRK_ATT_ROLE, ""), "st_red" ) == 0 ) graphic->lights[ i ].role = GR_TRACKLIGHT_START_RED; else if( strcmp( GfParmGetStr(TrackHandle, buf, TRK_ATT_ROLE, ""), "st_green" ) == 0 ) graphic->lights[ i ].role = GR_TRACKLIGHT_START_GREEN; else if( strcmp( GfParmGetStr(TrackHandle, buf, TRK_ATT_ROLE, ""), "st_green_st" ) == 0 ) graphic->lights[ i ].role = GR_TRACKLIGHT_START_GREENSTART; else if( strcmp( GfParmGetStr(TrackHandle, buf, TRK_ATT_ROLE, ""), "st_yellow" ) == 0 ) graphic->lights[ i ].role = GR_TRACKLIGHT_START_YELLOW; graphic->lights[ i ].red = GfParmGetNum(TrackHandle, buf, TRK_ATT_RED, (char*)NULL, 1.0f); graphic->lights[ i ].green = GfParmGetNum(TrackHandle, buf, TRK_ATT_GREEN, (char*)NULL, 1.0f); graphic->lights[ i ].blue = GfParmGetNum(TrackHandle, buf, TRK_ATT_BLUE, (char*)NULL, 1.0f); } // for i } // if nb_lights theTrack->nseg = 0; // Search for track filename, without any path info, eg: 'foo.xml' const char *s = strrchr(theTrack->filename, '/'); if (s == NULL) { s = theTrack->filename; } else { ++s; } // Internal name is track filename, without extension, eg: 'foo' theTrack->internalname = strdup(s); char *cs = strrchr(theTrack->internalname, '.'); if (cs != NULL) { *cs = 0; } // Default turnmark is 1m*1m, right next to the track graphic->turnMarksInfo.height = GfParmGetNum(TrackHandle, TRK_SECT_TURNMARKS, TRK_ATT_HEIGHT, NULL, 1); graphic->turnMarksInfo.width = GfParmGetNum(TrackHandle, TRK_SECT_TURNMARKS, TRK_ATT_WIDTH, NULL, 1); graphic->turnMarksInfo.vSpace = GfParmGetNum(TrackHandle, TRK_SECT_TURNMARKS, TRK_ATT_VSPACE, NULL, 0); graphic->turnMarksInfo.hSpace = GfParmGetNum(TrackHandle, TRK_SECT_TURNMARKS, TRK_ATT_HSPACE, NULL, 0); } // GetTrackHeader
/* 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 <= 0) return RM_ERROR; // Propagate competitor drivers info to the real race starting grid snprintf(path, sizeof(path), "%s/%d", RM_SECT_DRIVERS, ReStartingOrderIdx[nCurrDrvInd-1]); 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; }
static void rmShowStandings(void *prevHdle, tRmInfo *info, int start) { int i; int x1, x2, x3; int y; const int BUFSIZE = 1024; char buf[BUFSIZE]; char path[BUFSIZE]; float fgcolor[4] = {1.0, 0.0, 1.0, 1.0}; int nbCars; int offset; void *results = info->results; const char *race = info->_reRaceName; rmScrHdle = GfuiScreenCreate(); snprintf(buf, BUFSIZE, "%s Results", race); GfuiTitleCreate(rmScrHdle, buf, strlen(buf)); GfuiScreenAddBgImg(rmScrHdle, "data/img/splash-result.png"); offset = 200; x1 = offset + 30; x2 = offset + 60; x3 = offset + 240; y = 400; GfuiLabelCreateEx(rmScrHdle, "Rank", fgcolor, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Driver", fgcolor, GFUI_FONT_MEDIUM_C, x2+10, y, GFUI_ALIGN_HL_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Points", fgcolor, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HR_VB, 0); y -= 20; nbCars = (int)GfParmGetEltNb(results, RE_SECT_STANDINGS); for (i = start; i < MIN(start + MAX_LINES, nbCars); i++) { snprintf(path, BUFSIZE, "%s/%d", RE_SECT_STANDINGS, i + 1); snprintf(buf, BUFSIZE, "%d", i+1); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreate(rmScrHdle, GfParmGetStr(results, path, RE_ATTR_NAME, ""), GFUI_FONT_MEDIUM_C, x2, y, GFUI_ALIGN_HL_VB, 0); snprintf(buf, BUFSIZE, "%d", (int)GfParmGetNum(results, path, RE_ATTR_POINTS, NULL, 0)); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HR_VB, 0); y -= 15; } if (start > 0) { RmPrevRace.prevHdle = prevHdle; RmPrevRace.info = info; RmPrevRace.start = start - MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up-pushed.png", 80, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmPrevRace, rmChgStandingScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_UP, "Previous Results", (void*)&RmPrevRace, rmChgStandingScreen, NULL); } GfuiButtonCreate(rmScrHdle, "Continue", GFUI_FONT_LARGE, 210, 40, 150, GFUI_ALIGN_HC_VB, 0, prevHdle, GfuiScreenReplace, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); rmSaveId = GfuiButtonCreate(rmScrHdle, "Save", GFUI_FONT_LARGE, 430, 40, 150, GFUI_ALIGN_HC_VB, 0, info, rmSaveRes, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); if (i < nbCars) { RmNextRace.prevHdle = prevHdle; RmNextRace.info = info; RmNextRace.start = start + MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down-pushed.png", 540, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmNextRace, rmChgStandingScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_DOWN, "Next Results", (void*)&RmNextRace, rmChgStandingScreen, NULL); } GfuiAddKey(rmScrHdle, (unsigned char)27, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddKey(rmScrHdle, (unsigned char)13, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_F12, "Take a Screen Shot", NULL, GfuiScreenShot, NULL); GfuiScreenActivate(rmScrHdle); }
static void rmPracticeResults(void *prevHdle, tRmInfo *info, int start) { void *results = info->results; const char *race = info->_reRaceName; int i; int x1, x2, x3, x4, x5, x6; int offset; int y; const int BUFSIZE = 1024; char buf[BUFSIZE]; char path[BUFSIZE]; const int TIMEFMTSIZE = 256; char timefmt[TIMEFMTSIZE]; float fgcolor[4] = {1.0, 0.0, 1.0, 1.0}; int totLaps; rmScrHdle = GfuiScreenCreate(); snprintf(buf, BUFSIZE, "Practice Results"); GfuiTitleCreate(rmScrHdle, buf, strlen(buf)); snprintf(path, BUFSIZE, "%s/%s/%s", info->track->name, RE_SECT_RESULTS, race); snprintf(buf, BUFSIZE, "%s on track %s", GfParmGetStr(results, path, RM_ATTR_DRVNAME, ""), info->track->name); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_LARGE_C, 320, 420, GFUI_ALIGN_HC_VB, 0); GfuiScreenAddBgImg(rmScrHdle, "data/img/splash-result.png"); offset = 90; x1 = offset + 30; x2 = offset + 50; x3 = offset + 130; x4 = offset + 240; x5 = offset + 310; x6 = offset + 400; y = 400; GfuiLabelCreateEx(rmScrHdle, "Lap", fgcolor, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Time", fgcolor, GFUI_FONT_MEDIUM_C, x2+20, y, GFUI_ALIGN_HL_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Best", fgcolor, GFUI_FONT_MEDIUM_C, x3+20, y, GFUI_ALIGN_HL_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Top Spd", fgcolor, GFUI_FONT_MEDIUM_C, x4, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Min Spd", fgcolor, GFUI_FONT_MEDIUM_C, x5, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Damages", fgcolor, GFUI_FONT_MEDIUM_C, x6, y, GFUI_ALIGN_HC_VB, 0); y -= 20; snprintf(path, BUFSIZE, "%s/%s/%s", info->track->name, RE_SECT_RESULTS, race); totLaps = (int)GfParmGetEltNb(results, path); for (i = 0 + start; i < MIN(start + MAX_LINES, totLaps); i++) { snprintf(path, BUFSIZE, "%s/%s/%s/%d", info->track->name, RE_SECT_RESULTS, race, i + 1); /* Lap */ snprintf(buf, BUFSIZE, "%d", i+1); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); /* Time */ GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_TIME, NULL, 0), 0); GfuiLabelCreate(rmScrHdle, timefmt, GFUI_FONT_MEDIUM_C, x2, y, GFUI_ALIGN_HL_VB, 0); /* Best Lap Time */ GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0), 0); GfuiLabelCreate(rmScrHdle, timefmt, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HL_VB, 0); /* Top Spd */ snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_TOP_SPEED, NULL, 0) * 3.6)); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x4, y, GFUI_ALIGN_HC_VB, 0); /* Min Spd */ snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_BOT_SPEED, NULL, 0) * 3.6)); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x5, y, GFUI_ALIGN_HC_VB, 0); /* Damages */ snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_DAMMAGES, NULL, 0))); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x6, y, GFUI_ALIGN_HC_VB, 0); y -= 15; } if (start > 0) { RmPrevRace.prevHdle = prevHdle; RmPrevRace.info = info; RmPrevRace.start = start - MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up-pushed.png", 80, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmPrevRace, rmChgPracticeScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_UP, "Previous Results", (void*)&RmPrevRace, rmChgPracticeScreen, NULL); } GfuiButtonCreate(rmScrHdle, "Continue", GFUI_FONT_LARGE, 320, 40, 150, GFUI_ALIGN_HC_VB, 0, prevHdle, GfuiScreenReplace, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); if (i < totLaps) { RmNextRace.prevHdle = prevHdle; RmNextRace.info = info; RmNextRace.start = start + MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down-pushed.png", 540, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmNextRace, rmChgPracticeScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_DOWN, "Next Results", (void*)&RmNextRace, rmChgPracticeScreen, NULL); } GfuiAddKey(rmScrHdle, (unsigned char)27, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddKey(rmScrHdle, (unsigned char)13, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_F12, "Take a Screen Shot", NULL, GfuiScreenShot, NULL); GfuiScreenActivate(rmScrHdle); }
static void rmRaceResults(void *prevHdle, tRmInfo *info, int start) { void *results = info->results; const char *race = info->_reRaceName; int i; int x1, x2, x3, x4, x5, x6, x7, x8, x9; int dlap; int y; const int BUFSIZE = 1024; char buf[BUFSIZE]; char path[BUFSIZE]; const int TIMEFMTSIZE = 256; char timefmt[TIMEFMTSIZE]; float fgcolor[4] = {1.0, 0.0, 1.0, 1.0}; int laps, totLaps; tdble refTime; int nbCars; rmScrHdle = GfuiScreenCreate(); snprintf(buf, BUFSIZE, "Race Results"); GfuiTitleCreate(rmScrHdle, buf, strlen(buf)); snprintf(buf, BUFSIZE, "%s", info->track->name); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_LARGE_C, 320, 420, GFUI_ALIGN_HC_VB, 0); GfuiScreenAddBgImg(rmScrHdle, "data/img/splash-result.png"); x1 = 30; x2 = 60; x3 = 260; x4 = 330; x5 = 360; x6 = 420; x7 = 490; x8 = 545; x9 = 630; y = 400; GfuiLabelCreateEx(rmScrHdle, "Rank", fgcolor, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Driver", fgcolor, GFUI_FONT_MEDIUM_C, x2+10, y, GFUI_ALIGN_HL_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Total", fgcolor, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HR_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Best", fgcolor, GFUI_FONT_MEDIUM_C, x4, y, GFUI_ALIGN_HR_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Laps", fgcolor, GFUI_FONT_MEDIUM_C, x5, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Top Spd", fgcolor, GFUI_FONT_MEDIUM_C, x6, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Damage", fgcolor, GFUI_FONT_MEDIUM_C, x7, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Pit", fgcolor, GFUI_FONT_MEDIUM_C, x8, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreateEx(rmScrHdle, "Penalty", fgcolor, GFUI_FONT_MEDIUM_C, x9, y, GFUI_ALIGN_HR_VB, 0); y -= 20; snprintf(path, BUFSIZE, "%s/%s/%s", info->track->name, RE_SECT_RESULTS, race); totLaps = (int)GfParmGetNum(results, path, RE_ATTR_LAPS, NULL, 0); snprintf(path, BUFSIZE, "%s/%s/%s/%s/%d", info->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, 1); refTime = GfParmGetNum(results, path, RE_ATTR_TIME, NULL, 0); snprintf(path, BUFSIZE, "%s/%s/%s/%s", info->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK); nbCars = (int)GfParmGetEltNb(results, path); for (i = start; i < MIN(start + MAX_LINES, nbCars); i++) { snprintf(path, BUFSIZE, "%s/%s/%s/%s/%d", info->track->name, RE_SECT_RESULTS, race, RE_SECT_RANK, i + 1); laps = (int)GfParmGetNum(results, path, RE_ATTR_LAPS, NULL, 0); snprintf(buf, BUFSIZE, "%d", i+1); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x1, y, GFUI_ALIGN_HC_VB, 0); GfuiLabelCreate(rmScrHdle, GfParmGetStr(results, path, RE_ATTR_NAME, ""), GFUI_FONT_MEDIUM_C, x2, y, GFUI_ALIGN_HL_VB, 0); if (laps == totLaps) { if (i == 0) { GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_TIME, NULL, 0), 0); } else { GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_TIME, NULL, 0) - refTime, 1); } GfuiLabelCreate(rmScrHdle, timefmt, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HR_VB, 0); } else { dlap = totLaps - laps; if (dlap == 1) { snprintf(buf, BUFSIZE, "+1 Lap"); } else { snprintf(buf, BUFSIZE, "+%d Laps", dlap); } GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x3, y, GFUI_ALIGN_HR_VB, 0); } GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_BEST_LAP_TIME, NULL, 0), 0); GfuiLabelCreate(rmScrHdle, timefmt, GFUI_FONT_MEDIUM_C, x4, y, GFUI_ALIGN_HR_VB, 0); snprintf(buf, BUFSIZE, "%d", laps); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x5, y, GFUI_ALIGN_HC_VB, 0); snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_TOP_SPEED, NULL, 0) * 3.6)); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x6, y, GFUI_ALIGN_HC_VB, 0); snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_DAMMAGES, NULL, 0))); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x7, y, GFUI_ALIGN_HC_VB, 0); snprintf(buf, BUFSIZE, "%d", (int)(GfParmGetNum(results, path, RE_ATTR_NB_PIT_STOPS, NULL, 0))); GfuiLabelCreate(rmScrHdle, buf, GFUI_FONT_MEDIUM_C, x8, y, GFUI_ALIGN_HC_VB, 0); GfTime2Str(timefmt, TIMEFMTSIZE, GfParmGetNum(results, path, RE_ATTR_PENALTYTIME, NULL, 0), 0); GfuiLabelCreate(rmScrHdle, timefmt, GFUI_FONT_MEDIUM_C, x9, y, GFUI_ALIGN_HR_VB, 0); y -= 15; } if (start > 0) { RmPrevRace.prevHdle = prevHdle; RmPrevRace.info = info; RmPrevRace.start = start - MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up.png", "data/img/arrow-up-pushed.png", 80, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmPrevRace, rmChgRaceScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_UP, "Previous Results", (void*)&RmPrevRace, rmChgRaceScreen, NULL); } GfuiButtonCreate(rmScrHdle, "Continue", GFUI_FONT_LARGE, /* 210, */ 320, 40, 150, GFUI_ALIGN_HC_VB, 0, prevHdle, GfuiScreenReplace, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); if (i < nbCars) { RmNextRace.prevHdle = prevHdle; RmNextRace.info = info; RmNextRace.start = start + MAX_LINES; GfuiGrButtonCreate(rmScrHdle, "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down.png", "data/img/arrow-down-pushed.png", 540, 40, GFUI_ALIGN_HL_VB, 1, (void*)&RmNextRace, rmChgRaceScreen, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_PAGE_DOWN, "Next Results", (void*)&RmNextRace, rmChgRaceScreen, NULL); } GfuiAddKey(rmScrHdle, (unsigned char)27, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddKey(rmScrHdle, (unsigned char)13, "", prevHdle, GfuiScreenReplace, NULL); GfuiAddSKey(rmScrHdle, GLUT_KEY_F12, "Take a Screen Shot", NULL, GfuiScreenShot, NULL); GfuiScreenActivate(rmScrHdle); }
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); 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/%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 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; } } }
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); NoCleanupNeeded = true; return mode; }
/** * This function initialize some values which can only be done after the track is loaded. * * This function for example defines the sector start and ends * * @param TrackHandle The handle containing the information about the track */ static void FinishTrackLoading(void* TrackHandle) { double *distances = NULL; double currentDistance; double tmpDistance; int currentLength; int xx; theTrack->numberOfSectors = GfParmGetEltNb(TrackHandle, TRK_SECT_SECTORS); if (theTrack->numberOfSectors < 0) theTrack->numberOfSectors = 0; //TODO(kilo): possible divison by zero!!! if (theTrack->length / (double)theTrack->numberOfSectors < 100.0f ) { theTrack->numberOfSectors = (int)floor( theTrack->length / 100.0f ); GfOut( "WARNING: too many sectors" ); } if (theTrack->numberOfSectors == 0) { /* Default is: * 1 sector on circuits of 1km or shorter * 3 sectors on circuits between 1km and 6km * the minimum number of sectors such that every sector is at most 2km if the track is longer then 6km * * Note: the sector end at start-finish is added later */ if (theTrack->length < 1000.0f) theTrack->numberOfSectors = 0; else if(theTrack->length < 6000.0f) theTrack->numberOfSectors = 2; else theTrack->numberOfSectors = (int)floor( theTrack->length / 2000.0f ); if (theTrack->numberOfSectors > 0) { distances = (double*)malloc( sizeof( double ) * theTrack->numberOfSectors ); for( xx = 0; xx < theTrack->numberOfSectors; ++xx ) distances[ xx ] = theTrack->length * (double)(xx + 1) / (double)(theTrack->numberOfSectors + 1); } } else { distances = (double*)malloc( sizeof( double ) * theTrack->numberOfSectors ); currentLength = 0; if (GfParmListSeekFirst( TrackHandle, TRK_SECT_SECTORS ) == 0) { do { currentDistance = GfParmGetCurNum( TrackHandle, TRK_SECT_SECTORS, TRK_ATT_SECTOR_DFS, NULL, 0.0f); if (currentDistance <= 0.0f || currentDistance >= theTrack->length) continue; /* Don't add the startline as sector */ for (xx = 0; xx < currentLength; ++xx) { if (distances[xx] > currentDistance) { tmpDistance = distances[xx]; distances[xx] = currentDistance; currentDistance = tmpDistance; } } distances[currentLength] = currentDistance; ++currentLength; } while (GfParmListSeekNext(TrackHandle, TRK_SECT_SECTORS) == 0); } theTrack->numberOfSectors = currentLength; } /* All know, now allocte the structures with the right size */ if (theTrack->numberOfSectors > 0) { theTrack->sectors = (double*)malloc( sizeof(double) * theTrack->numberOfSectors ); for( xx = 0; xx < theTrack->numberOfSectors; ++xx ) theTrack->sectors[xx] = distances[xx]; } else { theTrack->sectors = NULL; } /* Add the finish line as last sector */ ++theTrack->numberOfSectors; /* Free unused memory */ if (distances) free( distances ); }
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 results/RE_ATTR_CUR_DRIVER-th driver in ReStartingOrderIdx // is added to the starting grid. // RE_ATTR_CUR_DRIVER is refreshed after every sub-race in ReRaceEnd(). 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)); } } } GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, 1.0); return RM_SYNC | RM_NEXT_STEP; }
void GfFileSetup() { void *dataVersionHandle; void *localVersionHandle; char *filename; size_t filenameLength; char *dataLocation; char *localLocation; char *absLocalLocation; char *absDataLocation; bool *isIndexUsed; int isIndexUsedLen; int index; bool anyLocalChange, fileFound; int major; int minor; struct stat st; // Open data (installation) version.xml. filenameLength = strlen(GfDataDir()) + 12 + 40; filename = (char*)malloc( sizeof(char) * filenameLength ); sprintf( filename, "%sversion.xml", GfDataDir() ); dataVersionHandle = GfParmReadFile( filename, GFPARM_RMODE_STD ); if( !dataVersionHandle ) { free( filename ); return; } // Exit if nothing inside. if( GfParmListSeekFirst( dataVersionHandle, "versions" ) != 0 ) { free( filename ); GfParmReleaseHandle( dataVersionHandle ); return; } // Create LocalDir (user settings root) if not already done. GfDirCreate( GfLocalDir() ); // Open local (user settings) version.xml (create it if not there). if( filenameLength < strlen(GfLocalDir()) + 12 ) { free( filename ); filenameLength = strlen(GfLocalDir()) + 12 + 40; filename = (char*)malloc( sizeof(char) * filenameLength ); } sprintf( filename, "%sversion.xml", GfLocalDir() ); anyLocalChange = !GfFileExists(filename); localVersionHandle = GfParmReadFile( filename, GFPARM_RMODE_CREAT ); // Exit if open/creation failed. if( !localVersionHandle ) { free( filename ); GfParmReleaseHandle( dataVersionHandle ); return; } // Setup the index of the XML files referenced in the local version.xml. isIndexUsedLen = GfParmGetEltNb( localVersionHandle, "versions" ) + GfParmGetEltNb( dataVersionHandle, "versions" ) + 2; isIndexUsed = (bool*)malloc( sizeof(bool) * isIndexUsedLen ); for( index = 0; index < isIndexUsedLen; index++ ) isIndexUsed[index] = false; if( GfParmListSeekFirst( localVersionHandle, "versions" ) == 0 ) { do { index = atoi( GfParmListGetCurEltName( localVersionHandle, "versions" ) ); if( 0 <= index && index < isIndexUsedLen ) isIndexUsed[index] = true; } while( GfParmListSeekNext( localVersionHandle, "versions" ) == 0 ); } // For each file referenced in the installation version.xml do { fileFound = false; // Get its installation path (data), user settings path (local), // and new major and minor version numbers dataLocation = strdup( GfParmGetCurStr( dataVersionHandle, "versions", "Data location", "" ) ); localLocation = strdup( GfParmGetCurStr( dataVersionHandle, "versions", "Local location", "" ) ); major = (int)GfParmGetCurNum( dataVersionHandle, "versions", "Major version", NULL, 0 ); minor = (int)GfParmGetCurNum( dataVersionHandle, "versions", "Minor version", NULL, 0 ); absLocalLocation = (char*)malloc( sizeof(char)*(strlen(GfLocalDir())+strlen(localLocation)+3) ); sprintf( absLocalLocation, "%s%s", GfLocalDir(), localLocation ); absDataLocation = (char*)malloc( sizeof(char)*(strlen(GfDataDir())+strlen(dataLocation)+3) ); sprintf( absDataLocation, "%s%s", GfDataDir(), dataLocation ); GfLogTrace("Checking %s : user settings version ", localLocation); // Search for its old major and minor version numbers in the user settings. if( GfParmListSeekFirst( localVersionHandle, "versions" ) == 0 ) { do { if( strcmp( absLocalLocation, GfParmGetCurStr( localVersionHandle, "versions", "Local location", "" ) ) == 0 ) { fileFound = true; const int locMinor = (int)GfParmGetCurNum( localVersionHandle, "versions", "Minor version", NULL, 0 ); const int locMajor = (int)GfParmGetCurNum( localVersionHandle, "versions", "Major version", NULL, 0 ); GfLogTrace("%d.%d is ", locMajor, locMinor); if( locMajor != major || locMinor < minor) { GfLogTrace("obsolete (installed one is %d.%d) => updating ...\n", major, minor); if ( gfFileSetupCopy( absDataLocation, absLocalLocation, major, minor, localVersionHandle, -1 ) ) anyLocalChange = true; } else { GfLogTrace("up-to-date"); if (stat(absLocalLocation, &st)) { GfLogTrace(", but not there => installing ...\n"); if ( gfFileSetupCopy( absDataLocation, absLocalLocation, major, minor, localVersionHandle, -1 ) ) anyLocalChange = true; } else GfLogTrace(".\n"); } break; } } while( GfParmListSeekNext( localVersionHandle, "versions" ) == 0 ); } if( !fileFound) { index = 0; while( isIndexUsed[index] ) ++index; GfLogTrace("not found => installing ...\n"); if ( gfFileSetupCopy( absDataLocation, absLocalLocation, major, minor, localVersionHandle, index ) ) anyLocalChange = true; isIndexUsed[index] = true; } free( dataLocation ); free( localLocation ); free( absDataLocation ); free( absLocalLocation ); } while( GfParmListSeekNext( dataVersionHandle, "versions" ) == 0 ); // Write the user settings version.xml if changed. if (anyLocalChange) GfParmWriteFile( NULL, localVersionHandle, "versions" ); GfParmReleaseHandle( localVersionHandle ); GfParmReleaseHandle( dataVersionHandle ); free( isIndexUsed ); free( filename ); }
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.shortname = GfParmGetStr(results, path2, RE_ATTR_SNAME, 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.shortname = GfParmGetStr(results, path, RE_ATTR_SNAME, 0); 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_SNAME, it->shortname.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
static void UpdateNetworkPlayers() { GfDriver* newDriver; NetNetwork *pNetwork = NetGetNetwork(); if (pNetwork->GetRefreshDisplay() == false) return; tRmInfo* reInfo = LmRaceEngine().inData(); //Set current driver that camera will look at pNetwork->SetCurrentDriver(); //reload xml file NetGetNetwork()->SetRaceXMLFile("config/raceman/networkrace.xml"); reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD); assert(reInfo->params); reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, ""); assert(reInfo->_reName); // Scan each of the human drivers to see if they're active in this race if (NetIsServer()) { NetServerMutexData *pSData = NetGetServer()->LockServerData(); assert(pSData); // Ensure that garage menu knows about driver for (unsigned int i=0; i < pSData->m_vecNetworkPlayers.size(); i++) { newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx); if (!newDriver) { GfLogInfo("Driver %s not found, reloading drivers\n", pSData->m_vecNetworkPlayers[i].name); GfDrivers::self()->reload(); LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true); break; } } for (unsigned int i=0; i < pSData->m_vecNetworkPlayers.size(); i++) { int k = 1; char path2[256]; pSData->m_vecNetworkPlayers[i].active = false; newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx); // Scan through drivers listed in 'networkrace.xml' while (pSData->m_vecNetworkPlayers[i].active == false) { sprintf(path2, "%s/%d", RM_SECT_DRIVERS, k++); if (GfParmExistsSection(reInfo->params, path2) == 0) { GfLogInfo("UpdateNetworkPlayers: Removing driver %s\n", pSData->m_vecNetworkPlayers[i].name); if (pSData->m_vecNetworkPlayers[i].client) { //need to tell/force client to disconnect } break; } if ((tdble)pSData->m_vecNetworkPlayers[i].idx == GfParmGetNum(reInfo->params, path2, RM_ATTR_IDX, NULL, 1.0) && strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, path2, RM_ATTR_MODULE, "")) == 0) { pSData->m_vecNetworkPlayers[i].active = true; } } // add or remove from competitor list (for garage menu) GfDriver* activeDriver = LmRaceEngine().race()->getCompetitor(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx); if (pSData->m_vecNetworkPlayers[i].active) { if (!activeDriver) LmRaceEngine().race()->appendCompetitor(newDriver); } else { if (activeDriver) LmRaceEngine().race()->removeCompetitor(newDriver); } } NetGetServer()->UnlockServerData(); } else { #if 1 // Client XML files already written to disk - this works but is not the best solution.... GfDrivers::self()->reload(); LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true); #endif } //Update track info std::string strTrackPath = GfParmGetStr(reInfo->params, "Tracks/1", RM_ATTR_NAME, ""); std::string strCategory = GfParmGetStr(reInfo->params, "Tracks/1", RM_ATTR_CATEGORY, ""); std::string strTrackName = GetTrackName(strCategory.c_str(),strTrackPath.c_str()); sprintf(buf, "%s", strTrackName.c_str()); GfuiLabelSetText(racemanMenuHdle,g_trackHd,buf); //Store current track - client needs this GfTrack* PCurTrack = GfTracks::self()->getTrackWithName(buf); LmRaceEngine().race()->getManager()->setEventTrack(0, PCurTrack); int laps = (int)GfParmGetNum(reInfo->params, reInfo->_reName,"laps", "", 1); sprintf(buf, "%i", laps); GfuiLabelSetText(racemanMenuHdle,g_lapsHd,buf); GfuiScreenAddBgImg(racemanMenuHdle, GetTrackPreviewFileName(strCategory.c_str(),strTrackPath.c_str()).c_str()); GfuiStaticImageSet(racemanMenuHdle, g_OutlineId, GetTrackOutlineFileName(strCategory.c_str(),strTrackPath.c_str()).c_str()); // Update category info std::string strCarCat; bool bCollisions; NetGetNetwork()->GetHostSettings(strCarCat,bCollisions); GfuiLabelSetText(racemanMenuHdle,g_catHd,strCarCat.c_str()); //fill in player data int nCars = GfParmGetEltNb(reInfo->params, RM_SECT_DRIVERS); char dname[256]; char robpath[256]; float *pColor = &green[0]; bool bEveryoneReadyToRace = true; for (int i = 1; i < nCars+1; i++) { sprintf(dname, "%s/%d", RM_SECT_DRIVERS, i); const char* robot = GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, ""); //lookup playerName and car name sprintf(robpath,"drivers/%s/%s.xml",robot,robot); void *pMod = GfParmReadFileLocal(robpath,GFPARM_RMODE_REREAD); if (pMod == NULL) { //try again in other path sprintf(robpath,"drivers/%s/%s.xml",robot,robot); pMod = GfParmReadFile(robpath,GFPARM_RMODE_REREAD); if (pMod == NULL) continue; } assert(pMod); char ppname[256]; int idx = GfParmGetNum(reInfo->params, dname, RM_ATTR_IDX, "",0); sprintf(ppname,"Robots/index/%d",idx); const char* name = GfParmGetStr(pMod, ppname, RM_ATTR_NAME, ""); const char* car = GfParmGetStr(pMod, ppname, "car name", ""); std::string strRealCar = GfCars::self()->getCar(car)->getName(); // WAIT : pNData->m_vecReadyStatus[i-1] ?! // This can only work when _only_ networkhuman drivers in the race // (that is _no_robot_driver_) ; because m_vecReadyStatus is indexed // by the networkhuman drivers list. // TO fix this, 2 solutions: // 1) make the networking module take care of the robot drivers too // (in m_vecReadyStatus, m_vecNetworkPlayers, ...) // 2) make the networking _menu_ only take care of the networkhuman drivers. bool bReady = bRobotsReady; if(strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, "")) == 0) { // Write car model, as it may have changed via garage menu if (NetIsServer()) { NetServerMutexData *pSData = NetGetServer()->LockServerData(); strncpy(pSData->m_vecNetworkPlayers[idx-1].car, car, 64); GfLogInfo("idx %d car set to %s\n", idx, car); // also need to write back for garage menu const GfCar* newCar = GfCars::self()->getCar(car); newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[idx-1].idx); newDriver->setCar(newCar); NetGetServer()->UnlockServerData(); } //GfLogInfo("idx %d, m_vecReadyStatus.size() %d\n", idx, pNData->m_vecReadyStatus.size()); NetMutexData *pNData = NetGetNetwork()->LockNetworkData(); bReady = pNData->m_vecReadyStatus[idx-1]; NetGetNetwork()->UnlockNetworkData(); } int readyindex = 0; if (bReady) readyindex = 1; else bEveryoneReadyToRace = false; if (strcmp(NetGetNetwork()->GetDriverName(),name)==0) { pColor = &green[0]; g_strCar = strRealCar; //Make sure checkbox matches ready state GfuiCheckboxSetChecked(racemanMenuHdle, g_ReadyCheckboxId, bReady); if (NetGetClient()) EnableMenuClientButtons(bReady); else EnableMenuHostButtons(bReady); } else pColor = &white[0]; GfuiVisibilitySet(racemanMenuHdle,g_readystatus[i-1],true); GfuiStaticImageSetActive(racemanMenuHdle,g_readystatus[i-1],readyindex); GfuiLabelSetColor(racemanMenuHdle, g_playerNames[i-1], pColor); GfuiLabelSetText(racemanMenuHdle,g_playerNames[i-1],name); GfuiLabelSetColor(racemanMenuHdle, g_carNames[i-1], pColor); GfuiLabelSetText(racemanMenuHdle,g_carNames[i-1],strRealCar.c_str()); GfParmReleaseHandle(pMod); } //Clear out rest of table for (int i=nCars;i<MAXNETWORKPLAYERS;i++) { GfuiVisibilitySet(racemanMenuHdle,g_readystatus[i],false); GfuiLabelSetText(racemanMenuHdle,g_playerNames[i],""); GfuiLabelSetText(racemanMenuHdle,g_carNames[i],""); } pNetwork->SetRefreshDisplay(false); GfuiApp().eventLoop().postRedisplay(); if (NetIsClient()) { NetGetClient()->ConnectToClients(); if (!NetGetClient()->TimeSynced()) { NetGetClient()->SendServerTimeRequest(); } } if (NetIsServer()) { if (bEveryoneReadyToRace && nCars > 1) ServerPrepareStartNetworkRace(NULL); } }