Customization Overview

Understand The Spotter Configuration files
Here a description of the customization power of this spotter, Not that this explication does not list all possible values, just an extract to show you the possibilites.

First, the spotter need a main ini file named Spotter.ini // if the vehicle class does not have it own parameter, the one in [DEFAULT] will be used instead. // In addition to the predefined parameters, you can create your own parameters and use them as Inputs in the rules files. // Those parameters must be prefixed by "v:" [DEFAULT] Rules.file=DefaultRules.ini Sounds.subPath=Sounds/EN DriverNames.subPath=Sounds/Drivers DriverNames.extension=wav Mapping.VehicleClass.file=vehicleClass.ini // usefull for multi category (when the mod does not have already one class per category) maxDetailLevel=2 v:breakTooHot=600 v:breakTooCold=500 As you can see, there is a [DEFAULT] section, and you can override any number of parameters in a section named with the VehicleClass provided by rF2 to the plugin in the VehicleClass mapping file.

So it will be possible to point to another spotter rules, for vehicle classes who run in NASCAR.

Here some explained parameters : Now looking to the vehicleClass file (the provided one, is very simple as all cars are grouped into a single category) - if you want to provide me a customized one, don't hesitate (for example if you already do the job in my plugin TV) - You can also override variable defined in the Spotter.ini // The [**DEFAULT**] is usefull for mono category config in case of you still want to display category informations - Those data are taken into account when there is no matching section equals to the rF2 vehicule class info [**DEFAULT**] category.name=*** // each section must have the name of each rF2 vehicule class string (used for multi category race) //[Corvette ALMS GT2 2009] //category.name=GT2 //v:breakTooHot=900 //v:breakTooCold=300 So when the plugin must compare your best lap, or any other relating timing comparaison, it will do it only with the other cars in the same category as you.
 * Rules.file : point to a file containing the spotter rules to apply (relative path from the Spotter directory)
 * Sounds.subPath : sub path to find sounds directory (usefull for multilanguage support)
 * DriverNames.subPath : sub path to find driver name sounds directory (usefull to put those sound outside the other sounds - usefull for league)
 * DriverNames.extension : extension to add after the driver name to retrieve the sound file. For exemple, if the driver name is "Amphiprion" and the extension is "wav", it will look the sound "Amphiprion.wav" in the DriverNames.subPath
 * maxDetailLevel : Each Event have a level, so this spotter will only analyse events having a detail value lower or equals to this max
 * Mapping.VehicleClass.file : point to a file providing category and overrided variable for each vehicle class. The category is used to group best laps per category, indeed in endurance race, there is no reason to compare the best lap of a GT to a P2. If you set debugMode=1 you will see the vehicle Class received by the plugin (Spotter.log), and so you will know how to name the class section.
 * v:  : this allows to create any number of user defined variable and provide them as input of event evaluation. For example, the brakes temperature threshold (thanks to the overridable mechanism in the vehicle mapping ini file, you can create a section for a given vehicle class, and set another value for a given user variable - ex: different threshold for different class cars)

Now, we enter in the main subject, starting with the rules file (example with an extract of DefaultRules.ini) [Main] Events.file=DefaultEvents.ini Rules.count=12 // One section per rule // [Rule.1] for the first rule, [Rule.2] for the second rule, ... The [Main] section is very simple: Then, you can define each rules. Here an example of the rule who compare your S1 time to your best lap S1 [Rule.1] Trigger=S1 Event=SelfGapSector1 Input1=SelfGap A rule can contains those parameters: A Trigger can be one of the predefined triggers (S1, OnPlaceChanged, ...)
 * Events.file : the file containing the detail of each events (algorhytm engine)
 * Rules.count : the number of rules, so the spotter will read all section from [Rule.1] to [Rule.n]
 * Trigger : When this rule must be evaluated
 * Trigger.Shortcut : Affect a shortcut to manually trigger this rule (put the index (1..n) of the shortcut defined in the Spotter.ini file).
 * Event : The name a the event (in the event file) to evaluate
 * Input1 : the value of the first input provided to the event (optional, depends to the choosen event)
 * Input2 : the value of the second input provided to the event (optional, depends to the choosen event)
 * Input3 : the value of the third input provided to the event (optional, depends to the choosen event)

An input can be several things like a fixed value (10.3), a user defined variable (v:breakTempMinThreshold), or a predefined spotter variable (Laptime) So as soon as a trigger exist and a data is provided by the spotter, you can create any kind of event (it is the "near" 100% customizable) - but like all my tools, if a something is missing to achieve a work, i will add it - for now, its is only a first version of the plugins, so several rf2 data and triggers are still missing. Here what some of triggers and predefined variables


 * Trigger

//    ScoreUpdate : correspond to a call to the UpdateScoring method of the plugin API (around every 0.5s) - WARNING: do not put too many rule with this trigger to avoid FPS loss //    AnySector : when the car reach a sector //    S1 : when the car reach the sector 1 //    S2 : when the car reach the sector 2 //    S3 : when the car reach the sector 3 (just finish a lap) //    PlaceChanged : when you rank change //    StartLightGo : When the starting light is green //    SectorFlagChanged : When one of the 3 sector flag change //    NewBestLap : When the beat the best laptime (all drivers best lap) //    NewCategoryBestLap : When the beat "only" the category best laptime //    NewSelfBestLap : When the beat "only" your own best laptime //    Finished : When you finish the session


 * Input1/2/3

//    <"hardcoded" number> : such as -0.37, range is that of IEEE double-precision floating point number //    v: : one of the custom variable defined in the Spotter.ini file //    Session : 0 - 13, 0=test day, 1=practice1 ..., 5=qual1, ..., 9=warmup, 10=race1..., 13=race3 //    Laptime : your laptime of the just finished lap (if trigger S3), else it is the current laptime //    MyBestLaptime : your current best lap (not yet updated in trigger S3, if you just beat it) //    Place : your current position //    LastPlace : your last position //    OilTemp : your oil temperature (celcius) //    WaterTemp : your water temperature (celcius) //    BreakTemp : your breaks temperature (celcius) - (take the higher temperature of the 4 wheels) //    TireTemp : your tire temperature (celcius) - (take the higher temperature of the 4 wheels - the center part of the wheel) //    TireInnerLayer : your inner layer (before carcass) tire temperature (celcius) - (take the higher temperature of the 4 wheels - the center part of the wheel) //    TireCarcass : your carcass tire temperature (celcius) - (take the higher temperature of the 4 wheels) //    TireTemp : your tire temperature (celcius) - (take the higher temperature of the 4 wheels - the center part of the wheel) //    Fuel : your fuel left (liters) //    FuelCapacity : your fuel tank capacity (liters) //    FuelPerLap : Fuel quantity used to completed the last lap - (updated at S3) //    RemainingLapsWithFuel : Number of laps remaining before empty fuel (based on FuelPerLap) - (updated at S3) - equals to "1000001" if FuelPerLap is not yet computed //    RemainingLaps : Number of laps remaining before the end of the session - (updated at S3) - equals to "1000000" if not yet computed //    NumberOfStartLight : Number of light in the start sequence (track specificity) //    CurrentStartLight : Current number of light (on) - if CurrentStartLight == NumberOfStartLight means the race start. //    Lap : the current lap number (0 for the first lap) //    TrackLapDist : The track lap distance (meter) //    LapDist : you current lap distance (meter) //    LapDistRatio : you current lap distance compare to the track lap distance(0.0 to 1.0) //    S1Flag : 0 = no flag, 1 = yellow flag //    S2Flag : 0 = no flag, 1 = yellow flag //    S3Flag : 0 = no flag, 1 = yellow flag //    OldSelfBestLaptime : my previous self best laptime (updated on trigger NewBestLap > NewCategoryBestLap > NewSelfBestLap - if you beat a any king of best lap only one will be triggered) //    OldBestLaptime : the beaten best laptime (updated on trigger NewBestLap > NewCategoryBestLap > NewSelfBestLap - if you beat a any king of best lap only one will be triggered) //    SelfGap : the gap to your previous best (updated at each sector) //    FinishStatus : your finish status (0=none, 1=finish, 2=dnf, 3=dq)

Now the most power full part of the spotter (this is based on the logic used by ISI in its own spotter, but in an enhanced way as i added several new features)

Mainly, this logic allow you to define event parameters and then create any number of condition (if) and action. Here the exemple of the  "SelfGapSector1" event, as it will be easyer to explain with an example:

Note: the explaination is in the comments (// .......)

// Tells player a sector 1 gap (compare to s1 of self best lap) Event=SelfGapSector1 // Input1 = sector1 gap { // Event properties (note that these are not applied if this event is played by another event) Detail=1 // Detail level (so this event will be evaluated as soon as the maxDetailLevel is t lest equals to 1 in the Spotter.ini  Spacing=0.0 // Number of second to wait before another event of this type is evaluate (0.0 as this event is used only on Trigger=S1)  Priority=1 // highest priority (used to priorize event in the awaiting queues - when several event occurs in the same time) - from 0.0 (lowest) to 1.0 (highest)  Probability=1.0 // probability to evaluate this event (0.0 (never - 0%) - 1.0 (always - 100%) TTL=10.0 // Time to live (in seconds) in the awaiting queue before he is discarded - so if this time is reached without being yet evaluated, it is discarded Break=0.25 // number of second (pause) to wait before any other awaiting event is evaluated // Repeat until duration ends (Not yet supported) Repeat=Off Duration=0.0 Volume=1.0 // volume from 0.0 to 1.0 // Now the real algorhytm to see if a sound must be played and which sound(s) Variable=Session      // set the working variable to the Session value {  Value=(>=0,<=8) { // check if we are not in WarmUp or Race Variable=Input1  // set the working variable to Input1 (the rule file set "SelfGap" as input1) {      Value=(>0,<=1.0) {  // look if the gap is positive and lower than 1.0s (so the spotter only speak if the gap is less than a second) File=slow_on_first.wav  // tell "Sector one is slower by..." PlayEvent=Gap             // play the other event which is used to tell the gap value (using the working variable as Input1 of the event) }      Value=(>=-1.0, <0) {  // look if the gap is negative and lower than 1.0s (so the spotter only speak if the gap is less than a second) Variable=Absolute { // get the absolution value of input1 (need a positive value for the "Gap" event) File=fast_on_first.wav  // tell "sector one is faster by..." PlayEvent=Gap   // play the other event which is used to tell the gap value (using the working variable as Input1 of the event) }      }     }   }  } }

Now the Gap event who is used to tell the gap value. As in our example, the Gap event is played by another event, its own properties (Detail, Spacing, etc...) are ignored. Only the logic is taken into account, and the Input1 is the one inherited from the calling event

// Tells player a gap Event=Gap // Input1 = gap (speak only if gap < 30s) {  // Event properties (note that these are not applied if this event is played by another event) Detail=1 Spacing=0.0 Priority=1 Probability=1.0 TTL=10.0 Break=0.25 // Repeat until duration ends Repeat=Off Duration=0.0 Volume=1.0 // Variable used to choose one File to play for this Sound (Variable compared to Value) Variable=Input1 {    Value=(>0;<0.10) { File=gap_000.wav } // tell "less than 0.1 second" Value=(>=0.1;<0.15) { File=gap_001.wav } // tell "less 0.1 second" Value=(>=0.15;<0.25) { File=gap_002.wav } Value=(>=0.25;<0.35) { File=gap_003.wav } Value=(>=0.35;<0.45) { File=gap_004.wav } Value=(>=0.45;<0.55) { File=gap_005.wav } Value=(>=0.55;<0.65) { File=gap_006.wav } Value=(>=0.65;<0.75) { File=gap_007.wav } Value=(>=0.75;<0.85) { File=gap_008.wav } Value=(>=0.85;<0.95) { File=gap_009.wav } Value=(>=0.95;<1.5) { File=gap_010.wav } // tell "less 1 second" Value=(>=1.5;<2.5) { File=gap_020.wav } Value=(>=2.5;<4.0) { File=gap_030.wav } Value=(>=4.0;<5.5) { File=gap_050.wav } Value=(>=5.5;<7.0) { File=gap_060.wav } Value=(>=7.0;<9.0) { File=gap_080.wav } Value=(>=9.0;<12.5) { File=gap_100.wav } Value=(>=12.5;<17.5) { File=gap_150.wav } Value=(>=17.5;<=25.0) { File=gap_200.wav } // tell "less 2 second" Value=(>=25.0;<=30.0) { File=gap_300.wav }// tell "less 3 second" } }

Voilà ! I think now, if your reach this point :), you understand the possibilities provided by the spotter.

Using vehicle class to override ini parameters
When the plugin take a value from the Spotter.ini, it start to take this parameter in a section who have the name of the VehicleClass (rF2 data provided by the plugin API) and if this parameter have not been overrided in the VehicleClass section (or if this section does not exists), it will read the parameter in the [DEFAULT] section.

So for example (as i don't know which value to put, i just put different value - not realistic values):

[DEFAULT] v:breakTooHot=600 v:breakTooCold=300 v:tireTooHot=105 v:tireTooCold=80 [SkipBarber_National] v:breakTooHot=900 v:breakTooCold=600 Rules.file=SkipBarber.ini Sounds.subPath=Sounds/FR maxDetailLevel=4

[Kart Junior] v:breakTooHot=400 v:breakTooCold=100 v:tireTooHot=135 v:tireTooCold=100

This example mean that if you enter the session with :


 * a Kart Junior : the optimal break range is between 100°C and 400°C and for tires is 100°C and 135°C


 * a SkipBarber_National : the optimal break range is between 600°C and 900°C and for tires is 80°C and 105°C (only tire temp come from [DEFAULT]) - in addition as you can override any parameter, i show you and example with not only user defined variable


 * any other car class : the optimal break range is between 300°C and 600°C and for tires is 80°C and 105°C (tire and break temp come from [DEFAULT])