diff --git a/src/libs/raceengineclient/CMakeLists.txt b/src/libs/raceengineclient/CMakeLists.txt index 35b3557e8..d18d00c53 100644 --- a/src/libs/raceengineclient/CMakeLists.txt +++ b/src/libs/raceengineclient/CMakeLists.txt @@ -6,13 +6,16 @@ SET(RACEENGINECLIENT_SOURCES racecareer.cpp raceupdate.cpp racenetwork.cpp racec racemessage.cpp racegl.cpp raceinit.cpp racemain.cpp racetrack.cpp raceresults.cpp racesimusimu.cpp racestate.cpp racesituation.cpp + raceutil.cpp racemanmenu.cpp raceselectmenu.cpp networkingmenu.cpp racenexteventmenu.cpp raceconfigstate.cpp raceengineclient.h raceenginemenus.h racecareer.h raceupdate.h racenetwork.h racecars.h racemessage.h racegl.h raceinit.h racetrack.h raceresults.h racesimusimu.h - racestate.h racesituation.h raceselectmenu.h networkingmenu.h) + racestate.h racesituation.h + raceutil.h + raceselectmenu.h networkingmenu.h) ADD_SD_DEFINITIONS() diff --git a/src/libs/raceengineclient/raceconfigstate.cpp b/src/libs/raceengineclient/raceconfigstate.cpp index 958428ff7..9e042e309 100644 --- a/src/libs/raceengineclient/raceconfigstate.cpp +++ b/src/libs/raceengineclient/raceconfigstate.cpp @@ -33,10 +33,10 @@ #include +#include + #include "racesituation.h" -//#include "racemain.h" -//#include "raceinit.h" -//#include "racestate.h" +#include "raceinit.h" #include "raceenginemenus.h" @@ -104,7 +104,7 @@ reConfigBackHookInit(void) } void -ReConfigRunState(void) +ReConfigRunState(bool bStart) { char path[256]; int i; @@ -114,23 +114,35 @@ ReConfigRunState(void) const char *opt; void *params = ReInfo->params; + // TODO: Replace any read/write to params to get/set from/to race/raceman instances ? + + // Reset config automaton to the "start" state if specified. + if (bStart) + GfParmSetNum(params, RM_SECT_CONF, RM_ATTR_CUR_CONF, NULL, 1); + + // If configuration finished, save race config to disk and go back to the raceman menu. curConf = (int)GfParmGetNum(params, RM_SECT_CONF, RM_ATTR_CUR_CONF, NULL, 1); if (curConf > GfParmGetEltNb(params, RM_SECT_CONF)) { GfLogInfo("%s configuration finished.\n", ReInfo->_reName); - GfParmWriteFile(NULL, ReInfo->params, ReInfo->_reName); - GfuiScreenActivate(ReGetRacemanMenuHandle()); /* Back to the race manager menu */ + ReGetRace()->save(); // Save race data to params. + GfParmWriteFile(NULL, params, ReInfo->_reName); // Save params to disk. + GfuiScreenActivate(ReGetRacemanMenuHandle()); // Back to the race manager menu return; } - + + // If wrong configuration data, back to the raceman menu. snprintf(path, sizeof(path), "%s/%d", RM_SECT_CONF, curConf); conf = GfParmGetStr(params, path, RM_ATTR_TYPE, 0); if (!conf) { - GfLogError("No %s here (%s) !\n", RM_ATTR_TYPE, path); + GfLogError("No '%s' field in '%s' section of %s\n", + RM_ATTR_TYPE, path, GfParmGetFileName(params)); GfuiScreenActivate(ReGetRacemanMenuHandle()); /* Back to the race manager menu */ return; } + // Normal configuration steps : GfLogInfo("%s configuration now in '%s' stage.\n", ReInfo->_reName, conf); + if (!strcmp(conf, RM_VAL_TRACKSEL)) { /* Track Select Menu */ @@ -140,7 +152,7 @@ ReConfigRunState(void) } else { ts.prevScreen = reConfigBackHookInit(); } - ts.param = ReInfo->params; + ts.pRace = ReGetRace(); ts.trackItf = ReInfo->_reTrackItf; RmTrackSelect(&ts); @@ -153,7 +165,7 @@ ReConfigRunState(void) } else { ds.prevScreen = reConfigBackHookInit(); } - ds.param = ReInfo->params; + ds.pRace = ReGetRace(); RmDriversSelect(&ds); } else if (!strcmp(conf, RM_VAL_RACECONF)) { @@ -165,8 +177,7 @@ ReConfigRunState(void) } else { rp.prevScreen = reConfigBackHookInit(); } - rp.param = ReInfo->params; - rp.title = GfParmGetStr(params, path, RM_ATTR_RACE, "Race"); + rp.pRace = ReGetRace(); /* Select options to configure */ rp.confMask = 0; diff --git a/src/libs/raceengineclient/raceenginemenus.h b/src/libs/raceengineclient/raceenginemenus.h index 754892458..15c309ebd 100644 --- a/src/libs/raceengineclient/raceenginemenus.h +++ b/src/libs/raceengineclient/raceenginemenus.h @@ -29,14 +29,14 @@ #include "raceengineclient.h" -RACEENGINECLIENT_API int ReRacemanMenu(void); +RACEENGINECLIENT_API int ReRacemanMenu(); RACEENGINECLIENT_API int ReNextEventMenu(void); RACEENGINECLIENT_API void ReConfigureRace(void * /* dummy */); RACEENGINECLIENT_API void ReSetRacemanMenuHandle(void * handle); extern void* ReGetRacemanMenuHandle(); -extern void ReConfigRunState(void); +extern void ReConfigRunState(bool bStart = false); #endif /* _RACEENGINEMENU_H_ */ diff --git a/src/libs/raceengineclient/raceinit.cpp b/src/libs/raceengineclient/raceinit.cpp index acc4bf151..8994d61e9 100644 --- a/src/libs/raceengineclient/raceinit.cpp +++ b/src/libs/raceengineclient/raceinit.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -49,12 +50,22 @@ #include "raceinit.h" -static const char *level_str[] = { ROB_VAL_ROOKIE, ROB_VAL_AMATEUR, ROB_VAL_SEMI_PRO, ROB_VAL_PRO }; +static const char *level_str[] = + { ROB_VAL_ROOKIE, ROB_VAL_AMATEUR, ROB_VAL_SEMI_PRO, ROB_VAL_PRO }; static tModList *reEventModList = 0; +// Modules ... ? tModList *ReRaceModList = 0; +// The race (temporary partially duplicates ReInfo, as long as not merged). +static GfRace* PReRace = 0; + +GfRace* ReGetRace() +{ + return PReRace; +} + /* Race Engine Initialization */ void @@ -156,24 +167,60 @@ ReStartNewRace(void * /* dummy */) } +// Select the given manager for the race. +void +ReRaceSelectRaceman(GfRaceManager* pRaceMan) +{ + // Trace the chosen raceman full type. + std::string strFullType(pRaceMan->getType()); + if (!pRaceMan->getSubType().empty()) + { + strFullType += " / "; + strFullType += pRaceMan->getSubType(); + } + GfLogTrace("'%s' race type selected\n", strFullType.c_str()); + + // Re-init. race engine info about the race. + ReInfo->mainParams = ReInfo->params = pRaceMan->getDescriptorHandle(); + ReInfo->_reName = pRaceMan->getName().c_str(); + ReInfo->_reFilename = pRaceMan->getId().c_str(); + + GfParmRemoveVariable (ReInfo->params, "/", "humanInGroup"); + GfParmSetVariable (ReInfo->params, "/", "humanInGroup", ReHumanInGroup() ? 1 : 0); +} + // Start configuring a race for the given manager void -ReRaceConfigure(GfRaceManager* pRaceman) +ReRaceConfigure(GfRaceManager* pRaceMan) { - ReInfo->mainParams = ReInfo->params = pRaceman->getDescriptorHandle(); - ReInfo->_reName = pRaceman->getName().c_str(); - ReInfo->_reFilename = pRaceman->getId().c_str(); + // Select the given race manager for the race. + ReRaceSelectRaceman(pRaceMan); + + // If not already done, instanciate the race. + if (!PReRace) + PReRace = new GfRace(); + + // (Re-)initialize it from the selected race manager. + PReRace->load(pRaceMan); + + // Enter CONFIG state. + ReStateApply(RE_STATE_CONFIG); +} - std::string strFullType(pRaceman->getType()); - if (!pRaceman->getSubType().empty()) - { - strFullType += " / "; - strFullType += pRaceman->getSubType(); - } - GfLogTrace("%s selected\n", strFullType.c_str()); - - // Enter CONFIG state. - ReStateApply(RE_STATE_CONFIG); +// Restore the race from the given result file +void +ReRaceRestore(GfRaceManager* pRaceMan, const char *pszResultFileName) +{ + // Select the given race manager for the race. + ReRaceSelectRaceman(pRaceMan); + + // Update race engine info. + ReInfo->mainResults = GfParmReadFile(pszResultFileName, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); + ReInfo->results = ReInfo->mainResults; + ReInfo->_reRaceName = ReInfo->_reName; + + // Fire standings screen. + RmShowStandings(ReInfo->_reGameScreen, ReInfo); } /* diff --git a/src/libs/raceengineclient/raceinit.h b/src/libs/raceengineclient/raceinit.h index 7760ee6c5..e2e7345e2 100644 --- a/src/libs/raceengineclient/raceinit.h +++ b/src/libs/raceengineclient/raceinit.h @@ -29,6 +29,7 @@ #include "raceengineclient.h" class GfRaceManager; +class GfRace; RACEENGINECLIENT_API void ReStartNewRace(void * /* dummy */); @@ -36,7 +37,9 @@ RACEENGINECLIENT_API void ReStartNewRace(void * /* dummy */); extern void ReInit(void); extern void ReShutdown(void); -extern void ReRaceConfigure(GfRaceManager* pRaceman); +extern void ReRaceSelectRaceman(GfRaceManager* pRaceMan); +extern void ReRaceRestore(GfRaceManager* pRaceMan, const char *pszResultFileName); +extern void ReRaceConfigure(GfRaceManager* pRaceMan); extern int ReInitCars(void); @@ -51,6 +54,9 @@ extern char *ReGetPrevRaceName(void); extern tModList *ReRaceModList; +// The race (temporarily partly duplicates ReInfo, as long as not merged together). +extern GfRace* ReGetRace(); + #endif /* _RACEINIT_H_ */ diff --git a/src/libs/raceengineclient/racemain.cpp b/src/libs/raceengineclient/racemain.cpp index 31c3da040..064338798 100644 --- a/src/libs/raceengineclient/racemain.cpp +++ b/src/libs/raceengineclient/racemain.cpp @@ -28,6 +28,7 @@ #include #include +#include "raceutil.h" // RmGetFeaturesList #include "racesituation.h" #include "racecareer.h" #include "raceinit.h" diff --git a/src/libs/raceengineclient/racemanmenu.cpp b/src/libs/raceengineclient/racemanmenu.cpp index 1604a25d0..fdc04f9eb 100644 --- a/src/libs/raceengineclient/racemanmenu.cpp +++ b/src/libs/raceengineclient/racemanmenu.cpp @@ -23,14 +23,15 @@ @version $Id$ */ -#include -#include #include +#include +#include #include +#include #include -#include + #include #include #include @@ -79,41 +80,37 @@ void* ReGetRacemanMenuHandle() void ReConfigureRace(void * /* dummy */) { - void *params = ReInfo->params; - - /* Reset configuration automaton */ - GfParmSetNum(params, RM_SECT_CONF, RM_ATTR_CUR_CONF, NULL, 1); - ReConfigRunState(); + ReConfigRunState(/*bStart=*/true); } -static char* -reGetLoadFileDir(char* pszDirPath, int nMaxLen) +// TODO: ossPathDirPath ... +static std::string +reGetLoadFileDir() { - void *params = ReInfo->params; + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); // For race types with more than 1 event (= 1 race on 1 track), load a race result file, // as the previous race standings has an influence on the next race starting grid. - if (GfParmGetEltNb(params, RM_SECT_TRACKS) > 1) - snprintf(pszDirPath, nMaxLen, "%sresults/%s", GfLocalDir(), ReInfo->_reFilename); + std::string strDirPath(GfLocalDir()); + if (pRaceMan->getEventCount() > 1) + strDirPath += "results/"; + // But for race types with only 1 event (= 1 race on 1 track), load a race config file. else - snprintf(pszDirPath, nMaxLen, "%sconfig/raceman/%s", GfLocalDir(), ReInfo->_reFilename); + strDirPath += "config/raceman/"; + + strDirPath += pRaceMan->getId(); - return pszDirPath; + return strDirPath; } static bool reCanLoadRace() { - void *params = ReInfo->params; - - // Determine the source folder. - char pszDirPath[256]; - reGetLoadFileDir(pszDirPath, sizeof(pszDirPath)); - // Get the list of files in the target folder. - tFList *pFileList = GfDirGetListFiltered(pszDirPath, "", PARAMEXT); + std::string strDirPath = reGetLoadFileDir(); + tFList *pFileList = GfDirGetListFiltered(strDirPath.c_str(), "", PARAMEXT); // Now we know what to answer. const bool bAnswer = (pFileList != 0); @@ -128,25 +125,24 @@ reCanLoadRace() static bool reCanSaveRace() { - void *params = ReInfo->params; + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); // Multi-events race types are automatically saved in config/raceman/results - return GfParmGetEltNb(params, RM_SECT_TRACKS) == 1; + return pRaceMan->getEventCount() == 1; } static void reOnRaceDataChanged() { - char buf[128]; - void *params = ReInfo->params; + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); - // Retrieve track infos. - const char* pszTrackId = GfParmGetStr(ReInfo->params, "Tracks/1", RM_ATTR_NAME, ""); - const GfTrack* pTrack = GfTracks::self()->getTrack(pszTrackId); + // Get the current track. + const GfTrack* pTrack = ReGetRace()->getTrack(); // Set title (race type + track name). - snprintf(buf, sizeof(buf), "%s at %s", ReInfo->_reName, pTrack->getName().c_str()); - GfuiLabelSetText(ScrHandle, TitleLabelId, buf); + std::ostringstream ossText; + ossText << pRaceMan->getName() << " at " << pTrack->getName(); + GfuiLabelSetText(ScrHandle, TitleLabelId, ossText.str().c_str()); // Display track name, outline image and preview image GfuiScreenAddBgImg(ScrHandle, pTrack->getPreviewFile().c_str()); @@ -158,86 +154,64 @@ reOnRaceDataChanged() GfuiEnable(ScrHandle, SaveRaceButtonId, reCanSaveRace() ? GFUI_ENABLE : GFUI_DISABLE); - // Re-load competitors scroll list from the race file. + // Re-load competitors scroll list from the race. GfuiScrollListClear(ScrHandle, CompetitorsScrollListId); VecCompetitorsInfo.clear(); - const int nCompetitors = GfParmGetEltNb(ReInfo->params, RM_SECT_DRIVERS); - for (int nCompIndex = 1; nCompIndex <= nCompetitors; nCompIndex++) + const std::vector& vecCompetitors = ReGetRace()->getCompetitors(); + for (int nCompIndex = 0; nCompIndex < (int)vecCompetitors.size(); nCompIndex++) { - snprintf(buf, sizeof(buf), "%s/%d", RM_SECT_DRIVERS, nCompIndex); - const char* pszCompModuleName = GfParmGetStr(ReInfo->params, buf, RM_ATTR_MODULE, ""); - int nCompItfIdx = (int)GfParmGetNum(ReInfo->params, buf, RM_ATTR_IDX, (char*)NULL, 0); - - const GfDriver* pComp = - GfDrivers::self()->getDriver(pszCompModuleName, nCompItfIdx); - if (pComp) - { - snprintf(buf, sizeof(buf), "%s (%s)", pComp->getName().c_str(), pComp->getCar()->getName().c_str()); - VecCompetitorsInfo.push_back(buf); - GfuiScrollListInsertElement(ScrHandle, CompetitorsScrollListId, - VecCompetitorsInfo.back().c_str(), nCompIndex, (void*)pComp); - GfLogDebug("Added competitor %s (%s#%d)\n", buf, pszCompModuleName, nCompItfIdx); - } - else - GfLogWarning("Ignoring competitor %s#%d (no such driver available)\n", - pszCompModuleName, nCompItfIdx); + const GfDriver* pComp = vecCompetitors[nCompIndex]; + ossText.str(""); + ossText << pComp->getName() << " (" << pComp->getCar()->getName() << ')'; + VecCompetitorsInfo.push_back(ossText.str()); + GfuiScrollListInsertElement(ScrHandle, CompetitorsScrollListId, + VecCompetitorsInfo.back().c_str(), nCompIndex+1, (void*)pComp); + GfLogDebug("Added competitor %s (%s#%d)\n", ossText.str().c_str(), + pComp->getModuleName().c_str(), pComp->getInterfaceIndex()); } } static void reLoadRaceFromResultsFile(const char *filename) { - char pszFileName[256]; + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); - snprintf(pszFileName, sizeof(pszFileName), "%sresults/%s/%s", GfLocalDir(), ReInfo->_reFilename, filename); - GfLogInfo("Loading saved race from %s ...\n", pszFileName); + // Determine the full path-name of the result file. + std::ostringstream ossResFileName; + ossResFileName << GfLocalDir() << "results/" << pRaceMan->getId() << '/' << filename; - // Update race data. - ReInfo->mainResults = GfParmReadFile(pszFileName, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); - ReInfo->results = ReInfo->mainResults; - ReInfo->_reRaceName = ReInfo->_reName; - - GfParmRemoveVariable (ReInfo->params, "/", "humanInGroup"); - GfParmSetVariable (ReInfo->params, "/", "humanInGroup", ReHumanInGroup() ? 1 : 0); + GfLogInfo("Restoring race from results %s ...\n", ossResFileName.str().c_str()); - // Fire standings screen. - RmShowStandings(ReInfo->_reGameScreen, ReInfo); + // Restore the race from the result file. + ReRaceRestore(ReGetRace()->getManager(), ossResFileName.str().c_str()); } static void reLoadRaceFromConfigFile(const char *filename) { - char pszSelFilePathName[256]; - snprintf(pszSelFilePathName, sizeof(pszSelFilePathName), "%sconfig/raceman/%s/%s", - GfLocalDir(), ReInfo->_reFilename, filename); - GfLogInfo("Loading saved race from %s ...\n", pszSelFilePathName); + GfRaceManager* pRaceMan = ReGetRace()->getManager(); - // Replace the main race file by the selected one. - char pszMainFilePathName[256]; - snprintf(pszMainFilePathName, sizeof(pszMainFilePathName), "%sconfig/raceman/%s%s", - GfLocalDir(), ReInfo->_reFilename, PARAMEXT); - if (!GfFileCopy(pszSelFilePathName, pszMainFilePathName)) + // Determine the full path-name of the selected race config file. + std::ostringstream ossSelFileName; + ossSelFileName << GfLocalDir() << "config/raceman/" << pRaceMan->getId() << '/' << filename; + + GfLogInfo("Loading saved race from config %s ...\n", ossSelFileName.str().c_str()); + + // Replace the main race config file by the selected one. + const std::string strMainFileName = pRaceMan->getDescriptorFileName(); + if (!GfFileCopy(ossSelFileName.str().c_str(), strMainFileName.c_str())) { - GfLogError("Failed to load selected race file %s", pszSelFilePathName); + GfLogError("Failed to load selected race config file %s", strMainFileName.c_str()); return; } - // Update race data. - GfParmReleaseHandle(ReInfo->params); - ReInfo->mainParams = ReInfo->params = GfParmReadFile(pszMainFilePathName, GFPARM_RMODE_STD); - ReInfo->_reName = GfParmGetStr(ReInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, ""); - ReInfo->_reRaceName = ReInfo->_reName; + // Update the race manager. + void* hparmRaceMan = GfParmReadFile(strMainFileName.c_str(), GFPARM_RMODE_STD); + pRaceMan->reset(hparmRaceMan, /* bClosePrevHdle= */ true); + + // Notify the race engine of the changes. + ReRaceSelectRaceman(pRaceMan); - GfParmRemoveVariable (ReInfo->params, "/", "humanInGroup"); - GfParmSetVariable (ReInfo->params, "/", "humanInGroup", ReHumanInGroup() ? 1 : 0); - - // Update the race manager (the params handle changed). - GfRaceManager* pRaceMan = GfRaceManagers::self()->getRaceManager(ReInfo->_reFilename); - if (pRaceMan) - pRaceMan->setDescriptorHandle(ReInfo->params); - else - GfLogError("No such race manager (id=%s)\n", ReInfo->_reFilename); - // Update GUI. reOnRaceDataChanged(); } @@ -246,22 +220,19 @@ static void reSaveRaceToConfigFile(const char *filename) { // Note: No need to write the main file here, already done at the end of race configuration. - char pszMainFilePathName[256]; - snprintf(pszMainFilePathName, sizeof(pszMainFilePathName), "%sconfig/raceman/%s%s", - GfLocalDir(), ReInfo->_reFilename, PARAMEXT); + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); - // Add .xml extension if not there. - char pszSelFilePathName[256]; - snprintf(pszSelFilePathName, sizeof(pszSelFilePathName), "%sconfig/raceman/%s/%s", - GfLocalDir(), ReInfo->_reFilename, filename); - const char* pszFileExt = strrchr(pszSelFilePathName, '.'); - if (!pszFileExt || strcmp(pszFileExt, PARAMEXT)) - strcat(pszSelFilePathName, PARAMEXT); + // Determine the full path-name of the target race config file (add .xml ext. if not there). + std::ostringstream ossTgtFileName; + ossTgtFileName << GfLocalDir() << "config/raceman/" << pRaceMan->getId() << '/' << filename; + if (ossTgtFileName.str().rfind(PARAMEXT) != ossTgtFileName.str().length() - strlen(PARAMEXT)) + ossTgtFileName << PARAMEXT; // Copy the main file to the selected one (overwrite if already there). - GfLogInfo("Saving race config to %s ...\n", pszSelFilePathName); - if (!GfFileCopy(pszMainFilePathName, pszSelFilePathName)) - GfLogError("Failed to save race to selected config file %s", pszSelFilePathName); + const std::string strMainFileName = pRaceMan->getDescriptorFileName(); + GfLogInfo("Saving race config to %s ...\n", strMainFileName.c_str()); + if (!GfFileCopy(strMainFileName.c_str(), ossTgtFileName.str().c_str())) + GfLogError("Failed to save race to selected config file %s", ossTgtFileName.str().c_str()); } static void @@ -287,18 +258,18 @@ reOnPlayerConfig(void * /* dummy */) static void reOnLoadRaceFromFile(void *pPrevMenu) { - void *params = ReInfo->params; - - fs.title = ReInfo->_reName; + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); + + fs.title = pRaceMan->getName(); fs.prevScreen = pPrevMenu; fs.mode = RmFSModeLoad; - char pszDirPath[256]; - fs.path = reGetLoadFileDir(pszDirPath, 256); + std::string strDirPath = reGetLoadFileDir(); + fs.path = strDirPath; // For race types with more than 1 event (= 1 race on 1 track), load a race result file, // as the previous race standings has an influence on the next race starting grid. - if (GfParmGetEltNb(params, RM_SECT_TRACKS) > 1) + if (pRaceMan->getEventCount() > 1) fs.select = reLoadRaceFromResultsFile; // But for race types with only 1 event (= 1 race on 1 track), load a race config file. @@ -312,17 +283,16 @@ reOnLoadRaceFromFile(void *pPrevMenu) static void reOnSaveRaceToFile(void *pPrevMenu) { - void *params = ReInfo->params; - + const GfRaceManager* pRaceMan = ReGetRace()->getManager(); + // Fill-in file selection descriptor - fs.title = ReInfo->_reName; + fs.title = pRaceMan->getName(); fs.prevScreen = pPrevMenu; fs.mode = RmFSModeSave; - char pszDirPath[256]; - snprintf(pszDirPath, sizeof(pszDirPath), "%sconfig/raceman/%s", - GfLocalDir(), ReInfo->_reFilename); - fs.path = pszDirPath; + fs.path = GfLocalDir(); + fs.path += "config/raceman/"; + fs.path += pRaceMan->getId(); fs.select = reSaveRaceToConfigFile; @@ -341,10 +311,8 @@ reOnActivate(void * /* dummy */) } int -ReRacemanMenu(void) +ReRacemanMenu() { - void *params = ReInfo->params; - // Special case of the online race. if (!strcmp(ReInfo->_reName, "Online Race")) { diff --git a/src/libs/raceengineclient/raceselectmenu.cpp b/src/libs/raceengineclient/raceselectmenu.cpp index 39bb4a7dc..b7e876b85 100644 --- a/src/libs/raceengineclient/raceselectmenu.cpp +++ b/src/libs/raceengineclient/raceselectmenu.cpp @@ -23,8 +23,6 @@ @version $Id$ */ -#include -#include #include #include @@ -46,7 +44,7 @@ static std::map reMapSubTypeComboIds; /* Called when the menu is activated */ static void -reOnRaceSelectMenuActivate(void * /* dummy */) +reOnActivate(void * /* dummy */) { /* Race engine init */ ReInit(); @@ -88,6 +86,7 @@ reOnSelectRaceMan(void *pvRaceManTypeIndex) } } } + // If only 1, no choice. else if (vecRaceMans.size() == 1) { @@ -114,7 +113,7 @@ ReRaceSelectInit(void *prevMenu) // Create screen, load menu XML descriptor and create static controls. reRaceSelectHandle = GfuiScreenCreateEx((float*)NULL, - NULL, reOnRaceSelectMenuActivate, + NULL, reOnActivate, NULL, (tfuiCallback)NULL, 1); void *hMenuXMLDesc = LoadMenuXML("raceselectmenu.xml"); diff --git a/src/libs/raceengineclient/racestate.cpp b/src/libs/raceengineclient/racestate.cpp index 99090d8d8..82478459b 100644 --- a/src/libs/raceengineclient/racestate.cpp +++ b/src/libs/raceengineclient/racestate.cpp @@ -27,7 +27,9 @@ #include #include + #include + #include #include "racesituation.h" diff --git a/src/libs/raceengineclient/racetrack.cpp b/src/libs/raceengineclient/racetrack.cpp index 078411cfd..2a000329b 100644 --- a/src/libs/raceengineclient/racetrack.cpp +++ b/src/libs/raceengineclient/racetrack.cpp @@ -322,7 +322,7 @@ reTrackInitWeather(void) else rain = TR_RAIN_HEAVY; - // Whatever rain level, heavy clouds. + // Whatever rain level (except for none), heavy clouds. clouds = TR_CLOUDS_FULL; } else @@ -336,6 +336,12 @@ reTrackInitWeather(void) pszWeatherSelect = "randomly selected"; } + else + { + if (rain != TR_RAIN_NONE) + // Whatever rain level (except for none), heavy clouds. + clouds = TR_CLOUDS_FULL; + } // Ground water = rain for the moment (might change in the future). const int water = rain; diff --git a/src/libs/racescreens/util.cpp b/src/libs/raceengineclient/raceutil.cpp similarity index 77% rename from src/libs/racescreens/util.cpp rename to src/libs/raceengineclient/raceutil.cpp index fb25d12ca..2f0a28672 100644 --- a/src/libs/racescreens/util.cpp +++ b/src/libs/raceengineclient/raceutil.cpp @@ -1,15 +1,37 @@ -/** - * This file contains function which can also be used by raceengineclient. - * This function is needed in both modules - * - * Copyright (C) 2006, Mart Kelder - */ +/************************************************************************** -#include -#include "racescreens.h" + file : racemain.cpp + created : Sat Nov 16 12:13:31 CET 2006 + copyright : (C) 2006 Mart Kelder + email : mart@kelder31.nl + 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 + Useful functions for race engine + @author Mart Kelder + @version $Id$ +*/ + +#include +#include "raceutil.h" #include + +// TODO: When the race engine will have been moved to using tgfdata (it is not at present), +// remove RmGetFeaturesList (use GfRace::getSupportedFeatures). + static const int nMaxFeatureNameLength = 30; typedef struct Feature diff --git a/src/libs/raceengineclient/raceutil.h b/src/libs/raceengineclient/raceutil.h new file mode 100644 index 000000000..2590b9e12 --- /dev/null +++ b/src/libs/raceengineclient/raceutil.h @@ -0,0 +1,34 @@ +/*************************************************************************** + + file : racestate.h + created : Sat Nov 16 14:05:06 CET 2006 + copyright : (C) 2006 Mart Kelder + email : mart@kelder31.nl + 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 + Useful functions for race engine + @author Mart Kelder + @version $Id$ +*/ + +#ifndef _RACEUTIL_H_ +#define _RACEUTIL_H_ + +extern int RmGetFeaturesList(void* param); + +#endif /* _RACEUTIL_H_ */ + + + diff --git a/src/libs/racescreens/CMakeLists.txt b/src/libs/racescreens/CMakeLists.txt index 95b1f5ff8..e806f12f3 100644 --- a/src/libs/racescreens/CMakeLists.txt +++ b/src/libs/racescreens/CMakeLists.txt @@ -5,7 +5,6 @@ INCLUDE(../../../cmake/macros.cmake) SET(RACESCREENS_SOURCES carselect.cpp driverselect.cpp fileselect.cpp loadingscreen.cpp miscscreens.cpp pitmenu.cpp raceparamsmenu.cpp results.cpp trackselect.cpp - util.cpp racescreens.h) ADD_INTERFACE_INCLUDEDIR() diff --git a/src/libs/racescreens/driverselect.cpp b/src/libs/racescreens/driverselect.cpp index a962b5904..dc4888a1f 100644 --- a/src/libs/racescreens/driverselect.cpp +++ b/src/libs/racescreens/driverselect.cpp @@ -25,9 +25,6 @@ */ -#include -#include -#include #include #include @@ -90,16 +87,13 @@ static size_t CurDriverTypeIndex = 0; static std::vector VecCurDriverPossSkins; static size_t CurSkinIndex = 0; -// The current race. -GfRace TheRace; - // The current driver // (the last one the user clicked on, shown as highligthed in one of the scroll-lists). GfDriver* PCurrentDriver; // Local functions. static void rmdsFilterCandidatesScrollList(const std::string& strCarCatId, - const std::string& strType); + const std::string& strType); static void rmdsClickOnDriver(void * /* dummy */); @@ -157,12 +151,12 @@ rmdsReloadCompetitorsScrollList() GfuiScrollListClear(ScrHandle, CompetitorsScrollListId); // For each competitor in the race : - std::vector vecCompetitors = TheRace.getCompetitors(); + std::vector vecCompetitors = MenuData->pRace->getCompetitors(); std::vector::iterator itComp; for (itComp = vecCompetitors.begin(); itComp != vecCompetitors.end(); itComp++) // Add its name to the Competitors scroll list. GfuiScrollListInsertElement(ScrHandle, CompetitorsScrollListId, (*itComp)->getName().c_str(), - TheRace.getCompetitorsCount(), (void*)(*itComp)); + MenuData->pRace->getCompetitorsCount(), (void*)(*itComp)); } // Screen activation call-back. @@ -199,8 +193,6 @@ rmdsCleanup(void) VecCarCategoryNames.clear(); VecDriverTypes.clear(); VecCurDriverPossSkins.clear(); - - TheRace.clear(); } // Screen de-activation call-back. @@ -294,7 +286,7 @@ static void rmdsNextMenu(void * /* dummy */) { // Save the race data to its params file - TheRace.save(); + MenuData->pRace->save(); // Finally, go back to the caller menu. rmdsDeactivate(MenuData->nextScreen); @@ -326,7 +318,7 @@ rmdsMoveCompetitor(void *vd) GfuiScrollListMoveSelectedElement(ScrHandle, CompetitorsScrollListId, (int)(long)vd); // Move the competitor in the race. - TheRace.moveCompetitor(PCurrentDriver, (int)(long)vd); + MenuData->pRace->moveCompetitor(PCurrentDriver, (int)(long)vd); } } @@ -402,21 +394,21 @@ rmdsSelectDeselectDriver(void * /* dummy */ ) const char* name; int src, dst; GfDriver *pDriver; - int sel; + bool bSelect; // If the selected driver is in the Candidate scroll-list, // and if the max number of selected drivers has not been reached, // remove the driver from the Candidate scroll-list, // and add him to the Competitors scroll-list and to the race competitors. - sel = 0; + bSelect = false; name = 0; - if (TheRace.acceptsMoreCompetitors()) { + if (MenuData->pRace->acceptsMoreCompetitors()) { src = CandidatesScrollListId; name = GfuiScrollListExtractSelectedElement(ScrHandle, src, (void**)&pDriver); if (name) { dst = CompetitorsScrollListId; GfuiScrollListInsertElement(ScrHandle, dst, name, GfDrivers::self()->getCount(), (void*)pDriver); - TheRace.appendCompetitor(pDriver); // Now selected. + MenuData->pRace->appendCompetitor(pDriver); // Now selected. } } @@ -425,7 +417,7 @@ rmdsSelectDeselectDriver(void * /* dummy */ ) // and add him to the Candidate scroll-list // (if it matches the Candidate scroll-list filtering criteria) if (!name) { - sel = 1; + bSelect = true; src = CompetitorsScrollListId; name = GfuiScrollListExtractSelectedElement(ScrHandle, src, (void**)&pDriver); if (name) { @@ -440,39 +432,33 @@ rmdsSelectDeselectDriver(void * /* dummy */ ) GfuiScrollListInsertElement(ScrHandle, dst, name, pDriver->isHuman() ? 0 : GfDrivers::self()->getCount(), (void*)pDriver); } - TheRace.removeCompetitor(pDriver); // No more selected. + MenuData->pRace->removeCompetitor(pDriver); // No more selected. } else { return; } } // Focused driver management (inhibited for the moment : what is it useful for ?) - const char *modName = GfParmGetStr(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, ""); - int robotIdx = (int)GfParmGetNum(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, (char*)NULL, 0); - if (sel) { - modName = GfParmGetStr(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, ""); - robotIdx = (int)GfParmGetNum(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, (char*)NULL, 0); - if (pDriver->getInterfaceIndex() == robotIdx && pDriver->getModuleName() == modName) { + const GfDriver* pFocDriver = MenuData->pRace->getFocusedCompetitor(); + if (bSelect) { + if (MenuData->pRace->isCompetitorFocused(pDriver)) { /* the focused element was deselected : select a new one */ name = GfuiScrollListGetElement(ScrHandle, CompetitorsScrollListId, 0, (void**)&pDriver); if (name) { - GfParmSetStr(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, pDriver->getModuleName().c_str()); - GfParmSetNum(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, (char*)NULL, pDriver->getInterfaceIndex()); + MenuData->pRace->setFocusedCompetitor(pDriver); #ifdef FOCUS GfuiLabelSetText(ScrHandle, FocusedDriverLabelId, pDriver->getName.c_str()); #endif } else { - GfParmSetStr(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, ""); - GfParmSetNum(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, (char*)NULL, 0); + MenuData->pRace->setFocusedCompetitor(0); #ifdef FOCUS GfuiLabelSetText(ScrHandle, FocusedDriverLabelId, ""); #endif } } } else { - if (strlen(modName) == 0 || pDriver->isHuman()) { - GfParmSetStr(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, pDriver->getModuleName().c_str()); - GfParmSetNum(MenuData->param, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, (char*)NULL, pDriver->getInterfaceIndex()); + if (!pFocDriver || pDriver->isHuman()) { + MenuData->pRace->setFocusedCompetitor(pDriver); #ifdef FOCUS GfuiLabelSetText(ScrHandle, FocusedDriverLabelId, pDriver->getName().c_str()); #endif @@ -483,7 +469,7 @@ rmdsSelectDeselectDriver(void * /* dummy */ ) rmdsClickOnDriver(0); // Don't allow user to Accept 0 drivers, this would cause a crash. - GfuiEnable(ScrHandle, NextButtonId, TheRace.getCompetitorsCount() > 0 ? GFUI_ENABLE : GFUI_DISABLE); + GfuiEnable(ScrHandle, NextButtonId, MenuData->pRace->getCompetitorsCount() > 0 ? GFUI_ENABLE : GFUI_DISABLE); // For a smart display refresh, when automatically called multiple time. GfuiDisplay(); @@ -520,7 +506,7 @@ rmdsSelectRandomCandidates(void * /* dummy */ ) unsigned nCount = 1; int nCandidates; while (nCount <= nRandomCompetitors - && TheRace.acceptsMoreCompetitors() + && MenuData->pRace->acceptsMoreCompetitors() && (nCandidates = GfuiScrollListGetNumberOfElements(ScrHandle, CandidatesScrollListId)) > 0) { // Pick-up a random candidate from the candidate scroll-list. @@ -541,7 +527,7 @@ static void rmdsShuffleCompetitors(void * /* dummy */ ) { // Shuffle the race competitor list and reload the scroll-list. - TheRace.shuffleCompetitors(); + MenuData->pRace->shuffleCompetitors(); rmdsReloadCompetitorsScrollList(); // Re-highlight the previously highlighted driver if any @@ -646,15 +632,12 @@ RmDriversSelect(void *vs) GfuiMenuDefaultKeysAdd(ScrHandle); rmdsAddKeys(); - // Load the race data from the params file. - TheRace.load(MenuData->param); - // Fill-in the competitors scroll-list. rmdsReloadCompetitorsScrollList(); // Initialize the currently highlighted driver. PCurrentDriver = 0; - std::vector vecCompetitors = TheRace.getCompetitors(); + std::vector vecCompetitors = MenuData->pRace->getCompetitors(); std::vector::iterator itComp; for (itComp = vecCompetitors.begin(); itComp != vecCompetitors.end(); itComp++) // Initialize the current driver (the last human driver, or else of the last driver). @@ -675,7 +658,7 @@ rmdsFilterCandidatesScrollList(const std::string& strCarCatId, const std::string GfuiEnable(ScrHandle, SelectButtonId, GFUI_DISABLE); // Fill it with drivers that match the filter criteria and are not among competitors. - const std::vector& vecCompetitors = TheRace.getCompetitors(); + const std::vector& vecCompetitors = MenuData->pRace->getCompetitors(); const std::string strCarCatIdFilter = (strCarCatId == AnyCarCategory ? "" : strCarCatId); const std::string strTypeFilter = (strType == AnyDriverType ? "" : strType); const std::vector vecCandidates = diff --git a/src/libs/racescreens/fileselect.cpp b/src/libs/racescreens/fileselect.cpp index 2b9edbc6a..7b4b7a888 100644 --- a/src/libs/racescreens/fileselect.cpp +++ b/src/libs/racescreens/fileselect.cpp @@ -46,7 +46,7 @@ rmOnActivate(void * /* dummy */ ) // Fill-in the Scroll List with the names of the files in the specified folder. GfuiScrollListClear(ScrHandle, FilesScrollListId); - FileList = GfDirGetList(RmFs->path); + FileList = GfDirGetList(RmFs->path.c_str()); if (FileList) { tFList *fileCur; @@ -135,7 +135,7 @@ RmFileSelect(void *pFileSelect) // Create variable title label. const int titleId = CreateLabelControl(ScrHandle, menuXMLDescHdle, "TitleLabel"); - GfuiLabelSetText(ScrHandle, titleId, RmFs->title); + GfuiLabelSetText(ScrHandle, titleId, RmFs->title.c_str()); // Create the Scroll List containing the File list FilesScrollListId = CreateScrollListControl(ScrHandle, menuXMLDescHdle, "FilesScrollList", diff --git a/src/libs/racescreens/raceparamsmenu.cpp b/src/libs/racescreens/raceparamsmenu.cpp index c4bc395a0..270519500 100644 --- a/src/libs/racescreens/raceparamsmenu.cpp +++ b/src/libs/racescreens/raceparamsmenu.cpp @@ -33,30 +33,28 @@ #include #include + #include #include #include #include #include +#include + #include "racescreens.h" // Constants. -static const char *DispModeValues[] = { RM_VAL_VISIBLE, RM_VAL_INVISIBLE}; - -static const char *TimeOfDayValues[] = RM_VALS_TIME; -static const int NTimeOfDayValues = sizeof( TimeOfDayValues ) / sizeof( const char* ); - -static const char* CloudsValues[] = RM_VALS_CLOUDS; -static const int NCloudsValues = sizeof( CloudsValues ) / sizeof( const char* ); - -static const char *RainValues[] = RM_VALS_RAIN; -static const int NRainValues = sizeof( RainValues ) / sizeof( const char* ); +static const char *DispModeValues[GfRace::nDisplayModeNumber] = + { RM_VAL_VISIBLE, RM_VAL_INVISIBLE}; +static const char *TimeOfDayValues[GfRace::nTimeSpecNumber] = RM_VALS_TIME; +static const char* CloudsValues[GfRace::nCloudsSpecNumber] = RM_VALS_CLOUDS; +static const char *RainValues[GfRace::nRainSpecNumber] = RM_VALS_RAIN; // Global variables. -static void *scrHandle; -static tRmRaceParam *rp; +static void *ScrHandle; +static tRmRaceParam *MenuData; // Menu control ids static int rmrpDistEditId; @@ -71,10 +69,10 @@ static int rmrpRainEditId; static int rmrpDistance; static int rmrpLaps; static int rmrpSessionTime; -static int rmrpDispMode; -static int rmrpClouds; -static int rmrpTimeOfDay; -static int rmrpRain; +static GfRace::EDisplayMode rmrpDispMode; +static GfRace::ECloudsSpec rmrpClouds; +static GfRace::ETimeOfDaySpec rmrpTimeOfDay; +static GfRace::ERainSpec rmrpRain; static int rmrpFeatures; static bool rmrpIsSkyDomeEnabled; @@ -83,7 +81,7 @@ static bool rmrpIsSkyDomeEnabled; static void rmrpDeactivate(void *screen) { - GfuiScreenRelease(scrHandle); + GfuiScreenRelease(ScrHandle); if (screen) { GfuiScreenActivate(screen); @@ -96,16 +94,16 @@ rmrpUpdDist(void * /* dummy */) char buf[32]; char *val; - val = GfuiEditboxGetString(scrHandle, rmrpDistEditId); + val = GfuiEditboxGetString(ScrHandle, rmrpDistEditId); rmrpDistance = strtol(val, (char **)NULL, 0); if (rmrpDistance == 0) { strcpy(buf, "---"); } else { sprintf(buf, "%d", rmrpDistance); rmrpLaps = 0; - GfuiEditboxSetString(scrHandle, rmrpLapsEditId, "---"); + GfuiEditboxSetString(ScrHandle, rmrpLapsEditId, "---"); } - GfuiEditboxSetString(scrHandle, rmrpDistEditId, buf); + GfuiEditboxSetString(ScrHandle, rmrpDistEditId, buf); } static void @@ -114,16 +112,16 @@ rmrpUpdLaps(void * /* dummy */) char buf[32]; char *val; - val = GfuiEditboxGetString(scrHandle, rmrpLapsEditId); + val = GfuiEditboxGetString(ScrHandle, rmrpLapsEditId); rmrpLaps = strtol(val, (char **)NULL, 0); if (rmrpLaps == 0) { strcpy(buf, "---"); } else { sprintf(buf, "%d", rmrpLaps); rmrpDistance = 0; - GfuiEditboxSetString(scrHandle, rmrpDistEditId, "---"); + GfuiEditboxSetString(ScrHandle, rmrpDistEditId, "---"); } - GfuiEditboxSetString(scrHandle, rmrpLapsEditId, buf); + GfuiEditboxSetString(ScrHandle, rmrpLapsEditId, buf); } static void @@ -138,7 +136,7 @@ rmrpUpdSessionTime(void * /*dummy*/) if ((rmrpFeatures & RM_FEATURE_TIMEDSESSION) == 0) return; /* No timed session feature => nothing to do here */ - val = GfuiEditboxGetString(scrHandle, rmrpSessionTimeEditId); + val = GfuiEditboxGetString(ScrHandle, rmrpSessionTimeEditId); while( true ) { @@ -186,22 +184,27 @@ rmrpUpdSessionTime(void * /*dummy*/) strcpy( buf, "---"); else sprintf(buf, "%d:%02d:%02d", (int)floor( (float)rmrpSessionTime / 3600.0f ), (int)floor( (float)rmrpSessionTime / 60.0f ) % 60, (int)floor( (float)rmrpSessionTime ) % 60 ); - GfuiEditboxSetString(scrHandle, rmrpSessionTimeEditId, buf); + GfuiEditboxSetString(ScrHandle, rmrpSessionTimeEditId, buf); } static void -rmChangeDisplayMode(void * /* dummy */) +rmChangeDisplayMode(void *vp) { - rmrpDispMode = 1 - rmrpDispMode; - GfuiLabelSetText(scrHandle, rmrpDispModeEditId, DispModeValues[rmrpDispMode]); + const long delta = (int)(long)vp; + rmrpDispMode = + (GfRace::EDisplayMode) + ((rmrpDispMode + GfRace::nDisplayModeNumber + delta) % GfRace::nDisplayModeNumber); + GfuiLabelSetText(ScrHandle, rmrpDispModeEditId, DispModeValues[rmrpDispMode]); } static void rmChangeTimeOfDay(void *vp) { - const long delta = (long)vp; - rmrpTimeOfDay = (rmrpTimeOfDay + NTimeOfDayValues + delta) % NTimeOfDayValues; - GfuiLabelSetText(scrHandle, rmrpTimeOfDayEditId, TimeOfDayValues[rmrpTimeOfDay]); + const long delta = (int)(long)vp; + rmrpTimeOfDay = + (GfRace::ETimeOfDaySpec) + ((rmrpTimeOfDay + GfRace::nTimeSpecNumber + delta) % GfRace::nTimeSpecNumber); + GfuiLabelSetText(ScrHandle, rmrpTimeOfDayEditId, TimeOfDayValues[rmrpTimeOfDay]); } static void rmChangeRain(void *vp); @@ -209,17 +212,19 @@ static void rmChangeRain(void *vp); static void rmChangeClouds(void *vp) { - const long delta = (long)vp; - rmrpClouds = (rmrpClouds + NCloudsValues + delta) % NCloudsValues; - GfuiLabelSetText(scrHandle, rmrpCloudsEditId, CloudsValues[rmrpClouds]); + const long delta = (int)(long)vp; + rmrpClouds = + (GfRace::ECloudsSpec) + ((rmrpClouds + GfRace::nCloudsSpecNumber + delta) % GfRace::nCloudsSpecNumber); + GfuiLabelSetText(ScrHandle, rmrpCloudsEditId, CloudsValues[rmrpClouds]); - if ((rp->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) + if ((MenuData->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) { // Make rain level compatible if needed. - if (rmrpClouds < NCloudsValues - 1) // No heavy clouds => no rain + if (rmrpClouds != GfRace::eCloudsFull) // No heavy clouds => no rain { - rmrpRain = TR_RAIN_NONE; - GfuiLabelSetText(scrHandle, rmrpRainEditId, RainValues[rmrpRain]); + rmrpRain = GfRace::eRainNone; + GfuiLabelSetText(ScrHandle, rmrpRainEditId, RainValues[rmrpRain]); } } } @@ -227,32 +232,34 @@ rmChangeClouds(void *vp) static void rmChangeRain(void *vp) { - const long delta = (long)vp; - rmrpRain = (rmrpRain + NRainValues + delta) % NRainValues; - GfuiLabelSetText(scrHandle, rmrpRainEditId, RainValues[rmrpRain]); + const long delta = (int)(long)vp; + rmrpRain = + (GfRace::ERainSpec) + ((rmrpRain + GfRace::nRainSpecNumber + delta) % GfRace::nRainSpecNumber); + GfuiLabelSetText(ScrHandle, rmrpRainEditId, RainValues[rmrpRain]); - if ((rp->confMask & RM_CONF_CLOUD_COVER) && rmrpIsSkyDomeEnabled) + if ((MenuData->confMask & RM_CONF_CLOUD_COVER) && rmrpIsSkyDomeEnabled) { // Make clouds state compatible if needed. int cloudsComboVisibility; - if (rmrpRain == TR_RAIN_RANDOM) // Random rain => Random clouds. + if (rmrpRain == GfRace::eRainRandom) // Random rain => Random clouds. { cloudsComboVisibility = GFUI_INVISIBLE; - GfuiLabelSetText(scrHandle, rmrpCloudsEditId, "random"); + GfuiLabelSetText(ScrHandle, rmrpCloudsEditId, "random"); } else { cloudsComboVisibility = GFUI_VISIBLE; - if (rmrpRain == TR_RAIN_NONE) - rmrpClouds = 0; // No rain => no clouds by default. + if (rmrpRain == GfRace::eRainNone) + rmrpClouds = GfRace::eCloudsNone; // No rain => no clouds by default. else - rmrpClouds = NCloudsValues - 1; // Rain => Heavy clouds. - GfuiLabelSetText(scrHandle, rmrpCloudsEditId, CloudsValues[rmrpClouds]); + rmrpClouds = GfRace::eCloudsFull; // Rain => Heavy clouds. + GfuiLabelSetText(ScrHandle, rmrpCloudsEditId, CloudsValues[rmrpClouds]); } // Show / hide clouds combo arrow buttons (random rain => no sky choice). - GfuiVisibilitySet(scrHandle, rmrpCloudsLeftArrowId, cloudsComboVisibility); - GfuiVisibilitySet(scrHandle, rmrpCloudsRightArrowId, cloudsComboVisibility); + GfuiVisibilitySet(ScrHandle, rmrpCloudsLeftArrowId, cloudsComboVisibility); + GfuiVisibilitySet(ScrHandle, rmrpCloudsRightArrowId, cloudsComboVisibility); } } @@ -262,43 +269,45 @@ rmrpValidate(void * /* dummy */) // Force current edit to loose focus (if one has it) and update associated variable. GfuiUnSelectCurrent(); - if (rp->confMask & RM_CONF_RACE_LEN) + GfRace::Parameters* pRaceParams = MenuData->pRace->getParameters(); + + if (MenuData->confMask & RM_CONF_RACE_LEN) { - GfParmSetNum(rp->param, rp->title, RM_ATTR_DISTANCE, "km", rmrpDistance); - GfParmSetNum(rp->param, rp->title, RM_ATTR_LAPS, (char*)NULL, rmrpLaps); - GfParmSetNum(rp->param, rp->title, RM_ATTR_SESSIONTIME, "s", (tdble)rmrpSessionTime); + pRaceParams->nDistance = rmrpDistance; + pRaceParams->nLaps = rmrpLaps; + pRaceParams->nDuration = rmrpSessionTime; } - if (rp->confMask & RM_CONF_TIME_OF_DAY) + if (MenuData->confMask & RM_CONF_TIME_OF_DAY) { - GfParmSetStr(rp->param, rp->title, RM_ATTR_TIME_OF_DAY, TimeOfDayValues[rmrpTimeOfDay]); + pRaceParams->eTimeOfDaySpec = (GfRace::ETimeOfDaySpec)rmrpTimeOfDay; } - if (rp->confMask & RM_CONF_CLOUD_COVER) + if (MenuData->confMask & RM_CONF_CLOUD_COVER) { - GfParmSetStr(rp->param, rp->title, RM_ATTR_CLOUDS, CloudsValues[rmrpClouds]); + pRaceParams->eCloudsSpec = (GfRace::ECloudsSpec)rmrpClouds; } - if ((rp->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) + if ((MenuData->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) { - GfParmSetStr(rp->param, rp->title, RM_ATTR_RAIN, RainValues[rmrpRain]); + pRaceParams->eRainSpec = (GfRace::ERainSpec)rmrpRain; } - if (rp->confMask & RM_CONF_DISP_MODE) + if (MenuData->confMask & RM_CONF_DISP_MODE) { - GfParmSetStr(rp->param, rp->title, RM_ATTR_DISPMODE, DispModeValues[rmrpDispMode]); + pRaceParams->eDisplayMode = (GfRace::EDisplayMode)rmrpDispMode; } - rmrpDeactivate(rp->nextScreen); + rmrpDeactivate(MenuData->nextScreen); } static void rmrpAddKeys(void) { - GfuiAddKey(scrHandle, GFUIK_RETURN, "Accept", NULL, rmrpValidate, NULL); - GfuiAddKey(scrHandle, GFUIK_ESCAPE, "Cancel", rp->prevScreen, rmrpDeactivate, NULL); - GfuiAddKey(scrHandle, GFUIK_F1, "Help", scrHandle, GfuiHelpScreen, NULL); - GfuiAddKey(scrHandle, GFUIK_F12, "Screen-Shot", NULL, GfuiScreenShot, NULL); + GfuiAddKey(ScrHandle, GFUIK_RETURN, "Accept", NULL, rmrpValidate, NULL); + GfuiAddKey(ScrHandle, GFUIK_ESCAPE, "Cancel", MenuData->prevScreen, rmrpDeactivate, NULL); + GfuiAddKey(ScrHandle, GFUIK_F1, "Help", ScrHandle, GfuiHelpScreen, NULL); + GfuiAddKey(ScrHandle, GFUIK_F12, "Screen-Shot", NULL, GfuiScreenShot, NULL); } void @@ -308,10 +317,14 @@ RmRaceParamsMenu(void *vrp) GfLogTrace("Entering Race Params menu\n"); - rp = (tRmRaceParam*)vrp; + MenuData = (tRmRaceParam*)vrp; + GfRace::Parameters* pRaceParams = MenuData->pRace->getParameters(); + if (!pRaceParams) + return; + // Get race features. - rmrpFeatures = RmGetFeaturesList(rp->param); + rmrpFeatures = MenuData->pRace->getSupportedFeatures(); // Check if SkyDome is enabled snprintf(buf, sizeof(buf), "%s%s", GfLocalDir(), GR_PARAM_FILE); @@ -321,29 +334,29 @@ RmRaceParamsMenu(void *vrp) GfParmReleaseHandle(grHandle); // Create screen, load menu XML descriptor and create static controls. - scrHandle = GfuiScreenCreateEx((float*)NULL, NULL, NULL, NULL, (tfuiCallback)NULL, 1); + ScrHandle = GfuiScreenCreateEx((float*)NULL, NULL, NULL, NULL, (tfuiCallback)NULL, 1); void *menuXMLDescHdle = LoadMenuXML("raceparamsmenu.xml"); - CreateStaticControls(menuXMLDescHdle,scrHandle); + CreateStaticControls(menuXMLDescHdle,ScrHandle); // Create variable title label. - int titleId = CreateLabelControl(scrHandle,menuXMLDescHdle,"title"); - sprintf(buf, "%s Options", rp->title); - GfuiLabelSetText(scrHandle,titleId,buf); + int titleId = CreateLabelControl(ScrHandle,menuXMLDescHdle,"title"); + sprintf(buf, "%s Options", MenuData->pRace->getSessionName().c_str()); + GfuiLabelSetText(ScrHandle,titleId,buf); - if (rp->confMask & RM_CONF_RACE_LEN) + if (MenuData->confMask & RM_CONF_RACE_LEN) { // Create Race distance label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"racedistancelabel"); - rmrpDistance = (int)GfParmGetNum(rp->param, rp->title, RM_ATTR_DISTANCE, "km", 0); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"racedistancelabel"); + rmrpDistance = pRaceParams->nDistance; // Create and initialize Race distance edit. - rmrpSessionTime = (int)GfParmGetNum(rp->param, rp->title, RM_ATTR_SESSIONTIME, NULL, 0); + rmrpSessionTime = pRaceParams->nDuration; if (rmrpSessionTime > 0 && ( rmrpFeatures & RM_FEATURE_TIMEDSESSION ) == 0 ) rmrpDistance += rmrpSessionTime / 30; if (rmrpDistance == 0) { strcpy(buf, "---"); - rmrpLaps = (int)GfParmGetNum(rp->param, rp->title, RM_ATTR_LAPS, NULL, 25); + rmrpLaps = pRaceParams->nLaps; if (rmrpSessionTime > 0 && ( rmrpFeatures & RM_FEATURE_TIMEDSESSION ) == 0 ) rmrpLaps += (int)floor( (tdble)rmrpSessionTime / 1.5f + 0.5f ); } @@ -353,11 +366,12 @@ RmRaceParamsMenu(void *vrp) rmrpLaps = 0; } - rmrpDistEditId = CreateEditControl(scrHandle,menuXMLDescHdle,"racedistanceedit",NULL,NULL,rmrpUpdDist); - GfuiEditboxSetString(scrHandle,rmrpDistEditId,buf); + rmrpDistEditId = CreateEditControl(ScrHandle, menuXMLDescHdle, "racedistanceedit", + NULL, NULL, rmrpUpdDist); + GfuiEditboxSetString(ScrHandle,rmrpDistEditId,buf); // Create Laps label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"lapslabel"); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"lapslabel"); // Create and initialize Laps edit. if (rmrpLaps == 0) @@ -369,13 +383,14 @@ RmRaceParamsMenu(void *vrp) sprintf(buf, "%d", rmrpLaps); } - rmrpLapsEditId = CreateEditControl(scrHandle,menuXMLDescHdle,"lapsedit",NULL,NULL,rmrpUpdLaps); - GfuiEditboxSetString(scrHandle,rmrpLapsEditId,buf); + rmrpLapsEditId = CreateEditControl(ScrHandle, menuXMLDescHdle, "lapsedit", + NULL, NULL, rmrpUpdLaps); + GfuiEditboxSetString(ScrHandle,rmrpLapsEditId,buf); if (rmrpFeatures & RM_FEATURE_TIMEDSESSION) { // Create Session time label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"sessiontimelabel"); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"sessiontimelabel"); // Create and initialize Session time edit. if (rmrpSessionTime <= 0) @@ -390,8 +405,9 @@ RmRaceParamsMenu(void *vrp) } rmrpSessionTimeEditId = - CreateEditControl(scrHandle,menuXMLDescHdle,"sessiontimeedit",NULL,NULL,rmrpUpdSessionTime); - GfuiEditboxSetString(scrHandle,rmrpSessionTimeEditId,buf); + CreateEditControl(ScrHandle, menuXMLDescHdle, "sessiontimeedit", + NULL, NULL, rmrpUpdSessionTime); + GfuiEditboxSetString(ScrHandle,rmrpSessionTimeEditId,buf); } else { @@ -400,115 +416,97 @@ RmRaceParamsMenu(void *vrp) } // Create and initialize Time of day combo box (2 arrow buttons and a variable label). - if (rp->confMask & RM_CONF_TIME_OF_DAY) + if (MenuData->confMask & RM_CONF_TIME_OF_DAY) { if (rmrpIsSkyDomeEnabled) { - rmrpTimeOfDay = 0; - const char* pszTimeOfDay = - GfParmGetStr(rp->param, rp->title, RM_ATTR_TIME_OF_DAY, RM_VAL_TIME_AFTERNOON); - for (int i = 0; i < NTimeOfDayValues; i++) - if (!strcmp(pszTimeOfDay, TimeOfDayValues[i])) - { - rmrpTimeOfDay = i; - break; - } + rmrpTimeOfDay = pRaceParams->eTimeOfDaySpec; // Create Time of day label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"timeofdaylabel"); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"timeofdaylabel"); // Create and initialize Time of day combo-box-like control. - CreateButtonControl(scrHandle,menuXMLDescHdle,"timeofdayleftarrow",(void*)-1, rmChangeTimeOfDay); - CreateButtonControl(scrHandle,menuXMLDescHdle,"timeofdayrightarrow",(void*)1, rmChangeTimeOfDay); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "timeofdayleftarrow", + (void*)-1, rmChangeTimeOfDay); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "timeofdayrightarrow", + (void*)1, rmChangeTimeOfDay); - rmrpTimeOfDayEditId = CreateLabelControl(scrHandle,menuXMLDescHdle,"timeofdayedit"); - GfuiLabelSetText(scrHandle,rmrpTimeOfDayEditId,TimeOfDayValues[rmrpTimeOfDay]); + rmrpTimeOfDayEditId = CreateLabelControl(ScrHandle,menuXMLDescHdle,"timeofdayedit"); + GfuiLabelSetText(ScrHandle, rmrpTimeOfDayEditId, TimeOfDayValues[rmrpTimeOfDay]); } else { - rmrpTimeOfDay = 3; // Afternoon (but normally not taken into account). + rmrpTimeOfDay = GfRace::eTimeAfternoon; // Normally not taken into account. } } - if (rp->confMask & RM_CONF_CLOUD_COVER) + if (MenuData->confMask & RM_CONF_CLOUD_COVER) { if (rmrpIsSkyDomeEnabled) { // Create and initialize Clouds combo box (2 arrow buttons and a variable label). - rmrpClouds = 0; - const char* pszClouds = - GfParmGetStr(rp->param, rp->title, RM_ATTR_CLOUDS, RM_VAL_CLOUDS_NONE); - for (int i = 0; i < NCloudsValues; i++) - if (!strcmp(pszClouds, CloudsValues[i])) - { - rmrpClouds = i; - break; - } + rmrpClouds = pRaceParams->eCloudsSpec; // Create Cloud cover label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"cloudslabel"); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"cloudslabel"); // Create and initialize Cloud cover combo-box-like control. rmrpCloudsLeftArrowId = - CreateButtonControl(scrHandle,menuXMLDescHdle,"cloudsleftarrow",(void*)-1, rmChangeClouds); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "cloudsleftarrow", + (void*)-1, rmChangeClouds); rmrpCloudsRightArrowId = - CreateButtonControl(scrHandle,menuXMLDescHdle,"cloudsrightarrow",(void*)1, rmChangeClouds); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "cloudsrightarrow", + (void*)+1, rmChangeClouds); - rmrpCloudsEditId = CreateLabelControl(scrHandle,menuXMLDescHdle,"cloudsedit"); - GfuiLabelSetText(scrHandle,rmrpCloudsEditId,CloudsValues[rmrpClouds]); + rmrpCloudsEditId = CreateLabelControl(ScrHandle,menuXMLDescHdle,"cloudsedit"); + GfuiLabelSetText(ScrHandle,rmrpCloudsEditId,CloudsValues[rmrpClouds]); } else { - rmrpClouds = 0; + rmrpClouds = GfRace::eCloudsNone; } } - if ((rp->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) + if ((MenuData->confMask & RM_CONF_RAIN_FALL) && (rmrpFeatures & RM_FEATURE_WETTRACK)) { // Create and initialize Rain combo box (2 arrow buttons and a variable label). - rmrpRain = 0; - const char* pszRain = - GfParmGetStr(rp->param, rp->title, RM_ATTR_RAIN, RM_VAL_RAIN_NONE); - for (int i = 0; i < NRainValues; i++) - if (!strcmp(pszRain, RainValues[i])) - { - rmrpRain = i; - break; - } + rmrpRain = pRaceParams->eRainSpec; // Create Rain label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"rainlabel"); + CreateLabelControl(ScrHandle,menuXMLDescHdle,"rainlabel"); // Create and initialize Rain combo-box-like control. - CreateButtonControl(scrHandle,menuXMLDescHdle,"rainleftarrow",(void*)-1, rmChangeRain); - CreateButtonControl(scrHandle,menuXMLDescHdle,"rainrightarrow",(void*)1, rmChangeRain); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "rainleftarrow", + (void*)-1, rmChangeRain); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "rainrightarrow", + (void*)1, rmChangeRain); - rmrpRainEditId = CreateLabelControl(scrHandle,menuXMLDescHdle,"rainedit"); - GfuiLabelSetText(scrHandle,rmrpRainEditId,RainValues[rmrpRain]); + rmrpRainEditId = CreateLabelControl(ScrHandle,menuXMLDescHdle,"rainedit"); + GfuiLabelSetText(ScrHandle,rmrpRainEditId,RainValues[rmrpRain]); rmChangeRain(0); // Make cloud cover settings compatible if needed. } - if (rp->confMask & RM_CONF_DISP_MODE) + if (MenuData->confMask & RM_CONF_DISP_MODE) { - if (!strcmp(GfParmGetStr(rp->param, rp->title, RM_ATTR_DISPMODE, RM_VAL_VISIBLE), RM_VAL_INVISIBLE)) - rmrpDispMode = 1; - else - rmrpDispMode = 0; + rmrpDispMode = pRaceParams->eDisplayMode; // Create Display mode label. - CreateLabelControl(scrHandle,menuXMLDescHdle,"displaylabel"); + CreateLabelControl(ScrHandle, menuXMLDescHdle, "displaylabel"); // Create and initialize Display mode combo-box-like control. - CreateButtonControl(scrHandle,menuXMLDescHdle,"displayleftarrow",(void*)0, rmChangeDisplayMode); - CreateButtonControl(scrHandle,menuXMLDescHdle,"displayrightarrow",(void*)1, rmChangeDisplayMode); - rmrpDispModeEditId = CreateLabelControl(scrHandle,menuXMLDescHdle,"displayedit"); - GfuiLabelSetText(scrHandle,rmrpDispModeEditId,DispModeValues[rmrpDispMode]); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "displayleftarrow", + (void*)-1, rmChangeDisplayMode); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "displayrightarrow", + (void*)+1, rmChangeDisplayMode); + rmrpDispModeEditId = CreateLabelControl(ScrHandle, menuXMLDescHdle, "displayedit"); + GfuiLabelSetText(ScrHandle, rmrpDispModeEditId, DispModeValues[rmrpDispMode]); } // Create Accept and Cancel buttons - CreateButtonControl(scrHandle,menuXMLDescHdle,"nextbutton",NULL,rmrpValidate); - CreateButtonControl(scrHandle,menuXMLDescHdle,"previousbutton",rp->prevScreen,rmrpDeactivate); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "nextbutton", NULL, rmrpValidate); + CreateButtonControl(ScrHandle, menuXMLDescHdle, "previousbutton", + MenuData->prevScreen, rmrpDeactivate); // Close menu XML descriptor. GfParmReleaseHandle(menuXMLDescHdle); @@ -516,5 +514,5 @@ RmRaceParamsMenu(void *vrp) // Register keyboard shortcuts. rmrpAddKeys(); - GfuiScreenActivate(scrHandle); + GfuiScreenActivate(ScrHandle); } diff --git a/src/libs/racescreens/racescreens.h b/src/libs/racescreens/racescreens.h index c363cb5ec..94d93a4d7 100644 --- a/src/libs/racescreens/racescreens.h +++ b/src/libs/racescreens/racescreens.h @@ -29,6 +29,8 @@ #include // tfuiCalback +class GfRace; + // DLL exported symbols declarator for Windows. #ifdef WIN32 @@ -44,7 +46,7 @@ typedef struct RmTrackSelect { - void *param; /* Race manager parameters where to set the selected track */ + GfRace *pRace; /* The race to update */ void *prevScreen; /* Race manager screen to go back */ void *nextScreen; /* Race manager screen to go after select */ tTrackItf trackItf; /* Track module interface */ @@ -52,17 +54,16 @@ typedef struct RmTrackSelect typedef struct RmDriverSelect { - void *param; + GfRace *pRace; /* The race to update */ void *prevScreen; /* Race manager screen to go back */ void *nextScreen; /* Race manager screen to go after select */ } tRmDriverSelect; typedef struct RmRaceParam { - void *param; + GfRace *pRace; /* The race to update */ void *prevScreen; void *nextScreen; /* Race manager screen to go after select */ - const char *title; unsigned int confMask; /* Tell what to configure */ #define RM_CONF_RACE_LEN 0x00000001 #define RM_CONF_DISP_MODE 0x00000002 @@ -77,8 +78,8 @@ enum RmFileSelectMode { RmFSModeLoad, RmFSModeSave }; typedef struct RmFileSelect { - const char *title; - const char *path; + std::string title; + std::string path; void *prevScreen; tfSelectFile select; RmFileSelectMode mode; @@ -128,7 +129,5 @@ RACESCREENS_API void RmShowStandings(void *prevHdle, tRmInfo *info); RACESCREENS_API void* RmFileSelect(void *vs); -RACESCREENS_API int RmGetFeaturesList( void* param ); - #endif /* __RACESCREENS_H__ */ diff --git a/src/libs/racescreens/trackselect.cpp b/src/libs/racescreens/trackselect.cpp index ef1b2283d..08444f7f3 100644 --- a/src/libs/racescreens/trackselect.cpp +++ b/src/libs/racescreens/trackselect.cpp @@ -22,16 +22,16 @@ @version $Id$ */ - #include #include -#include #include #include #include #include + +#include #include #include "racescreens.h" @@ -40,8 +40,8 @@ // Screen handle. static void *ScrHandle; -// -static tRmTrackSelect *TrackSelect; +// Track select menu data. +static tRmTrackSelect *MenuData; // The currently selected track. GfTrack* PCurTrack; @@ -84,130 +84,18 @@ rmtsWordWrap(const std::string str, std::string &str1, std::string &str2, unsign it++; }//while - if(str.size() >= length) //If input string was longer than required, + if (str.size() >= length) //If input string was longer than required, str2 = str.substr(str1.size()); //put the rest in str2. }//rmtsWordWrap -/** - * rmtsGetFirstUsableTrack - * - * Retrieve the first usable track in the given category, searching in the given direction - * and skipping the first found if specified - * - * @param strCatId Id of the category to search inside of. - * @param strFromTrackId Id of the track from which to start the search. - * @param nSearchDir <0 = previous, >0 = next. - * @param bSkipFrom If true, skip the first found track. - */ -static GfTrack* -rmtsGetFirstUsableTrack(const std::string& strCatId, const std::string& strFromTrackId = "", - int nSearchDir = +1, bool bSkipFrom = false) -{ - //GfLogDebug("rmtsGetFirstUsableTrack(c=%s, ft=%s, %d)\n", - // strCatId.c_str(), strFromTrackId.c_str(), nSearchDir); - - GfTrack* pTrack = 0; - - if (nSearchDir == 0) - nSearchDir = +1; - - // Check category. - const std::vector& vecCatIds = GfTracks::self()->getCategoryIds(); - if (std::find(vecCatIds.begin(), vecCatIds.end(), strCatId) == vecCatIds.end()) - return 0; - - // Retrieve tracks in this category. - const std::vector vecTracksInCat = - GfTracks::self()->getTracksInCategory(strCatId); - if (vecTracksInCat.size() == 0) - return 0; - - // Retrieve the index of the specified track to start from, if any. - int nCurTrackInd = 0; - if (!strFromTrackId.empty()) - { - std::vector::const_iterator itTrack = vecTracksInCat.begin(); - while (itTrack != vecTracksInCat.end()) - { - if ((*itTrack)->getId() == strFromTrackId) - { - nCurTrackInd = itTrack - vecTracksInCat.begin(); - break; - } - itTrack++; - } - } - - int nTrackInd = nCurTrackInd; - if (bSkipFrom || !vecTracksInCat[nTrackInd]->isUsable()) - { - const int nPrevTrackInd = nCurTrackInd; - do - { - nTrackInd = - (nTrackInd + nSearchDir + vecTracksInCat.size()) % vecTracksInCat.size(); - //GfLogDebug("xxx nTrackInd=%d\n", nTrackInd); - } - while (nTrackInd != nPrevTrackInd && !vecTracksInCat[nTrackInd]->isUsable()); - } - - if (vecTracksInCat[nTrackInd]->isUsable()) - pTrack = vecTracksInCat[nTrackInd]; - - return pTrack; -} - -/** - * rmtsGetFirstUsableTrack - * - * Retrieve the first usable track among all categories, searching in the given direction - * from the given category, but skipping it if specified - * - * @param strFromCatId Id of the category to search inside of. - * @param nSearchDir <0 = previous, >0 = next. - * @param bSkipFrom If true, skip the first found track. - */ -static GfTrack* -rmtsGetFirstUsableTrack(const std::string& strFromCatId, int nSearchDir, bool bSkipFrom = false) -{ - //GfLogDebug("rmtsGetFirstUsableTrack(fc=%s, %d)\n", strFromCatId.c_str(), nSearchDir); - - GfTrack* pTrack = 0; - - if (nSearchDir == 0) - nSearchDir = +1; - - // Retrieve and check category. - const std::vector& vecCatIds = GfTracks::self()->getCategoryIds(); - std::vector::const_iterator itFromCat = - std::find(vecCatIds.begin(), vecCatIds.end(), strFromCatId); - if (itFromCat == vecCatIds.end()) - return 0; - - int nCatInd = itFromCat - vecCatIds.begin(); - - if (bSkipFrom || !(pTrack = rmtsGetFirstUsableTrack(vecCatIds[nCatInd]))) - { - const int nPrevCatInd = nCatInd; - //GfLogDebug("xxx nPrevCatInd=%d\n", nPrevCatInd); - do - { - nCatInd = - (nCatInd + nSearchDir + vecCatIds.size()) % vecCatIds.size(); - pTrack = rmtsGetFirstUsableTrack(vecCatIds[nCatInd]); - //GfLogDebug("xxx cat[%d]=%s, p=%p\n", nCatInd, vecCatIds[nCatInd].c_str(), pTrack); - } - while (nCatInd != nPrevCatInd && !pTrack); - } - - return pTrack; -} - static void rmtsUpdateTrackInfo(void) { static const int nMaxLinesLength = 30; //Line length for track description (chars) + if (!PCurTrack) + return; + // Update GUI with track info. // 0) Track category and name. GfuiLabelSetText(ScrHandle, CategoryEditId, PCurTrack->getCategoryName().c_str()); @@ -270,17 +158,14 @@ rmtsActivate(void * /* dummy */) static void rmtsTrackPrevNext(void *vsel) { - const int nSearchDir = vsel ? (int)(long)vsel : +1; + const int nSearchDir = (long)vsel > 0 ? +1 : -1; - PCurTrack = - rmtsGetFirstUsableTrack(PCurTrack->getCategoryId(), PCurTrack->getId(), nSearchDir, true); + // Select next usable track in the current catergory in the requested direction. + PCurTrack = GfTracks::self()->getFirstUsableTrack(PCurTrack->getCategoryId(), + PCurTrack->getId(), nSearchDir, true); - // If any next/previous usable track in the current category, select it. - if (PCurTrack) - { - // Update GUI - rmtsUpdateTrackInfo(); - } + // Update GUI + rmtsUpdateTrackInfo(); } @@ -288,106 +173,25 @@ rmtsTrackPrevNext(void *vsel) static void rmtsTrackCatPrevNext(void *vsel) { - const int nSearchDir = vsel ? (int)(long)vsel : +1; + const int nSearchDir = (long)vsel > 0 ? +1 : -1; - // - PCurTrack = rmtsGetFirstUsableTrack(PCurTrack->getCategoryId(), nSearchDir, true); + // Select first usable track in the next catergory in the requested direction. + PCurTrack = GfTracks::self()->getFirstUsableTrack(PCurTrack->getCategoryId(), + nSearchDir, true); - // If any next/previous usable category, select it. - if (PCurTrack) - { - // Update GUI - rmtsUpdateTrackInfo(); - } - -// /* Get next/previous usable track category -// Note: Here, we assume there's at least one, -// which is guaranteed by CategoryList initialization in RmTrackSelect */ -// const int nDeltaInd = (int)(long)(vsel ? vsel : 1); -// const std::string& strCurCat = GfTracks::self()->getCategoryIds()[NCurCatIndex]; -// const std::vector vecTracksInCat = -// GfTracks::self()->getTracksInCategory(strCurCat); -// const int nPrevTrackIndex = NCurTrackCatIndex; -// do -// { -// NCurTrackInCatIndex = -// (NCurTrackInCatIndex + nDeltaInd + GfTracks::self()->getCategoryIds()) -// % GfTracks::self()->getCategoryIds(); -// } -// while (nPrevTrackIndex != NCurTrackInCatIndex -// && vecTracksInCat[NCurTrackCatIndex]->isUsable()); - - -// tFList *curCat = CategoryList; -// do { - -// /* Next/previous category */ -// curCat = vsel ? curCat->next : curCat->prev; - -// /* Try and get the category display name if not already done */ -// if (curCat->userData && !curCat->dispName) { -// curCat->dispName = rmtsGetCategoryName(curCat->name); -// if (!curCat->dispName || strlen(curCat->dispName) == 0) { -// GfError("rmtsTrackCatPrevNext: No definition for track category %s\n", curCat->name); -// } -// } - -// /* If the category is loadable and not empty : */ -// if (curCat->dispName && curCat->userData) { - -// /* Select the first usable track in the category */ -// tFList *curTr = (tFList*)(curCat->userData); -// do { - -// /* Try and get the track display name if not already done */ -// if (!curTr->dispName) { -// curTr->dispName = rmtsGetTrackName(curCat->name, curTr->name); -// if (!curTr->dispName || strlen(curTr->dispName) == 0) { -// GfError("rmtsTrackCatPrevNext: No definition for track %s\n", curTr->name); -// } -// } - -// /* That's all if the track is usable*/ -// if (curTr->dispName) -// break; - -// /* Next track */ -// curTr = curTr->next; - -// } while (curTr != (tFList*)(curCat->userData)); -// curCat->userData = (void*)curTr; -// } - -// } while ((!curCat->dispName || !curCat->userData || !((tFList*)(curCat->userData))->dispName) -// && curCat != CategoryList); -// CategoryList = curCat; - -// /* Update GUI */ -// GfuiLabelSetText(ScrHandle, CategoryEditId, CategoryList->dispName); -// GfuiLabelSetText(ScrHandle, NameEditId, ((tFList*)curCat->userData)->dispName); -// GfuiStaticImageSet(ScrHandle, OutlineImageLabelId, rmtsGetOutlineFileName(PathBuf, MaxPathSize)); -// GfuiScreenAddBgImg(ScrHandle, rmtsGetPreviewFileName(PathBuf, MaxPathSize)); -// rmtsUpdateTrackInfo(); + // Update GUI + rmtsUpdateTrackInfo(); } static void rmtsSelect(void * /* dummy */) { - // Save currently slected track category and LabelId to the race params file. - const int nCurTrackInd = - (int)GfParmGetNum(TrackSelect->param, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, 1); - std::ostringstream ossParamPath; - ossParamPath << RM_SECT_TRACKS << '/' << nCurTrackInd; - - GfParmSetStr(TrackSelect->param, ossParamPath.str().c_str(), RM_ATTR_CATEGORY, - PCurTrack->getCategoryId().c_str()); - GfParmSetStr(TrackSelect->param, ossParamPath.str().c_str(), RM_ATTR_NAME, - PCurTrack->getId().c_str()); - GfParmSetStr(TrackSelect->param, ossParamPath.str().c_str(), RM_ATTR_FULLNAME, - PCurTrack->getId().c_str()); + // Save currently selected track into the race. + MenuData->pRace->setTrack(PCurTrack); - rmtsDeactivate(TrackSelect->nextScreen); + // Next screen. + rmtsDeactivate(MenuData->nextScreen); } @@ -395,7 +199,7 @@ static void rmtsAddKeys(void) { GfuiAddKey(ScrHandle, GFUIK_RETURN, "Select Track", NULL, rmtsSelect, NULL); - GfuiAddKey(ScrHandle, GFUIK_ESCAPE, "Cancel Selection", TrackSelect->prevScreen, rmtsDeactivate, NULL); + GfuiAddKey(ScrHandle, GFUIK_ESCAPE, "Cancel Selection", MenuData->prevScreen, rmtsDeactivate, NULL); GfuiAddKey(ScrHandle, GFUIK_LEFT, "Previous Track", (void*)-1, rmtsTrackPrevNext, NULL); GfuiAddKey(ScrHandle, GFUIK_RIGHT, "Next Track", (void*)+1, rmtsTrackPrevNext, NULL); GfuiAddKey(ScrHandle, GFUIK_F1, "Help", ScrHandle, GfuiHelpScreen, NULL); @@ -413,33 +217,28 @@ rmtsAddKeys(void) void RmTrackSelect(void *vs) { - TrackSelect = (tRmTrackSelect*)vs; + MenuData = (tRmTrackSelect*)vs; // Get currently selected track for the current race type // (or the first usable one in the selected category). - const int nCurTrackInd = - (int)GfParmGetNum(TrackSelect->param, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, 1); - std::ostringstream ossSectionPath; - ossSectionPath << RM_SECT_TRACKS << '/' << nCurTrackInd; - const char* pszCurTrackId = - GfParmGetStr(TrackSelect->param, ossSectionPath.str().c_str(), RM_ATTR_NAME, 0); - const char* pszCurTrackCatId = - GfParmGetStr(TrackSelect->param, ossSectionPath.str().c_str(), RM_ATTR_CATEGORY, 0); - - PCurTrack = rmtsGetFirstUsableTrack(pszCurTrackCatId, pszCurTrackId); - if (PCurTrack && PCurTrack->getId() != pszCurTrackId) - GfLogWarning("Could not find selected track %s (%s) ; using %s (%s)\n", - pszCurTrackId, pszCurTrackCatId, + PCurTrack = MenuData->pRace->getTrack(); + const std::string strReqTrackId = PCurTrack->getId(); + const std::string strReqTrackCatId = PCurTrack->getCategoryId(); + PCurTrack = + GfTracks::self()->getFirstUsableTrack(PCurTrack->getCategoryId(), PCurTrack->getId()); + if (PCurTrack && PCurTrack->getId() != strReqTrackId) + GfLogWarning("Could not find / use selected track %s (%s) ; using %s (%s)\n", + strReqTrackId.c_str(), strReqTrackCatId.c_str(), PCurTrack->getId().c_str(), PCurTrack->getCategoryId().c_str()); // If not usable, try and get the first usable track going ahead in categories if (!PCurTrack) { - PCurTrack = rmtsGetFirstUsableTrack(pszCurTrackCatId, +1, true); + PCurTrack = GfTracks::self()->getFirstUsableTrack(strReqTrackCatId, +1, true); if (PCurTrack) - GfLogWarning("Could not find selected track %s and category %s unusable" + GfLogWarning("Could not find / use selected track %s and category %s unusable" " ; using %s (%s)\n", - pszCurTrackId, pszCurTrackCatId, + strReqTrackId.c_str(), strReqTrackCatId.c_str(), PCurTrack->getId().c_str(), PCurTrack->getCategoryId().c_str()); } @@ -468,7 +267,7 @@ RmTrackSelect(void *vs) OutlineImageId = CreateStaticImageControl(ScrHandle, hparmMenu, "outlineimage"); CreateButtonControl(ScrHandle, hparmMenu, "nextbutton", NULL, rmtsSelect); - CreateButtonControl(ScrHandle, hparmMenu, "previousbutton", TrackSelect->prevScreen, rmtsDeactivate); + CreateButtonControl(ScrHandle, hparmMenu, "previousbutton", MenuData->prevScreen, rmtsDeactivate); DescLine1LabelId = CreateLabelControl(ScrHandle, hparmMenu, "descriptionlabel"); DescLine2LabelId = CreateLabelControl(ScrHandle, hparmMenu, "descriptionlabel2"); diff --git a/src/libs/tgfdata/drivers.cpp b/src/libs/tgfdata/drivers.cpp index a8602a388..647508728 100644 --- a/src/libs/tgfdata/drivers.cpp +++ b/src/libs/tgfdata/drivers.cpp @@ -124,26 +124,14 @@ GfDrivers::GfDrivers() continue; } - // Read driver info from the XML file. - std::ostringstream ossDriverListPath; - ossDriverListPath << ROB_SECT_ROBOTS << '/' << ROB_LIST_INDEX - << '/' << pCurModule->modInfo[nItfInd].index; - const char* pszCarId = GfParmGetStr(hparmRobot, ossDriverListPath.str().c_str(), ROB_ATTR_CAR, ""); - const bool bIsHuman = strcmp(GfParmGetStr(hparmRobot, ossDriverListPath.str().c_str(), ROB_ATTR_TYPE, ROB_VAL_ROBOT), ROB_VAL_ROBOT) != 0; + // Create the driver and load info from the XML file. + GfDriver* pDriver = new GfDriver(strModName, pCurModule->modInfo[nItfInd].index, + pCurModule->modInfo[nItfInd].name, hparmRobot); - // Compute/retrieve other information. - const GfCar* pCar = GfCars::self()->getCar(pszCarId); - if (pCar) + // Keep the driver only if its car exists and is usable. + if (pDriver->getCar()) { - // Store it in the GfDriver structure. - GfDriver* pDriver = new GfDriver; - pDriver->setName(pCurModule->modInfo[nItfInd].name); - pDriver->setModuleName(strModName); - pDriver->setInterfaceIndex(pCurModule->modInfo[nItfInd].index); - pDriver->setIsHuman(bIsHuman); - pDriver->setCar(pCar); - - // Update the GfCars singleton. + // Update the GfDrivers singleton. _pPrivate->vecDrivers.push_back(pDriver); const std::pair driverKey(pDriver->getModuleName(), pDriver->getInterfaceIndex()); @@ -152,13 +140,21 @@ GfDrivers::GfDrivers() pDriver->getType()) == _pPrivate->vecTypes.end()) _pPrivate->vecTypes.push_back(pDriver->getType()); if (std::find(_pPrivate->vecCarCategoryIds.begin(), _pPrivate->vecCarCategoryIds.end(), - pCar->getCategoryId()) == _pPrivate->vecCarCategoryIds.end()) - _pPrivate->vecCarCategoryIds.push_back(pCar->getCategoryId()); + pDriver->getCar()->getCategoryId()) == _pPrivate->vecCarCategoryIds.end()) + _pPrivate->vecCarCategoryIds.push_back(pDriver->getCar()->getCategoryId()); } else { + delete pDriver; + + std::ostringstream ossDrvSecPath; + ossDrvSecPath << ROB_SECT_ROBOTS << '/' << ROB_LIST_INDEX << '/' + << pCurModule->modInfo[nItfInd].index; + const char* pszCarId = + GfParmGetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_CAR, ""); GfLogWarning("Ignoring '%s' driver '%s' (#%d) (default car %s not available)\n", - strModName.c_str(), pCurModule->modInfo[nItfInd].name, nItfInd, pszCarId); + strModName.c_str(), pCurModule->modInfo[nItfInd].name, + pCurModule->modInfo[nItfInd].index, pszCarId); } } @@ -233,8 +229,10 @@ void GfDrivers::print() const GfLogTrace(" '%s' car category :\n", itCarCatId->c_str()); std::vector::const_iterator itDriver; for (itDriver = vecDrivers.begin(); itDriver != vecDrivers.end(); itDriver++) - GfLogTrace(" %-24s : %s\n", (*itDriver)->getName().c_str(), - (*itDriver)->getCar()->getName().c_str()); + GfLogTrace(" %-24s : %s, %02X-featured\n", + (*itDriver)->getName().c_str(), + (*itDriver)->getCar()->getName().c_str(), + (*itDriver)->getSupportedFeatures()); } } } @@ -282,8 +280,95 @@ void GfDriverSkin::setCarPreviewFileName(const std::string& strFileName) // GfDriver class ------------------------------------------------------------------- -GfDriver::GfDriver() : _nItfIndex(-1), _bIsHuman(false), _pCar(0) +// Skill level related constants. +static const char *ASkillLevelStrings[] = + { ROB_VAL_ROOKIE, ROB_VAL_AMATEUR, ROB_VAL_SEMI_PRO, ROB_VAL_PRO }; +static const int NbSkillLevels = sizeof(ASkillLevelStrings) / sizeof(ASkillLevelStrings[0]); +static const double ASkillLevelValues[NbSkillLevels] = { 10.0, 7.0, 3.0, 0.0 }; + +// Robot drivers features related constants. +struct RobotFeature { + const char *pszName; + int nValue; +}; + +static RobotFeature RobotFeatures[] = +{ + { ROB_VAL_FEATURE_PENALTIES, RM_FEATURE_PENALTIES }, + { ROB_VAL_FEATURE_TIMEDSESSION, RM_FEATURE_TIMEDSESSION }, + { ROB_VAL_FEATURE_WETTRACK, RM_FEATURE_WETTRACK }, + + /* Career mode features not yet resurrected (robots need work to support them). + { ROB_VAL_FEATURE_SC, RM_FEATURE_SC | RM_FEATURE_YELLOW | RM_FEATURE_PENALTIES }, + { ROB_VAL_FEATURE_YELLOW, RM_FEATURE_YELLOW | RM_FEATURE_PENALTIES }, + { ROB_VAL_FEATURE_RED, RM_FEATURE_RED }, + { ROB_VAL_FEATURE_BLUE, RM_FEATURE_BLUE }, + { ROB_VAL_FEATURE_PITEXIT, RM_FEATURE_PITEXIT | RM_FEATURE_PENALTIES }, + { ROB_VAL_FEATURE_TIMEDSESSION, RM_FEATURE_TIMEDSESSION }, + { ROB_VAL_FEATURE_PENALTIES, RM_FEATURE_PENALTIES } + */ +}; +static const int NRobotFeatures = sizeof(RobotFeatures) / sizeof(RobotFeatures[0]); + + +GfDriver::GfDriver(const std::string& strModName, int nItfIndex, + const std::string& strName, void* hparmRobot) +: _strModName(strModName), _strName(strName), _nItfIndex(nItfIndex), _bIsHuman(false), _pCar(0) +{ + load(hparmRobot); +} + +void GfDriver::load(void* hparmRobot) +{ + std::ostringstream ossDrvSecPath; + ossDrvSecPath << ROB_SECT_ROBOTS << '/' << ROB_LIST_INDEX << '/' << _nItfIndex; + + // Humanity. + _bIsHuman = + strcmp(GfParmGetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_TYPE, ROB_VAL_ROBOT), + ROB_VAL_ROBOT) != 0; + + // Skill level. + const char* pszKillLevel = + GfParmGetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_LEVEL, ROB_VAL_SEMI_PRO); + for(int nLevelInd = 0; nLevelInd < NbSkillLevels; nLevelInd++) + { + if (!strcmp(ASkillLevelStrings[nLevelInd], pszKillLevel)) + { + _fSkillLevel = ASkillLevelValues[nLevelInd]; + break; + } + } + + // Supported features. + if (_bIsHuman) + { + _nFeatures = RM_FEATURE_TIMEDSESSION | RM_FEATURE_WETTRACK; + if (_fSkillLevel <= ASkillLevelValues[3]) // Pro (TODO: Create enum fro that !) + _nFeatures |= RM_FEATURE_PENALTIES; + } + else + { + _nFeatures = 0; + char* pszDrvFeatures = + strdup(GfParmGetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_FEATURES, "")); + for (char* pszFeature = strtok(pszDrvFeatures, ";"); + pszFeature != 0; pszFeature = strtok(NULL, ";")) + { + for (int nFeatInd = 0; nFeatInd < NRobotFeatures; nFeatInd++) + if (!strcmp(pszFeature, RobotFeatures[nFeatInd].pszName)) + { + _nFeatures |= RobotFeatures[nFeatInd].nValue; + break; + } + } + free(pszDrvFeatures); + } + + // Driven car. + const char* pszCarId = GfParmGetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_CAR, ""); + _pCar = GfCars::self()->getCar(pszCarId); } const std::string& GfDriver::getName() const @@ -345,25 +430,35 @@ bool GfDriver::matchesTypeAndCategory(const std::string& strType, && (strCarCatId.empty() || getCar()->getCategoryId() == strCarCatId); } -void GfDriver::setName(const std::string& strName) +double GfDriver::getSkillLevel() const { - _strName = strName; + return _fSkillLevel; } -void GfDriver::setModuleName(const std::string& strModName) +int GfDriver::getSupportedFeatures() const { - _strModName = strModName; + return _nFeatures; } -void GfDriver::setInterfaceIndex(int nItfIndex) -{ - _nItfIndex = nItfIndex; -} +// void GfDriver::setName(const std::string& strName) +// { +// _strName = strName; +// } -void GfDriver::setIsHuman(bool bIsHuman) -{ - _bIsHuman = bIsHuman; -} +// void GfDriver::setModuleName(const std::string& strModName) +// { +// _strModName = strModName; +// } + +// void GfDriver::setInterfaceIndex(int nItfIndex) +// { +// _nItfIndex = nItfIndex; +// } + +// void GfDriver::setIsHuman(bool bIsHuman) +// { +// _bIsHuman = bIsHuman; +// } void GfDriver::setCar(const GfCar* pCar) { diff --git a/src/libs/tgfdata/drivers.h b/src/libs/tgfdata/drivers.h index 453a7c2e6..9ddd31641 100644 --- a/src/libs/tgfdata/drivers.h +++ b/src/libs/tgfdata/drivers.h @@ -61,10 +61,11 @@ class TGFDATA_API GfDriver { public: - GfDriver(); - -public: + GfDriver(const std::string& strModuleName, int nItfIndex, + const std::string& strName, void* hparmRobot); + void load(void* hparmRobot); + const std::string& getName() const; const std::string& getModuleName() const; int getInterfaceIndex() const; @@ -76,10 +77,14 @@ public: bool matchesTypeAndCategory(const std::string& strType = "", const std::string& strCarCatId = "") const; - void setName(const std::string& strName); - void setModuleName(const std::string& strModName); - void setInterfaceIndex(int nItfIndex); - void setIsHuman(bool bIsHuman); + int getSupportedFeatures() const; + + double getSkillLevel() const; + +// void setName(const std::string& strName); +// void setModuleName(const std::string& strModName); +// void setInterfaceIndex(int nItfIndex); +// void setIsHuman(bool bIsHuman); void setCar(const GfCar* pCar); void setSkin(const GfDriverSkin& skin); @@ -107,6 +112,9 @@ protected: GfDriverSkin _skin; // Skin mutable std::string _strType; // Type ~ module type (ex: "simplix", "usr") + + double _fSkillLevel; // From 0 (pro) to 10 (rookie). + int _nFeatures; // Bit mask built with RM_FEATURE_* }; class TGFDATA_API GfDrivers diff --git a/src/libs/tgfdata/race.cpp b/src/libs/tgfdata/race.cpp index a318b0d14..51ae3335f 100644 --- a/src/libs/tgfdata/race.cpp +++ b/src/libs/tgfdata/race.cpp @@ -22,80 +22,173 @@ #include #include +#include #include #include #include "cars.h" #include "drivers.h" +#include "tracks.h" +#include "racemanagers.h" #include "race.h" +// Constants. +static const char *DispModeNames[GfRace::nDisplayModeNumber] = + { RM_VAL_VISIBLE, RM_VAL_INVISIBLE}; +static const char *TimeOfDaySpecNames[GfRace::nTimeSpecNumber] = RM_VALS_TIME; +static const char* CloudsSpecNames[GfRace::nCloudsSpecNumber] = RM_VALS_CLOUDS; +static const char *RainSpecNames[GfRace::nRainSpecNumber] = RM_VALS_RAIN; + // Private data for GfRace class GfRace::Private { public: - Private() : hparmRace(0), nMaxCompetitors(0) {}; + Private() : pRaceMan(0), pParameters(0), nMaxCompetitors(0), nFocusedItfIndex(-1) {}; public: - // The race params handle. - void* hparmRace; + // The "parent" race manager. + GfRaceManager* pRaceMan; + // Session type (like Qualification 1/2/3 ... Race ...) + std::string strSessionName; + + // Race parameters. + Parameters* pParameters; + // Max authorized number of competitors. unsigned nMaxCompetitors; // One GfDriver pointer for each competitor (order = race starting grid). std::vector vecCompetitors; - // TODO: Is this usefull ? // Map for quick access to GfDriver by { module name, interface index } typedef std::map, GfDriver*> TMapCompetitorsByKey; TMapCompetitorsByKey mapCompetitorsByKey; + + // Focused competitor (what for ?). + std::string strFocusedModuleName; + int nFocusedItfIndex; }; -GfRace::GfRace(void* hparmRace) +GfRace::GfRace() { _pPrivate = new GfRace::Private; - load(hparmRace); } void GfRace::clear() { - _pPrivate->hparmRace = 0; + _pPrivate->pRaceMan = 0; _pPrivate->nMaxCompetitors = 0; _pPrivate->mapCompetitorsByKey.clear(); _pPrivate->vecCompetitors.clear(); } -void GfRace::load(void* hparmRace) +void GfRace::load(GfRaceManager* pRaceMan) { + // Clear the race. clear(); - _pPrivate->hparmRace = hparmRace; + // Save the new race manager. + _pPrivate->pRaceMan = pRaceMan; - if (!_pPrivate->hparmRace) + // Check if usable, and exit if not. + if (!_pPrivate->pRaceMan) return; - // Load data from the race params. + void* hparmRaceMan = pRaceMan->getDescriptorHandle(); + + if (!hparmRaceMan) + return; + + // Load race parameters (from the "race config" configuration, if any). + // a) Search for the "race config" configuration. + std::ostringstream ossConfSecPath; + const char* pszSessionName = 0; + const int nbConfs = GfParmGetEltNb(hparmRaceMan, RM_SECT_CONF); + int nConfInd = 1; + while (nConfInd <= nbConfs) + { + ossConfSecPath.str(""); + ossConfSecPath << RM_SECT_CONF << '/' << nConfInd; + const char* pszConfType = + GfParmGetStr(hparmRaceMan, ossConfSecPath.str().c_str(), RM_ATTR_TYPE, 0); + if (pszConfType && !strcmp(pszConfType, RM_VAL_RACECONF)) + { + pszSessionName = + GfParmGetStr(hparmRaceMan, ossConfSecPath.str().c_str(), RM_ATTR_RACE, "Race"); + break; + } + nConfInd++; + } + + // b) If found, load the race parameters from it. + if (pszSessionName) + { + _pPrivate->pParameters = new Parameters; + + _pPrivate->strSessionName = pszSessionName; + + _pPrivate->pParameters->nLaps = + (int)GfParmGetNum(hparmRaceMan, pszSessionName, RM_ATTR_LAPS, NULL, 25); + _pPrivate->pParameters->nDistance = + (int)GfParmGetNum(hparmRaceMan, pszSessionName, RM_ATTR_DISTANCE, "km", 0); + _pPrivate->pParameters->nDuration = + (int)GfParmGetNum(hparmRaceMan, pszSessionName, RM_ATTR_SESSIONTIME, "s", 0); + + _pPrivate->pParameters->eDisplayMode = + strcmp(GfParmGetStr(hparmRaceMan, pszSessionName, RM_ATTR_DISPMODE, RM_VAL_VISIBLE), + RM_VAL_INVISIBLE) ? eDisplayNormal : eDisplayResultsOnly; + + const char* pszTimeOfDaySpec = + GfParmGetStr(hparmRaceMan, pszSessionName, RM_ATTR_TIME_OF_DAY, RM_VAL_TIME_AFTERNOON); + for (int i = 0; i < nTimeSpecNumber; i++) + if (!strcmp(pszTimeOfDaySpec, TimeOfDaySpecNames[i])) + { + _pPrivate->pParameters->eTimeOfDaySpec = (ETimeOfDaySpec)i; + break; + } + + const char* pszCloudsSpec = + GfParmGetStr(hparmRaceMan, pszSessionName, RM_ATTR_CLOUDS, RM_VAL_CLOUDS_NONE); + for (int i = 0; i < nCloudsSpecNumber; i++) + if (!strcmp(pszCloudsSpec, CloudsSpecNames[i])) + { + _pPrivate->pParameters->eCloudsSpec = (ECloudsSpec)i; + break; + } + + const char* pszRainSpec = + GfParmGetStr(hparmRaceMan, pszSessionName, RM_ATTR_RAIN, RM_VAL_RAIN_NONE); + for (int i = 0; i < nRainSpecNumber; i++) + if (!strcmp(pszRainSpec, RainSpecNames[i])) + { + _pPrivate->pParameters->eRainSpec = (ERainSpec)i; + break; + } + } + + // Load competitors data from the raceman params. _pPrivate->vecCompetitors.clear(); _pPrivate->mapCompetitorsByKey.clear(); _pPrivate->nMaxCompetitors = - (unsigned)GfParmGetNum(_pPrivate->hparmRace, RM_SECT_DRIVERS, RM_ATTR_MAXNUM, NULL, 0); - const int nCompetitors = GfParmGetEltNb(_pPrivate->hparmRace, RM_SECT_DRIVERS); - GfLogDebug("Competitors : n=%d (max=%d)\n", nCompetitors, _pPrivate->nMaxCompetitors); + (unsigned)GfParmGetNum(hparmRaceMan, RM_SECT_DRIVERS, RM_ATTR_MAXNUM, NULL, 0); + const int nCompetitors = GfParmGetEltNb(hparmRaceMan, RM_SECT_DRIVERS); + std::ostringstream ossDrvSecPath; for (int nCompIndex = 1; nCompIndex < nCompetitors+1; nCompIndex++) { - // Get driver infos from the the starting grid in the race params file - std::ostringstream ossSectionPath; - ossSectionPath << RM_SECT_DRIVERS << '/' << nCompIndex; + // Get driver infos from the the starting grid in the race params file. + ossDrvSecPath.str(""); + ossDrvSecPath << RM_SECT_DRIVERS << '/' << nCompIndex; const char* pszModName = - GfParmGetStr(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_MODULE, ""); + GfParmGetStr(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_MODULE, ""); const int nItfIndex = - (int)GfParmGetNum(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_IDX, NULL, 0); + (int)GfParmGetNum(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_IDX, NULL, 0); - GfLogDebug("Competitor #%d : %s#%d\n", nCompIndex, pszModName, nItfIndex); + //GfLogDebug("Competitor #%d : %s#%d\n", nCompIndex, pszModName, nItfIndex); // Try and retrieve this driver among all the available drivers GfDriver* pCompetitor = GfDrivers::self()->getDriver(pszModName, nItfIndex); @@ -111,26 +204,22 @@ void GfRace::load(void* hparmRace) if (acceptsMoreCompetitors()) { const char* pszSkinName = - GfParmGetStr(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_SKINNAME, ""); + GfParmGetStr(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_SKINNAME, ""); const int nSkinTargets = - (int)GfParmGetNum(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_SKINTARGETS, NULL, 0); + (int)GfParmGetNum(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_SKINTARGETS, NULL, 0); const bool bExtended = - GfParmGetNum(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_EXTENDED, NULL, 0) + GfParmGetNum(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_EXTENDED, NULL, 0) ? true : false; - GfLogDebug(" Name = %s, ext=%d\n", - pCompetitor->getName().c_str(), bExtended ? 1 : 0); - // Get the chosen car for the race if any specified (human only). const GfCar* pCar = 0; if (pCompetitor->isHuman() && bExtended) { - ossSectionPath.str(""); - ossSectionPath << RM_SECT_DRIVERINFO << '/' << pszModName + ossDrvSecPath.str(""); + ossDrvSecPath << RM_SECT_DRIVERINFO << '/' << pszModName << '/' << (bExtended ? 1 : 0) << '/' << nItfIndex; const char* pszCarId = - GfParmGetStr(hparmRace, ossSectionPath.str().c_str(), RM_ATTR_CARNAME, 0); - GfLogDebug(" Extended && Human, %s : %s\n", ossSectionPath.str().c_str(), pszCarId); + GfParmGetStr(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_CARNAME, 0); pCar = GfCars::self()->getCar(pszCarId); if (!pCar) GfLogError("Falling back to default car '%s' " @@ -156,12 +245,50 @@ void GfRace::load(void* hparmRace) break; } } + + // Load focused competitor data from the raceman params. + _pPrivate->strFocusedModuleName = + GfParmGetStr(hparmRaceMan, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, ""); + _pPrivate->nFocusedItfIndex = + (int)GfParmGetNum(hparmRaceMan, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, NULL, 0); } void GfRace::save() { + if (!_pPrivate->pRaceMan) + return; + + void* hparmRaceMan = _pPrivate->pRaceMan->getDescriptorHandle(); + + if (!hparmRaceMan) + return; + + // Save race manager level data. + _pPrivate->pRaceMan->save(); + + // Save race session and associated parameters. + if (_pPrivate->pParameters) + { + const Parameters* pParams = _pPrivate->pParameters; + const char* pszSessionName = _pPrivate->strSessionName.c_str(); + GfParmSetNum(hparmRaceMan, pszSessionName, RM_ATTR_LAPS, + (char*)NULL, (tdble)pParams->nLaps); + GfParmSetNum(hparmRaceMan, pszSessionName, RM_ATTR_DISTANCE, + "km", (tdble)pParams->nDistance); + GfParmSetNum(hparmRaceMan, pszSessionName, RM_ATTR_SESSIONTIME, + "s", (tdble)pParams->nDuration); + GfParmSetStr(hparmRaceMan, pszSessionName, RM_ATTR_DISPMODE, + DispModeNames[pParams->eDisplayMode]); + GfParmSetStr(hparmRaceMan, pszSessionName, RM_ATTR_TIME_OF_DAY, + TimeOfDaySpecNames[pParams->eTimeOfDaySpec]); + GfParmSetStr(hparmRaceMan, pszSessionName, RM_ATTR_CLOUDS, + CloudsSpecNames[pParams->eCloudsSpec]); + GfParmSetStr(hparmRaceMan, pszSessionName, RM_ATTR_RAIN, + RainSpecNames[pParams->eRainSpec]); + } + // Clear the race starting grid. - GfParmListClean(_pPrivate->hparmRace, RM_SECT_DRIVERS); + GfParmListClean(hparmRaceMan, RM_SECT_DRIVERS); // And then rebuild it from the current Competitors list state // (for each competitor, module name, interface index, car name if human, @@ -170,39 +297,39 @@ void GfRace::save() for (itComp = _pPrivate->vecCompetitors.begin(); itComp != _pPrivate->vecCompetitors.end(); itComp++) { - std::ostringstream ossSectionPath; - ossSectionPath << RM_SECT_DRIVERS + std::ostringstream ossDrvSecPath; + ossDrvSecPath << RM_SECT_DRIVERS << '/' << (unsigned)(itComp - _pPrivate->vecCompetitors.begin() + 1); - const std::string strDrvSec(ossSectionPath.str()); + const std::string strDrvSec(ossDrvSecPath.str()); - GfParmSetNum(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_IDX, (char*)NULL, + GfParmSetNum(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_IDX, (char*)NULL, (tdble)(*itComp)->getInterfaceIndex()); - GfParmSetStr(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_MODULE, + GfParmSetStr(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_MODULE, (*itComp)->getModuleName().c_str()); const GfCar* pCar = (*itComp)->getCar(); if (pCar && (*itComp)->isHuman()) { /* Set extended */ - GfParmSetNum(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_EXTENDED, NULL, 1); + GfParmSetNum(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_EXTENDED, NULL, 1); - ossSectionPath.str(""); - ossSectionPath << RM_SECT_DRIVERINFO << '/' << (*itComp)->getModuleName() + ossDrvSecPath.str(""); + ossDrvSecPath << RM_SECT_DRIVERINFO << '/' << (*itComp)->getModuleName() << '/' << 1 /*extended*/ << '/' << (*itComp)->getInterfaceIndex(); - GfParmSetStr(_pPrivate->hparmRace, ossSectionPath.str().c_str(), RM_ATTR_CARNAME, + GfParmSetStr(hparmRaceMan, ossDrvSecPath.str().c_str(), RM_ATTR_CARNAME, pCar->getId().c_str()); // Save also the chosen car as the default one for this human driver // (may be needed later for races where it is not specified in .xml) std::ostringstream ossFilePath; - ossFilePath << GfLocalDir() << "drivers/" << (*itComp)->getModuleName() + ossFilePath << GetLocalDir() << "drivers/" << (*itComp)->getModuleName() << '/' << (*itComp)->getModuleName() << PARAMEXT; void* hparmRobot = GfParmReadFile(ossFilePath.str().c_str(), GFPARM_RMODE_STD); - ossSectionPath.str(""); - ossSectionPath << ROB_SECT_ROBOTS << '/' << ROB_LIST_INDEX + ossDrvSecPath.str(""); + ossDrvSecPath << ROB_SECT_ROBOTS << '/' << ROB_LIST_INDEX << '/' << (*itComp)->getInterfaceIndex(); - GfParmSetStr(hparmRobot, ossSectionPath.str().c_str(), ROB_ATTR_CAR, + GfParmSetStr(hparmRobot, ossDrvSecPath.str().c_str(), ROB_ATTR_CAR, pCar->getId().c_str()); GfParmWriteFile(NULL, hparmRobot, (*itComp)->getModuleName().c_str()); GfParmReleaseHandle(hparmRobot); @@ -210,18 +337,57 @@ void GfRace::save() else { /* Not extended for robots yet in driverconfig */ - GfParmSetNum(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_EXTENDED, NULL, 0); + GfParmSetNum(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_EXTENDED, NULL, 0); } // Skin and skin targets. const GfDriverSkin& skin = (*itComp)->getSkin(); - GfParmSetNum(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_SKINTARGETS, (char*)NULL, + GfParmSetNum(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_SKINTARGETS, NULL, (tdble)skin.getTargets()); if ((!skin.getName().empty()) - || GfParmGetStr(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_SKINNAME, 0)) - GfParmSetStr(_pPrivate->hparmRace, strDrvSec.c_str(), RM_ATTR_SKINNAME, + || GfParmGetStr(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_SKINNAME, 0)) + GfParmSetStr(hparmRaceMan, strDrvSec.c_str(), RM_ATTR_SKINNAME, skin.getName().c_str()); } + + // Save focused competitor data to the raceman params. + const GfDriver* pFocComp = getFocusedCompetitor(); + GfParmSetStr(hparmRaceMan, RM_SECT_DRIVERS, RM_ATTR_FOCUSED, + _pPrivate->strFocusedModuleName.c_str()); + GfParmSetNum(hparmRaceMan, RM_SECT_DRIVERS, RM_ATTR_FOCUSEDIDX, NULL, + (tdble)_pPrivate->nFocusedItfIndex); +} + +GfRaceManager* GfRace::getManager() const +{ + return _pPrivate->pRaceMan; +} + +const std::string& GfRace::getSessionName() const +{ + return _pPrivate->strSessionName; +} + +GfRace::Parameters* GfRace::getParameters() +{ + return _pPrivate->pParameters; +} + +int GfRace::getSupportedFeatures() const +{ + int nFeatures = 0; + + std::vector::const_iterator itComp; + for (itComp = _pPrivate->vecCompetitors.begin(); + itComp != _pPrivate->vecCompetitors.end(); itComp++) + { + if (itComp == _pPrivate->vecCompetitors.begin()) + nFeatures = (*itComp)->getSupportedFeatures(); + else + nFeatures &= (*itComp)->getSupportedFeatures(); + } + + return nFeatures; } const std::vector& GfRace::getCompetitors() const @@ -242,7 +408,7 @@ bool GfRace::acceptsMoreCompetitors() const GfDriver* GfRace::getCompetitor(const std::string& strModName, int nItfIndex) const { const std::pair compKey(strModName, nItfIndex); - Private::TMapCompetitorsByKey::iterator itComp; + Private::TMapCompetitorsByKey::iterator itComp = _pPrivate->mapCompetitorsByKey.find(compKey); if (itComp != _pPrivate->mapCompetitorsByKey.end()) return itComp->second; @@ -250,6 +416,23 @@ GfDriver* GfRace::getCompetitor(const std::string& strModName, int nItfIndex) co return 0; } +bool GfRace::isCompetitorFocused(const GfDriver* pComp) const +{ + return _pPrivate->strFocusedModuleName == pComp->getModuleName() + && _pPrivate->nFocusedItfIndex == pComp->getInterfaceIndex(); +} + +GfDriver* GfRace::getFocusedCompetitor() const +{ + return getCompetitor(_pPrivate->strFocusedModuleName, _pPrivate->nFocusedItfIndex); +} + +void GfRace::setFocusedCompetitor(const GfDriver* pComp) +{ + _pPrivate->strFocusedModuleName = pComp ? pComp->getModuleName() : ""; + _pPrivate->nFocusedItfIndex = pComp ? pComp->getInterfaceIndex() : -1; +} + bool GfRace::appendCompetitor(GfDriver* pComp) { const bool bAppended = acceptsMoreCompetitors(); @@ -358,3 +541,20 @@ bool GfRace::shuffleCompetitors() return true; } + +GfTrack* GfRace::getTrack() const +{ + return _pPrivate->pRaceMan ? _pPrivate->pRaceMan->getCurrentEventTrack() : 0; +} + +void GfRace::setTrack(GfTrack* pTrack) +{ + if (_pPrivate->pRaceMan && pTrack) + _pPrivate->pRaceMan->setCurrentEventTrack(pTrack); +} + +void GfRace::print() const +{ + // TODO. + GfLogWarning("GfTrack::print() not yet implemented\n"); +} diff --git a/src/libs/tgfdata/race.h b/src/libs/tgfdata/race.h index 91cee73be..7c1bea812 100644 --- a/src/libs/tgfdata/race.h +++ b/src/libs/tgfdata/race.h @@ -32,23 +32,55 @@ #include "tgfdata.h" +class GfRaceManager; class GfDriver; +class GfTrack; class TGFDATA_API GfRace { public: - GfRace(void* hparmRace = 0); + //! Constructor. + GfRace(); - //! Load from the race params. - void load(void* hparmRace); + //! Load from the given race manager params file. + void load(GfRaceManager* pRaceMan); //! Clear the race. void clear(); - //! Save to the race params. + //! Save to the race manager params file. void save(); + + GfRaceManager* getManager() const; + + const std::string& getSessionName() const; + + enum EDisplayMode { eDisplayNormal, eDisplayResultsOnly, + nDisplayModeNumber }; + enum ETimeOfDaySpec { eTimeDawn, eTimeMorning, eTimeNoon, eTimeAfternoon, + eTimeDusk, eTimeNight, eTimeNow, eTimeFromTrack, + nTimeSpecNumber }; + enum ECloudsSpec { eCloudsNone, eCloudsFew, eCloudsScarce, eCloudsMany, eCloudsFull, + nCloudsSpecNumber}; + enum ERainSpec { eRainNone, eRainLittle, eRainMedium, eRainHeavy, eRainRandom, + nRainSpecNumber }; + class Parameters + { + public: + int nLaps; + int nDistance; // km + int nDuration; // s + EDisplayMode eDisplayMode; + ETimeOfDaySpec eTimeOfDaySpec; + ECloudsSpec eCloudsSpec; + ERainSpec eRainSpec; + }; + + Parameters* getParameters(); + + int getSupportedFeatures() const; unsigned getCompetitorsCount() const; const std::vector& getCompetitors() const; @@ -60,14 +92,15 @@ public: bool shuffleCompetitors(); GfDriver* getCompetitor(const std::string& strModName, int nItfIndex) const; -// GfDriver* getCompetitorWithName(const std::string& strName) const; -// const std::string& getCompetitorName(const std::string& strId) const; -// std::vector getCompetitorsInCategory(const std::string& strCatId = "") const; -// std::vector getCompetitorIdsInCategory(const std::string& strCatId = "") const; -// std::vector getCompetitorIdsInCategory(const std::string& strCatId = "") const; + bool isCompetitorFocused(const GfDriver* pComp) const; + GfDriver* getFocusedCompetitor() const; + void setFocusedCompetitor(const GfDriver* pComp); + + GfTrack* getTrack() const; + void setTrack(GfTrack* pTrack); -// void print() const; + void print() const; protected: diff --git a/src/libs/tgfdata/racemanagers.cpp b/src/libs/tgfdata/racemanagers.cpp index 8b1daaff9..92421cf6e 100755 --- a/src/libs/tgfdata/racemanagers.cpp +++ b/src/libs/tgfdata/racemanagers.cpp @@ -23,6 +23,7 @@ #include +#include "tracks.h" #include "racemanagers.h" @@ -99,7 +100,6 @@ GfRaceManagers::GfRaceManagers() } } - //const std::string strRaceManId(pFile->name, strlen(pFile->name) - strlen(PARAMEXT)); std::string strRaceManId(pFile->name); strRaceManId.erase(strlen(pFile->name) - strlen(PARAMEXT)); if (!hparmRaceMan) @@ -109,14 +109,8 @@ GfRaceManagers::GfRaceManagers() continue; } - // Read race manager info and store it in the GfRaceManager structure. - GfRaceManager* pRaceMan = new GfRaceManager; - pRaceMan->setId(strRaceManId); - pRaceMan->setName(GfParmGetStr(hparmRaceMan, RM_SECT_HEADER, RM_ATTR_NAME, "")); - pRaceMan->setType(GfParmGetStr(hparmRaceMan, RM_SECT_HEADER, RM_ATTR_TYPE, "")); - pRaceMan->setSubType(GfParmGetStr(hparmRaceMan, RM_SECT_HEADER, RM_ATTR_SUBTYPE, "")); - pRaceMan->setPriority((int)GfParmGetNum(hparmRaceMan, RM_SECT_HEADER, RM_ATTR_PRIO, NULL, 10000)); - pRaceMan->setDescriptorHandle(hparmRaceMan); + // Create the race manager and load it from the params file. + GfRaceManager* pRaceMan = new GfRaceManager(strRaceManId, hparmRaceMan); // Update the GfRaceManagers singleton. _pPrivate->vecRaceMans.push_back(pRaceMan); @@ -132,6 +126,7 @@ GfRaceManagers::GfRaceManagers() // Sort the race manager vector by priority. std::sort(_pPrivate->vecRaceMans.begin(), _pPrivate->vecRaceMans.end(), hasHigherPriority); + // And log what we've got now. print(); } @@ -161,7 +156,7 @@ GfRaceManager* GfRaceManagers::getRaceManagerWithName(const std::string& strName return 0; } -const std::vector GfRaceManagers::getRaceManagersWithType(const std::string& strType) const +std::vector GfRaceManagers::getRaceManagersWithType(const std::string& strType) const { std::vector vecRaceMans; @@ -193,15 +188,94 @@ void GfRaceManagers::print() const // GfRaceManager class --------------------------------------------------------------- -GfRaceManager::GfRaceManager() : _nPriority(-1), _hparmHandle(0) +GfRaceManager::GfRaceManager(const std::string& strId, void* hparmHandle) { + _strId = strId; + + // Load constant properties (never changed afterwards). + _strName = GfParmGetStr(hparmHandle, RM_SECT_HEADER, RM_ATTR_NAME, ""); + _strType = GfParmGetStr(hparmHandle, RM_SECT_HEADER, RM_ATTR_TYPE, ""); + _strSubType = GfParmGetStr(hparmHandle, RM_SECT_HEADER, RM_ATTR_SUBTYPE, ""); + _nPriority = (int)GfParmGetNum(hparmHandle, RM_SECT_HEADER, RM_ATTR_PRIO, NULL, 10000); + + // Load other "mutable" properties. + reset(hparmHandle, false); } +void GfRaceManager::reset(void* hparmHandle, bool bClosePrevHdle) +{ + if (bClosePrevHdle && _hparmHandle) + GfParmReleaseHandle(_hparmHandle); + _hparmHandle = hparmHandle; + + // Get current event in the schedule. + _nCurrentEventInd = + (int)GfParmGetNum(_hparmHandle, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, 1) - 1; + + // Load track id for each event in the schedule. + std::ostringstream ossSectionPath; + int nEventNum = 1; + const char* pszTrackId; + do + { + ossSectionPath.str(""); + ossSectionPath << RM_SECT_TRACKS << '/' << nEventNum; + pszTrackId = GfParmGetStr(_hparmHandle, ossSectionPath.str().c_str(), RM_ATTR_NAME, 0); + if (pszTrackId) + { + _vecEventTrackIds.push_back(pszTrackId); + nEventNum++; + } + } + while (pszTrackId); +} + +void GfRaceManager::save() +{ + if (!_hparmHandle) + return; + + // Note: No need to save constant properties (never changed). + + // Current event in the schedule. + GfParmSetNum(_hparmHandle, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, + (tdble)(_nCurrentEventInd + 1)); + + // Info about each event in the schedule. + std::ostringstream ossSectionPath; + for (unsigned nEventInd = 0; nEventInd < _vecEventTrackIds.size(); nEventInd++) + { + ossSectionPath.str(""); + ossSectionPath << RM_SECT_TRACKS << '/' << nEventInd + 1; + GfParmSetStr(_hparmHandle, ossSectionPath.str().c_str(), RM_ATTR_NAME, + _vecEventTrackIds[nEventInd].c_str()); + GfTrack* pTrack = GfTracks::self()->getTrack(_vecEventTrackIds[nEventInd]); + GfParmSetStr(_hparmHandle, ossSectionPath.str().c_str(), RM_ATTR_CATEGORY, + pTrack->getCategoryId().c_str()); + } +} + +GfRaceManager::~GfRaceManager() +{ + if (_hparmHandle) + GfParmReleaseHandle(_hparmHandle); +} + const std::string& GfRaceManager::getId() const { return _strId; } +void* GfRaceManager::getDescriptorHandle() const +{ + return _hparmHandle; +} + +std::string GfRaceManager::getDescriptorFileName() const +{ + return const_cast(GfParmGetFileName(_hparmHandle)); +} + const std::string& GfRaceManager::getName() const { return _strName; @@ -222,38 +296,37 @@ const int GfRaceManager::getPriority() const return _nPriority; } -void* GfRaceManager::getDescriptorHandle() const +unsigned GfRaceManager::getEventCount() const { - return _hparmHandle; + return _vecEventTrackIds.size(); } -void GfRaceManager::setId(const std::string& strId) +bool GfRaceManager::stepToNextEvent() { - _strId = strId; + if (_nCurrentEventInd < (int)_vecEventTrackIds.size() - 1) + { + _nCurrentEventInd++; + return true; + } + + return false; } -void GfRaceManager::setName(const std::string& strName) +GfTrack* GfRaceManager::getCurrentEventTrack() { - _strName = strName; + GfTrack* pTrack; + + // If the current event track is not usable, step to the next event (an so on). + while (!(pTrack = GfTracks::self()->getTrack(_vecEventTrackIds[_nCurrentEventInd])) + && stepToNextEvent()); + + return pTrack; } -void GfRaceManager::setType(const std::string& strType) +void GfRaceManager::setCurrentEventTrack(GfTrack* pTrack) { - _strType = strType ; -} + if (!pTrack) + return; -void GfRaceManager::setSubType(const std::string& strSubType) -{ - _strSubType = strSubType; + _vecEventTrackIds[_nCurrentEventInd] = pTrack->getId(); } - -void GfRaceManager::setPriority(int nPriority) -{ - _nPriority = nPriority; -} - -void GfRaceManager::setDescriptorHandle(void* hparmHandle) -{ - _hparmHandle = hparmHandle; -} - diff --git a/src/libs/tgfdata/racemanagers.h b/src/libs/tgfdata/racemanagers.h index 718993f05..d6516fedd 100755 --- a/src/libs/tgfdata/racemanagers.h +++ b/src/libs/tgfdata/racemanagers.h @@ -25,6 +25,8 @@ #include "tgfdata.h" +class GfTrack; + /** @file Singleton holding information on the available race managers @@ -35,33 +37,40 @@ class TGFDATA_API GfRaceManager { public: - GfRaceManager(); - -public: + GfRaceManager(const std::string& strId, void* hparmHandle); + void reset(void* hparmHandle, bool bClosePrevHdle = false); + ~GfRaceManager(); + const std::string& getId() const; + void* getDescriptorHandle() const; + std::string getDescriptorFileName() const; + const std::string& getName() const; const std::string& getType() const; const std::string& getSubType() const; const int getPriority() const; - void* getDescriptorHandle() const; - void setId(const std::string& strId); - void setName(const std::string& strName); - void setType(const std::string& strType); - void setSubType(const std::string& strSubType); - void setPriority(int nPriority); - void setDescriptorHandle(void* hparmHandle); + unsigned getEventCount() const; + bool stepToNextEvent(); + GfTrack* getCurrentEventTrack(); + void setCurrentEventTrack(GfTrack* pTrack); + + //! Save data to params (in-memory). + void save(); protected: std::string _strId; // XML file name (ex: quickrace, singleevent-endurance, championship-sc) + void* _hparmHandle; // Params handle to the descriptor file. + std::string _strName; // User friendly full name (ex: Quick Race, Supercar Championship). std::string _strType; // User friendly type name (ex: Quick Race, Single Event, Championship). std::string _strSubType; // User friendly sub-type name (ex: "", Endurance, Challenge, Supercars"). - std::string _strDescFile; // Path-name of the XML descriptor file. int _nPriority; // Gives the order of the buttons in the race select menu - void* _hparmHandle; // Params handle to the descriptor file. + + std::vector _vecEventTrackIds; // Id of the track for each event. + int _nCurrentEventInd; }; class TGFDATA_API GfRaceManagers @@ -76,7 +85,7 @@ public: GfRaceManager* getRaceManager(const std::string& strId) const; GfRaceManager* getRaceManagerWithName(const std::string& strName) const; - const std::vector getRaceManagersWithType(const std::string& strType = "") const; + std::vector getRaceManagersWithType(const std::string& strType = "") const; void print() const; diff --git a/src/libs/tgfdata/tgfdata.h b/src/libs/tgfdata/tgfdata.h index 5c36e2040..8295f61fb 100755 --- a/src/libs/tgfdata/tgfdata.h +++ b/src/libs/tgfdata/tgfdata.h @@ -36,6 +36,11 @@ # define TGFDATA_API #endif +#ifdef _MSC_VER +// Disable useless MSVC warnings +# pragma warning (disable:4251) // class XXX needs a DLL interface ... +#endif + #endif /* __TGFDATA__H__ */ diff --git a/src/libs/tgfdata/tracks.cpp b/src/libs/tgfdata/tracks.cpp index 57198bbcc..25f32b172 100755 --- a/src/libs/tgfdata/tracks.cpp +++ b/src/libs/tgfdata/tracks.cpp @@ -278,6 +278,121 @@ std::vector GfTracks::getTrackNamesInCategory(const std::string& st return vecTrackNames; } +/** + * GfTracks::getFirstUsableTrack + * + * Retrieve the first usable track in the given category, searching in the given direction + * and skipping the first found if specified + * + * @param strCatId Id of the category to search inside of. + * @param strFromTrackId Id of the track from which to start the search. + * @param nSearchDir <0 = previous, >0 = next. + * @param bSkipFrom If true, skip the first found track. + */ +GfTrack* GfTracks::getFirstUsableTrack(const std::string& strCatId, + const std::string& strFromTrackId, + int nSearchDir, bool bSkipFrom) const +{ + // Check and fix nSearchDir. + nSearchDir = nSearchDir > 0 ? +1 : -1; + + // Check category. + if (std::find(_pPrivate->vecCatIds.begin(), _pPrivate->vecCatIds.end(), strCatId) + == _pPrivate->vecCatIds.end()) + { + GfLogError("GfTracks::getFirstUsableTrack : No such category %s\n", strCatId.c_str()); + return 0; + } + + // Retrieve tracks in this category. + const std::vector vecTracksInCat = getTracksInCategory(strCatId); + if (vecTracksInCat.size() == 0) + { + // Should never happen, empty categories are not even created ... + GfLogError("GfTracks::getFirstUsableTrack : Empty category %s\n", strCatId.c_str()); + return 0; + } + + // Retrieve the index of the specified track to start from, if any. + int nCurTrackInd = 0; + if (!strFromTrackId.empty()) + { + std::vector::const_iterator itTrack = vecTracksInCat.begin(); + while (itTrack != vecTracksInCat.end()) + { + if ((*itTrack)->getId() == strFromTrackId) + { + nCurTrackInd = itTrack - vecTracksInCat.begin(); + break; + } + itTrack++; + } + } + + int nTrackInd = nCurTrackInd; + if (bSkipFrom || !vecTracksInCat[nTrackInd]->isUsable()) + { + const int nPrevTrackInd = nCurTrackInd; + do + { + nTrackInd = + (nTrackInd + nSearchDir + vecTracksInCat.size()) % vecTracksInCat.size(); + } + while (nTrackInd != nPrevTrackInd && !vecTracksInCat[nTrackInd]->isUsable()); + } + + GfTrack* pTrack = 0; + if (vecTracksInCat[nTrackInd]->isUsable()) + pTrack = vecTracksInCat[nTrackInd]; + + return pTrack; +} + +/** + * GfTracks::getFirstUsableTrack + * + * Retrieve the first usable track among all categories, searching in the given direction + * from the given category, but skipping it if specified + * + * @param strFromCatId Id of the category to search inside of. + * @param nSearchDir <0 = previous, >0 = next. + * @param bSkipFrom If true, skip the first found track. + */ +GfTrack* GfTracks::getFirstUsableTrack(const std::string& strFromCatId, + int nSearchDir, bool bSkipFrom) const +{ + // Check and fix nSearchDir. + nSearchDir = nSearchDir > 0 ? +1 : -1; + + // Retrieve and check category. + const std::vector& vecCatIds = GfTracks::self()->getCategoryIds(); + std::vector::const_iterator itFromCat = + std::find(_pPrivate->vecCatIds.begin(), _pPrivate->vecCatIds.end(), strFromCatId); + if (itFromCat == _pPrivate->vecCatIds.end()) + { + GfLogError("GfTracks::getFirstUsableTrack : No such category %s\n", strFromCatId.c_str()); + return 0; + } + + int nCatInd = itFromCat - _pPrivate->vecCatIds.begin(); + + GfTrack* pTrack = 0; + + if (bSkipFrom || !(pTrack = getFirstUsableTrack(_pPrivate->vecCatIds[nCatInd]))) + { + const int nPrevCatInd = nCatInd; + do + { + nCatInd = + (nCatInd + nSearchDir + _pPrivate->vecCatIds.size()) % _pPrivate->vecCatIds.size(); + pTrack = getFirstUsableTrack(_pPrivate->vecCatIds[nCatInd]); + } + while (nCatInd != nPrevCatInd && !pTrack); + } + + return pTrack; +} + void GfTracks::print(bool bVerbose) const { GfLogTrace("Track base : %d categories, %d tracks\n", diff --git a/src/libs/tgfdata/tracks.h b/src/libs/tgfdata/tracks.h index 1d6c6e3d9..084df7b23 100755 --- a/src/libs/tgfdata/tracks.h +++ b/src/libs/tgfdata/tracks.h @@ -113,6 +113,12 @@ public: std::vector getTrackIdsInCategory(const std::string& strCatId = "") const; std::vector getTrackNamesInCategory(const std::string& strCatId = "") const; + GfTrack* getFirstUsableTrack(const std::string& strCatId, + const std::string& strFromTrackId = "", + int nSearchDir = +1, bool bSkipFrom = false) const; + GfTrack* getFirstUsableTrack(const std::string& strFromCatId, + int nSearchDir, bool bSkipFrom = false) const; + void print(bool bVerbose = false) const; protected: