// DRIVER RATINGS LOGICS //SETUPS // this class exists to get data from SPRINT RACE and calculate DRIVER RATINGS let RATING_DATA = SpreadsheetApp.getActive().getSheetByName("RATING_DATA") let IRC_DATA_SHEET = SpreadsheetApp.openById("1QaQUnQSiL_bKDY7zdCNp458fmDe8cS6N7taMem-b654") let DRIVER_DATA = IRC_DATA_SHEET.getSheetByName("DRIVER_DATA") // PROPERTIES // max xp limit to regular let XP_LIMIT_CUT = 100 // a max xp lvl to make even hard to earn points let SECOND_XP_CUT = 90 let FIRST_XP_CUT = 70 // this is the maximum value for the rating addition on lap times // driver can receive up to LAP_TIME_INITIAL_BONUS let RP_INITIAL_BONUS = 100 // race time target additional let RACE_LAP_TIME_TARGET_ADD = 1.5 // make an average from last season data (with top first & last drivers) // max random value for possibility point let POSSIBILITY_MAX_POINT = 3 //means max 2 -> review it to make a parameter? // TODO: APL - driver DNF by other driver incident // TODO: copy/use this for race result adding DNS [3.0,4.0] let RATINGS_PARAMS = { "experience": { "DNS": [2.5,3.5], "DNF": [1.0, 1.2], "DSQ": [1.0, 1.2], "APL": [0.0,0.0], "avg_DNF": [0.5,1.0], "in_game_warning_mult": [0.3, 0.4], "in_game_penalty_mult": [0.3, 0.6], "fia_warning_mult": [0.3, 1.0], "fia_penalty_mult": [0.3, 1.6], "performance_history": [0.5, 1.0], "result_div": [2.8,3.5], "fastest_lap": [1.0,2.0], "dotd": [1.5, 3.0], "avg_result": [1.0,2.4], "pos_mult": [0.2, 0.4], "consistency": [1.0,2.0], "time_lap": [2.0,2.5], "race_aditional": [2.0, 2.5], }, "race_craft": { "DNS": [2.5,3.5], "DNF": [1.0, 1.4], "DSQ": [1.0, 1.5], "APL": [0.0,0.0], "avg_DNF": [0.5,1.0], "in_game_warning_mult": [0.3, 0.4], "in_game_penalty_mult": [1.0, 1.6], "fia_warning_mult": [0.3, 1.0], "fia_penalty_mult": [0.3, 1.6], "performance_history": [0.5, 1.0], "result_div": [2.5,3.2], "fastest_lap": [2.0,2.5], "dotd": [2.0, 4.0], "avg_result": [1.0,2.0], "pos_mult": [0.35, 0.7], "consistency": [1.0,2.0], "time_lap": [3.0,3.5], "race_aditional": [2.2, 2.5] }, "awareness": { "DNS": [2.5,3.5], "DNF": [2.0, 2.5], "DSQ": [2.1, 3.0], "APL": [0.0,0.0], "avg_DNF": [0.5,1.0], "in_game_warning_mult": [0.3, 0.4], "in_game_penalty_mult": [1.3, 1.6], "fia_warning_mult": [0.3, 1.0], "fia_penalty_mult": [0.3, 1.6], "performance_history": [0.5, 1.0], "result_div": [2.0,3.0], "fastest_lap": [0.0,0.4], "dotd": [2.4, 4.2], "avg_result": [1.0,2.0], "pos_mult": [0.3, 0.5], "consistency": [1.0,2.0], "time_lap": [2.3,3.0], "race_aditional": [2.2, 2.5] }, "pace": { "DNS": [2.5,3.5], "DNF": [0.5, 1.0], "DSQ": [0.5, 1.2], "APL": [0.0,0.0], "avg_DNF": [0.5,1.0], "in_game_warning_mult": [0.3, 0.4], "in_game_penalty_mult": [0.3, 0.6], "fia_warning_mult": [0.3, 1.0], "fia_penalty_mult": [0.3, 1.6], "performance_history": [0.5, 1.0], "result_div": [2.5,3.2], "fastest_lap": [1.5, 2.2], "dotd": [1.5, 2.2], "avg_result": [1.0,2.0], "pos_mult": [0.45, 1.25], "consistency": [1.0,2.0], "time_lap": [2.5,3.4], "race_aditional": [1.0, 1.5] } } let LICENSES = { "s_license": { "emoji_id": "<:s_license:917610460562477066>", "img_url": "https://drive.google.com/uc?id=1wirknHWI37qYyX5nCa82buukmgsvrcg3", "min_sp": 18, "max_sp": 20 }, "a_license": { "emoji_id": "<:a_license:917610460285648927>", "img_url": "https://drive.google.com/uc?id=1n7xXoUMeijt_Cok9V2oRuoxv71MwJ-ut", "min_sp": 14, "max_sp": 17 }, "b_license": { "emoji_id": "<:b_license:917610460067545188>", "img_url": "https://drive.google.com/uc?id=10DJ15KS3kSWsppNCMpsjk-PbbXi_3JOt", "min_sp": 10, "max_sp": 13 }, "c_license": { "emoji_id": "<:c_license:917610459992043580>", "img_url": "https://drive.google.com/uc?id=1dKvBzOl7OdHA2volZEizGH-qJofqIooM", "min_sp": 7, "max_sp": 9 }, "d_license": { "emoji_id": "<:d_license:917610459975286844>", "img_url": "https://drive.google.com/uc?id=1oqBEw6jveh0HaA8KolzcRKbxhivXRHnQ", "min_sp": 4, "max_sp": 6 }, "n_license": { "emoji_id": "<:n_license:924330517233537074>", "img_url": "https://drive.google.com/uc?id=1PJGY74fNeodEzda5OiWEBEXL2dFFf6Ro", "min_sp": 0, "max_sp": 3 } } //------------------------------------------------------------------------------------------------------ function GET_RACE_RESULTS() { var minIndex = 3 let maxIndex = 22 var raceResults = [] // sort list by quali order SORT_BY_QUALI() // loop to get results while(minIndex <= maxIndex) { // race resut data let driverName = RATING_DATA.getRange(`C${minIndex}`).getValue() let rowRef = RATING_DATA.getRange(`D${minIndex}`).getValue() let qualiTime = parseFloat(RATING_DATA.getRange(`E${minIndex}`).getValue().toString().slice(2)) let raceTime = parseFloat(RATING_DATA.getRange(`F${minIndex}`).getValue().toString().slice(2)) let result = RATING_DATA.getRange(`G${minIndex}`).getValue() let inGameWarnings = RATING_DATA.getRange(`H${minIndex}`).getValue() let inGamePenalties = RATING_DATA.getRange(`I${minIndex}`).getValue() let fiaWarnings = RATING_DATA.getRange(`J${minIndex}`).getValue() let fiaPenalties = RATING_DATA.getRange(`K${minIndex}`).getValue() let backgroundDOTD = RATING_DATA.getRange(`C${minIndex}`).getFontColor() let backgroundFLP = RATING_DATA.getRange(`G${minIndex}`).getFontColor() let eventType = RATING_DATA.getRange("E24:F24").getValue().toString() let circuit = RATING_DATA.getRange("G24:H24").getValue().toString() let ratingDataRowRef = minIndex // check if reach last driver data if (driverName == "") { break } // pole let isPole = false if (minIndex == 3) { isPole = true } // is winner let isWinner = false if (parseInt(result) == 1) { isWinner = true } // is podium let isPodium = false if (minIndex <= 5) { isPodium = true } // driver data (rating) var driverXp = parseInt(DRIVER_DATA.getRange(`T${rowRef}`).getValue()) let driverRc = parseInt(DRIVER_DATA.getRange(`U${rowRef}`).getValue()) let driverAw = parseInt(DRIVER_DATA.getRange(`V${rowRef}`).getValue()) let driverPa = parseInt(DRIVER_DATA.getRange(`W${rowRef}`).getValue()) let driverAvg = parseInt(DRIVER_DATA.getRange(`X${rowRef}`).getValue()) let totalDNFs = parseInt(DRIVER_DATA.getRange(`R${rowRef}`).getValue()) // not counting this event result let numberOfSprintsRaced = parseInt(DRIVER_DATA.getRange(`L${rowRef}`).getValue()) let numberOfRacesRaced = parseInt(DRIVER_DATA.getRange(`M${rowRef}`).getValue()) let totalOfRacesRaced = numberOfRacesRaced + numberOfSprintsRaced + 1 // last results var lastResults = [] let lastResultsString = DRIVER_DATA.getRange(`S${rowRef}`).getValue().toString() lastResultsString = lastResultsString.replace("DNS", "25").replace("DNF", "22").replace("DSQ", "24").replace("APL", "") if (lastResultsString != "0") { lastResults = lastResultsString.split(",").map(Number).filter(number => number > 0) } if (!isNaN(result)) { lastResults.push(parseInt(result)) } // result avarage, variance, deviation (consistency) let avgRaceResult = CALCULATE_AVERAGE_RESULTS(lastResults) let variance = CALCULATE_DRIVER_RESULT_VARIANCE(lastResults) let deviation = CALCULATE_DRIVER_RESULT_DEVIATION(lastResults) // fastet lap & dotd let isFastestLap = (backgroundFLP == "#6842d5") let isDriverOfTheDay = (backgroundDOTD == "#10a499") console.log(isFastestLap) console.log(isDriverOfTheDay) // avg lap time target let qualiTargetFastesLap = parseFloat(RATING_DATA.getRange("I24:J24").getValue().toString().slice(2)) let qualiTargetSlowestLap = parseFloat(RATING_DATA.getRange("K24:L24").getValue().toString().slice(2)) // lap target values let raceAdditional = RACE_LAP_TIME_TARGET_ADD let avgTargetFastestLap = (qualiTargetFastesLap + (qualiTargetFastesLap + raceAdditional)) / 2 let avgTargetSlowestLap = (qualiTargetSlowestLap + qualiTargetSlowestLap + raceAdditional) / 2 let avgLapTime = (qualiTime + raceTime) / 2 // driver time target result let avgTargetRange = avgTargetSlowestLap - avgTargetFastestLap let driverDeltaTime = avgLapTime - avgTargetFastestLap let timeTargetResult = driverDeltaTime / avgTargetRange // performance history multiplier let titlesTotal = parseInt(DRIVER_DATA.getRange(`K${rowRef}`).getValue()) * 1.2 let polesTotal = parseInt(DRIVER_DATA.getRange(`N${rowRef}`).getValue()) * 1.15 let winsTotal = parseInt(DRIVER_DATA.getRange(`O${rowRef}`).getValue()) * 1.1 let podiumsTotal = parseInt(DRIVER_DATA.getRange(`P${rowRef}`).getValue()) * 1.08 let dotdTotal = parseInt(DRIVER_DATA.getRange(`Q${rowRef}`).getValue()) // keep same value let performanceAvg = (titlesTotal + polesTotal + winsTotal + podiumsTotal + dotdTotal) / 5 let performanceFactor = performanceAvg / totalOfRacesRaced // create max xp limit factor multiplier let xpLimitCutFactor = MAKE_XP_LIMIT_CUT_FACTOR(driverAvg) // safety points let safetyPoints = parseInt(DRIVER_DATA.getRange(`Z${minIndex}`).getValue()) let raceResult = { "driver_name": driverName, "row_ref": rowRef, "grid_start_pos": minIndex-2, "quali_time": qualiTime, "race_time": raceTime, "avg_lap_time": avgLapTime, "result": result, "dnfs_total": totalDNFs, "in_game_warnings": inGameWarnings, "in_game_penalties": inGamePenalties, "fia_warnings": fiaWarnings, "fia_penalties": fiaPenalties, "safety_points": safetyPoints, "last_results": lastResults, "avg_race_result": avgRaceResult, "is_fastest_lap": isFastestLap, "is_dotd": isDriverOfTheDay, "driver_xp": driverXp, "driver_rc": driverRc, "driver_aw": driverAw, "driver_pa": driverPa, "driver_avg": driverAvg, "eventType": eventType, "circuit": circuit, "avg_target_fastest_lap": avgTargetFastestLap, "avg_target_slowest_lap": avgTargetSlowestLap, "rating_data_row_ref": ratingDataRowRef, "time_target_result": timeTargetResult, "number_of_sprints_raced": numberOfSprintsRaced, "number_of_races_raced": numberOfRacesRaced, "total_of_races_raced": totalOfRacesRaced, "variance": variance, "deviation": deviation, "performance_factor": performanceFactor, "xp_limit_cut_factor": xpLimitCutFactor, "dotd_total": dotdTotal, "is_pole": isPole, "is_podium": isPodium, "is_winner": isWinner } raceResults.push(raceResult) minIndex ++ } return raceResults } //------------------------------------------------------------------------------------------------------ function CALCULATE_AVERAGE_RESULTS(lastResults) { let length = lastResults.length if (length == 0) { return 0 } let average = lastResults?.reduce((a,b) => a+b,0) / length return average } function CALCULATE_DRIVER_RESULT_VARIANCE(lastResults) { let length = lastResults.length if (length < 3) { return -1 } let avgResult = CALCULATE_AVERAGE_RESULTS(lastResults) let variance = lastResults.map(value => { let avgDelta = value - avgResult let squareValue = Math.pow(avgDelta, 2) return squareValue }).reduce((a,b) => a+b,0) / (length-1) / 100 return variance } function CALCULATE_DRIVER_RESULT_DEVIATION(lastResults) { let length = lastResults.length if (length < 3) { return -1 } let avgResult = CALCULATE_AVERAGE_RESULTS(lastResults) let deviation = Math.sqrt( lastResults .map(value => Math.pow(value - avgResult, 2)) .reduce((a,b) => a+b,0) / (length-1) ) / 20 return deviation } // UPDATE RATINGS //------------------------------------------------------------------------------------------------------ function UPDATE_DRIVER_RATING() { let raceResults = GET_RACE_RESULTS() raceResults.forEach(result => { // TODO: clead this console.log("######################################") console.log(result.driver_name) // experience let xpRatingFactor = RATINGS_PARAMS.experience var xpRatingValue = GET_EXPERIENCE_FOR(xpRatingFactor, result) var xpRating = parseInt(xpRatingValue + result.driver_xp) let xpValue = Math.min(Math.max(xpRating,50), 100) //DRIVER_DATA.getRange(`T${result.row_ref}`).setValue(xpValue) // race cra1ft let rcRatingFactor = RATINGS_PARAMS.race_craft let rcRating = parseInt(GET_RATING_FOR(rcRatingFactor, result) + result.driver_rc) let rcValue = Math.min(Math.max(rcRating,50), 100) //DRIVER_DATA.getRange(`U${result.row_ref}`).setValue(rcValue) // awareness let awRatingFactor = RATINGS_PARAMS.awareness let awRating = parseInt(GET_RATING_FOR(awRatingFactor, result) + result.driver_aw) let awValue = Math.min(Math.max(awRating,50), 100) //DRIVER_DATA.getRange(`V${result.row_ref}`).setValue(awValue) // pace let paRatingFactor = RATINGS_PARAMS.pace let paRating = parseInt(GET_RATING_FOR(paRatingFactor, result) + result.driver_pa) let paValue = Math.min(Math.max(paRating,50), 100) //DRIVER_DATA.getRange(`W${result.row_ref}`).setValue(paValue) // average let avgValue = Math.ceil((xpValue + rcValue + awValue + paValue) / 4) //DRIVER_DATA.getRange(`X${result.row_ref}`).setValue(avgValue) RATING_DATA.getRange(`N${result.rating_data_row_ref}`).setValue(avgValue) //number of races & sprints if (result.eventType == "SPRINT") { let numberOfSprintsRaced = result.number_of_sprints_raced + 1 //DRIVER_DATA.getRange(`L${result.row_ref}`).setValue(numberOfSprintsRaced) } if (result.eventType == "RACE") { let numberOfRacesRaced = result.number_of_races_raced + 1 //DRIVER_DATA.getRange(`M${result.row_ref}`).setValue(numberOfRacesRaced) } let ratings = `${xpValue}, ${rcValue}, ${awValue}, ${paValue}` RATING_DATA.getRange(`M${result.rating_data_row_ref}`).setValue(ratings) RATING_DATA.getRange(`N26`).setValue(result.total_of_races_raced) // TODO: right those values on DRIVER DATA // POLES WINS PODIUMS DOTD's DNF's LAST 5 RESULTS if (result.is_pole) { let polesTotal = parseInt(DRIVER_DATA.getRange(`N${result.row_ref}`).getValue()) + 1 //DRIVER_DATA.getRange(`N${result.row_ref}`).setValue(polesTotal) } if (result.is_winner) { let winsTotal = parseInt(DRIVER_DATA.getRange(`O${result.row_ref}`).getValue()) + 1 //DRIVER_DATA.getRange(`O${result.row_ref}`).setValue(winsTotal) } if (result.is_podium) { let podiumsTotal = parseInt(DRIVER_DATA.getRange(`P${result.row_ref}`).getValue()) + 1 //DRIVER_DATA.getRange(`P${result.row_ref}`).setValue(podiumsTotal) } // update driver of the day if (result.is_dotd) { let dotdTotal = result.dotd_total + 1 //DRIVER_DATA.getRange(`Q${result.row_ref}`).setValue(dotdTotal) } // update dnf if (result.result == "DNF") { let dnfsTotal = parseInt(DRIVER_DATA.getRange(`R${result.row_ref}`).getValue()) //DRIVER_DATA.getRange(`R${result.row_ref}`).setValue(dnfsTotal+1) } // last results var resultList = [] var driverLastResults = DRIVER_DATA.getRange(`S${result.row_ref}`).getValue().toString() if (driverLastResults != "0") { resultList = driverLastResults.split(",") } resultList.push(result.result) // drop first index (older result) if (resultList.length > 5) { resultList.shift() } driverLastResults = resultList.toString() //DRIVER_DATA.getRange(`S${result.row_ref}`).setValue(driverLastResults) // TODO: review the logic & move it to own method + calculate all points on GET_DRIVER_DATA and here only update on DRIVER_DATA sheet // license points let hasFiaIssuedAPenaltyOrWarning = ((result.fia_penalties <=0) && (result.fia_warnings <= 0)) let hasFinishedOrAppealed = (!(isNaN(result.result)) || (result.result == "APL")) if (hasFinishedOrAppealed && hasFiaIssuedAPenaltyOrWarning) { var licensePoints = result.safety_points if (result.safety_points < 20) { licensePoints += 1 } //DRIVER_DATA.getRange(`Y${result.row_ref}`).setValue(licensePoints) RATING_DATA.getRange(`L${result.rating_data_row_ref}`).setValue(licensePoints) } else { let licensePoints = result.safety_points - result.fia_penalties //DRIVER_DATA.getRange(`Y${result.row_ref}`).setValue(licensePoints) RATING_DATA.getRange(`L${result.rating_data_row_ref}`).setValue(licensePoints) } let totalLicensePoints = parseInt(RATING_DATA.getRange(`L${result.rating_data_row_ref}`).getValue()) let licenseImgUrl = GET_LICENSE_IMG_FORMULA_BY(totalLicensePoints) let licenseImgFormula = `=IMAGE(\"${licenseImgUrl}\";4;30;30)` //DRIVER_DATA.getRange(`AA${result.row_ref}`).setFormula(licenseImgFormula) }) // sort SORT_TABLE() } //------------------------------------------------------------------------------------------------------ // LICENSE HELPER function GET_LICENSE_IMG_FORMULA_BY(licensePoints) { if (licensePoints >= LICENSES.s_license.min_sp) { return LICENSES.s_license.img_url } else if (licensePoints >= LICENSES.a_license.min_sp) { return LICENSES.a_license.img_url } else if (licensePoints >= LICENSES.b_license.min_sp) { return LICENSES.b_license.img_url } else if (licensePoints >= LICENSES.c_license.min_sp) { return LICENSES.c_license.img_url } else if (licensePoints >= LICENSES.d_license.min_sp) { return LICENSES.d_license.img_url } else if (licensePoints >= LICENSES.n_license.min_sp) { return LICENSES.n_license.img_url } } // RATING METHODS // calculate value for experience function GET_EXPERIENCE_FOR(xpRatingFactor, result) { var xpRatingValue = GET_RATING_FOR(xpRatingFactor, result) return xpRatingValue // TODO: Move it to GET_RATING_FOR method and leave here only logic regarding XP (USE DNF's to calculate) // CHANGE IT TO BE FACTOR WITH MAX XP LVL ( DIVIDE BY 100 & GET PERCENTAGE ) // xp gets harder to earn regarding lvl and if (result.driver_xp > RP_INITIAL_BONUS) { // every 3 races may update xp if (result.total_of_races_raced % 3 == 0) { // max xp limit to calculations, now is up to possibility if (result.driver_xp >= MAX_XP_LIMIT) { return POSSIBILITY_POINT() } // limit to 3 if (xpRatingValue > 3) { xpRatingValue = 3 } // add possibility xpRatingValue += POSSIBILITY_POINT() } } // limit point removal to 5 if (xpRatingValue < -5) { xpRatingValue = -5 } return xpRatingValue } // small chance to return up to 2 points function POSSIBILITY_POINT() { let possibility = Math.random() let rating = Math.floor(Math.random() * POSSIBILITY_MAX_POINT) return possibility > 0.89 ? rating : 0 } // CALCULATIONS // timeTargetResult deviation variance total_of_dnfs (get avg of DNFs) lap_time_factor + review /* "DNS": [2.5,3.5], ok "DNF": [1.0, 1.2], ok "DSQ": [1.0, 1.2], ok "APL": [0.0,0.0], ok "avg_DNF": [0.5,1.0], "in_game_warning_mult": [0.3, 0.4],ok "in_game_penalty_mult": [0.3, 0.6],ok "fia_warning_mult": [0.3, 0.4],ok "fia_penalty_mult": [0.3, 0.6],ok "result_div": [3.0,4.8], ok "fastest_lap": [1.0,2.0], ok "dotd": [1.0, 2.5], ok "avg_result": [1.0,2.0] ok "pos_mult": [0.2, 0.4], ok "consistency": [1.0,2.0], ok "time_lap": [5.0,7.0] ok "race_aditional": [2.0, 2.5], ok */ //------------------------------------------------------------------------------------------------------ function GET_RATING_FOR(ratingFactor, raceResult) { var performancePoints = 0 // REMOVEs // dns if (raceResult.result == "DNS") { performancePoints -= RANDOM_VALUES(ratingFactor.DNS) } // dnf if (raceResult.result == "DNF") { performancePoints -= RANDOM_VALUES(ratingFactor.DNF) console.log("DNF") console.log(performancePoints) } // dsq if (raceResult.result == "DSQ") { performancePoints -= RANDOM_VALUES(ratingFactor.DSQ) } // avg dnf's - removes a small factor regarding driver avg dnf's in relation with total races // change avgDNF to DNF_DEBIT and add 5 debit // move this to DRIVER DATA initializer // driver dnf's avg debit - calculate remotion based on DNFs if (raceResult.dnfs_total > 0) { // more avg rating means higher dnf debit var avgDnfFactor = RANDOM_VALUES(ratingFactor.avg_DNF) * (raceResult.driver_avg/100) console.log("raceResult.dnfs_total") console.log(raceResult.dnfs_total) console.log("raceResult.totalOfRacesRaced") console.log(raceResult.total_of_races_raced) console.log("avgDnfFactor") console.log(avgDnfFactor) // move this to the drive data calculations performancePoints -= avgDnfFactor * (raceResult.dnfs_total / raceResult.total_of_races_raced) console.log("avgDnfFactor") console.log(performancePoints) } // TODO: get number of driver DNFs and calculate % with total number of races (make new factor) // incidents in game let inGameIncidentMult = RANDOM_VALUES(ratingFactor.in_game_warning_mult) performancePoints -= inGameIncidentMult * raceResult.in_game_warnings console.log("inGameIncidentMult") console.log(performancePoints) let inGamePenaltyMult = RANDOM_VALUES(ratingFactor.in_game_penalty_mult) performancePoints -= inGamePenaltyMult * raceResult.in_game_penalties console.log("inGamePenaltyMult") console.log(performancePoints) // incidents FIA let fiaIncidentMult = RANDOM_VALUES(ratingFactor.fia_warning_mult) performancePoints -= fiaIncidentMult * raceResult.fia_warnings console.log("fiaIncidentMult") console.log(performancePoints) let fiaPenaltyMult = RANDOM_VALUES(ratingFactor.fia_penalty_mult) performancePoints -= fiaPenaltyMult * raceResult.fia_penalties console.log("fiaPenaltyMult") console.log(performancePoints) // ADDs let performanceMult = RANDOM_VALUES(ratingFactor.performance_history) performancePoints += raceResult.performance_factor * performanceMult // consistency (variance & deviation) // only if the value is equal or higher than 0 (means more than 2 races at least) if (raceResult.variance >= 0 && raceResult.deviation >= 0) { let consistencyMultiplier = (raceResult.variance + raceResult.deviation) / 2 if (consistencyMultiplier >= 0) { let consistencyFactor = RANDOM_VALUES(ratingFactor.consistency) performancePoints += consistencyFactor - ( consistencyFactor * consistencyMultiplier) console.log("consistencyFactor") console.log(performancePoints) } } // quali time result additional let timelapFactor = RANDOM_VALUES(ratingFactor.time_lap) performancePoints += timelapFactor - (timelapFactor * raceResult.time_target_result).toFixed(2) console.log("timelapFactor") console.log(performancePoints) // race aditional performancePoints += RANDOM_VALUES(ratingFactor.race_aditional) console.log("race aditional") console.log(performancePoints) // fastest lap if(raceResult.is_fastest_lap) { performancePoints += RANDOM_VALUES(ratingFactor.fastest_lap) console.log("FASTEST LAP") console.log(performancePoints) } // driver of the day if (raceResult.is_dotd) { performancePoints += RANDOM_VALUES(ratingFactor.dotd) console.log("DOTD") console.log(performancePoints) } // TODO: review & test this if (isNaN(raceResult.result)) { console.log("result isNaN") console.log("raceResult.xp_limit_cut_factor") console.log(raceResult.xp_limit_cut_factor) console.log("performancePoints") console.log(Math.floor(performancePoints * raceResult.xp_limit_cut_factor)) return Math.floor(performancePoints * raceResult.xp_limit_cut_factor) } // result -> pace CONSIDER REVIEW THIS let resultFactor = RANDOM_VALUES(ratingFactor.result_div) performancePoints += resultFactor / raceResult.result console.log("resultFactor") console.log(performancePoints) // TODO: Add factor in % // avg result (delta) -> pace & race craft let avgResMult = RANDOM_VALUES(ratingFactor.avg_result) console.log("avg_race_result") console.log(raceResult.avg_race_result) console.log("raceResult.result") console.log(raceResult.result) var avgDeltaPos = raceResult.avg_race_result - raceResult.result console.log("avgDeltaPos") console.log(avgDeltaPos) avgDeltaPos = avgDeltaPos == 0 ? 1 : avgDeltaPos performancePoints += avgResMult * (avgDeltaPos/20) console.log("avgResMult") console.log(avgResMult * (avgDeltaPos/20)) console.log(performancePoints) // result (delta) -> race craft // start & final position multiplier let posMult = RANDOM_VALUES(ratingFactor.pos_mult) var deltaPos = raceResult.grid_start_pos - raceResult.result deltaPos = deltaPos == 0 ? 1 : deltaPos performancePoints += posMult * deltaPos console.log("posMult") console.log(performancePoints) //review this -> make this logic that cutting one on XP method let performancePointsTotal = performancePoints * raceResult.xp_limit_cut_factor console.log("raceResult.xp_limit_cut_factor") console.log(raceResult.xp_limit_cut_factor) console.log("### FINAL performancePointsTotal") console.log(performancePointsTotal) if (raceResult.driver_avg >= FIRST_XP_CUT) { return Math.floor(performancePointsTotal) } return Math.ceil(performancePointsTotal) } function MAKE_XP_LIMIT_CUT_FACTOR(driverAvg) { // if a driver has reach avg xp limit // return less % for new points if (driverAvg > SECOND_XP_CUT) { return (XP_LIMIT_CUT - driverAvg) / 110 } if (driverAvg > FIRST_XP_CUT) { return (XP_LIMIT_CUT - driverAvg) / 100 } let bonusFactor = RP_INITIAL_BONUS + XP_LIMIT_CUT console.log("NORMAL CUT") console.log((bonusFactor - driverAvg) / 100) return (bonusFactor - driverAvg) / 100 } // set quali factor regarding driver avg rating // this can return high rating values for drivers with target closest time // NOT TO BE USED ANYMORE function GET_LAP_TIME_FACTOR_BY(driverAvg) { // if a driver has reach avg xp limit for the higher lap time factor return a possibility points if (driverAvg > MAX_LAP_TIME_XP_BONUS) { return POSSIBILITY_POINT() } // first cut returns up to the lap factor limit let firstCut = MAX_LAP_TIME_XP_BONUS - 15 var lapFactorLimit = LAP_TIME_INITIAL_BONUS let minimumAvgRating = 50 if (driverAvg <= firstCut) { let lapTimeFactor = lapFactorLimit - (driverAvg - minimumAvgRating) return Math.min(Math.max(lapTimeFactor, 2), lapFactorLimit) } // second cut retuns lower factor // driver avg is between limit and first cut // note: there's a gap between lap factor and avg rating between cuts (minimumAvgRating values) lapFactorLimit -= 10 minimumAvgRating += 15 let lapTimeFactor = (lapFactorLimit - (driverAvg - minimumAvgRating)) return Math.max(lapTimeFactor, lapFactorLimit) } // TODO review shorting // sort by rating function SORT_TABLE() { var range = RATING_DATA.getRange("B3:N22") range.sort([{column: 14, ascending: false}]) } function SORT_BY_QUALI() { var range = RATING_DATA.getRange("B3:N22") range.sort([{column: 5, ascending: true}]) } function RANDOM_VALUES(factorValues) { // randomized between factor range let min = factorValues[0] let max = factorValues[1] let value = parseFloat((Math.random() * (max - min) + min).toFixed(2)) return value } //------------------------------------------------------------------------------------------------------