From cdd00dc2b789ea8cfe6a87b15de87208ad1e0f6f Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 5 May 2023 22:01:51 +0200 Subject: [PATCH 01/71] Rework get functions into getFromToneAPI #8 --- mod.json | 4 +- mod/scripts/vscripts/pulse.gnut | 71 +++---------------- mod/scripts/vscripts/ui/menu_stats_maps.nut | 8 +-- .../vscripts/ui/menu_stats_overview.nut | 28 ++++---- mod/scripts/vscripts/ui/menu_stats_time.nut | 2 +- mod/scripts/vscripts/ui/menu_stats_titans.nut | 2 +- .../vscripts/ui/menu_stats_utility.nut | 10 +-- .../vscripts/ui/menu_stats_weapons.nut | 6 +- 8 files changed, 40 insertions(+), 91 deletions(-) diff --git a/mod.json b/mod.json index 6113565..a3c0074 100644 --- a/mod.json +++ b/mod.json @@ -1,7 +1,7 @@ { "Name": "ToneAPI.pulse", "Description": "Displays Tone API kill data in the Stats tab.", - "Version": "1.2.1", + "Version": "1.2.2", "LoadPriority": 1, "ConVars": [ { @@ -22,7 +22,7 @@ }, { "Name": "PatchVersion", - "DefaultValue": "1" + "DefaultValue": "2" } ], "Scripts": [ diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index c0cc1bf..c6f185d 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -3,13 +3,7 @@ global function GetWeaponStatsFromToneAPI global function GetGlobalDataFromToneAPI global function GetMapStatsFromToneAPI global function GetGamemodeStatsFromToneAPI -global function getWeaponKillsFromToneAPI -global function getNemesisWeaponFromToneAPI -global function getDWEFromToneAPI -global function getMapKillFromToneAPI -global function getMapDeathFromToneAPI -global function getMapDistFromToneAPI -global function getMapMDistFromToneAPI +global function getFromToneAPI global function fetchGamemodeStatsFromToneAPI global table globalToneAPIKillData = {} @@ -32,6 +26,10 @@ int mapEntries = 0 int gamemodeEntries = 0 int mapGamemodeEntries = 0 +struct { + array allMaps +} file + void function pulseInit() { prefix = "\x1b[38;2;255;178;102m[PULSE]\x1b[0m " @@ -206,62 +204,13 @@ void function fetchGamemodeStatsFromToneAPI(string mapName) NSHttpRequest(getMapGamemodeStats, onSuccess, onFailure) } -int function getWeaponKillsFromToneAPI(string weaponRef){ +int function getFromToneAPI(string parameter, table data){ - if(weaponRef in globalToneAPIKillData){ - return expect int(globalToneAPIKillData[weaponRef]) + if (file.allMaps.find(parameter) != -1) { + parameter = parameter.slice(3) } - return 0 -} - -int function getNemesisWeaponFromToneAPI(string weaponRef){ - - if(weaponRef in globalToneAPIDeathData){ - return expect int(globalToneAPIDeathData[weaponRef]) - } - return 0 -} - -int function getDWEFromToneAPI(string weaponRef){ - - if(weaponRef in globalToneAPIDWEData){ - return expect int(globalToneAPIDWEData[weaponRef]) - } - return 0 -} - -int function getMapKillFromToneAPI(string mapName){ - - mapName = mapName.slice(3) - if(mapName in globalToneAPIMapKillData){ - return expect int(globalToneAPIMapKillData[mapName]) - } - return 0 -} - -int function getMapDeathFromToneAPI(string mapName){ - - mapName = mapName.slice(3) - if(mapName in globalToneAPIMapDeathData){ - return expect int(globalToneAPIMapDeathData[mapName]) - } - return 0 -} - -int function getMapMDistFromToneAPI(string mapName){ - - mapName = mapName.slice(3) - if(mapName in globalToneAPIMapMDistData){ - return expect int(globalToneAPIMapMDistData[mapName]) - } - return 0 -} - -int function getMapDistFromToneAPI(string mapName){ - - mapName = mapName.slice(3) - if(mapName in globalToneAPIMapDistData){ - return expect int(globalToneAPIMapDistData[mapName]) + if (parameter in data) { + return expect int(data[parameter]) } return 0 } diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mod/scripts/vscripts/ui/menu_stats_maps.nut index e86f05c..388897a 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -155,16 +155,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue0", getMapKillFromToneAPI(mapName) ) + SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(mapName, globalToneAPIMapKillData) ) SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue1", getMapDeathFromToneAPI(mapName) ) + SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(mapName, globalToneAPIMapDeathData) ) SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(getMapDistFromToneAPI(mapName) ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(getFromToneAPI(mapName, globalToneAPIMapDistData) ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(getMapMDistFromToneAPI(mapName) ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(getFromToneAPI(mapName, globalToneAPIMapMDistData) ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) SetStatsLabelValue( file.menu, "KillsValue4", "--" ) diff --git a/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mod/scripts/vscripts/ui/menu_stats_overview.nut index a2a74c6..3b4197c 100644 --- a/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -50,7 +50,7 @@ void function GetTitanKills( string titanName ) foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - titanKillData[weaponRef] <- getWeaponKillsFromToneAPI(weaponRef) + titanKillData[weaponRef] <- getFromToneAPI(weaponRef, globalToneAPIKillData) } } @@ -316,7 +316,7 @@ function UpdateViewStatsOverviewMenu() if (key in titanKillData) { continue } else { - killsAsPilot += getWeaponKillsFromToneAPI(string(key)) + killsAsPilot += getFromToneAPI(string(key), globalToneAPIKillData) } } @@ -391,27 +391,27 @@ function UpdateViewStatsOverviewMenu() Hud_SetText( GetElem( file.menu, "KillsAsPilotValue0" ), string( killsAsPilot ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsPilot" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue2" ), string( GetPlayerStatInt( player, "kills_stats", "totalNPC" ) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( getWeaponKillsFromToneAPI("pilot_emptyhanded") ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( getWeaponKillsFromToneAPI("human_execution") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( getFromToneAPI("pilot_emptyhanded", globalToneAPIKillData) ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( getFromToneAPI("human_execution", globalToneAPIKillData) ) ) // Hud_SetText( GetElem( file.menu, "KillsAsPilotValue5" ), string( GetPlayerStatInt( player, "kills_stats", "titanFallKill" ) ) ) var titanMeleeKills = 0 - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_ion") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_scorch") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_northstar") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_sword") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_tone") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_legion") - titanMeleeKills += getWeaponKillsFromToneAPI("titan_punch_vanguard") - titanMeleeKills += getWeaponKillsFromToneAPI("auto_titan_melee") + titanMeleeKills += getFromToneAPI("titan_punch_ion", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_scorch", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_northstar", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_sword", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_tone", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_legion", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_vanguard", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("auto_titan_melee", globalToneAPIKillData) - var titanExecutions = getWeaponKillsFromToneAPI("titan_execution") + var titanExecutions = getFromToneAPI("titan_execution", globalToneAPIKillData) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue0" ), string( killsAsTitan ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsTitan" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue2" ), string( titanExecutions ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue3" ), string( titanMeleeKills ) ) - Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( getWeaponKillsFromToneAPI("damagedef_titan_step") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( getFromToneAPI("damagedef_titan_step", globalToneAPIKillData) ) ) } function PlotKDPointsOnGraph( menu, graphIndex, values, dottedAverage ) diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mod/scripts/vscripts/ui/menu_stats_time.nut index a12aefa..f517eaa 100644 --- a/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -49,7 +49,7 @@ float function GetTitanKills( string titanName) float weaponKills = 0 foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - weaponKills += float(getWeaponKillsFromToneAPI(weaponRef)) + weaponKills += float(getFromToneAPI(weaponRef, globalToneAPIKillData)) } return weaponKills } diff --git a/mod/scripts/vscripts/ui/menu_stats_titans.nut b/mod/scripts/vscripts/ui/menu_stats_titans.nut index 33fd156..b7912a3 100644 --- a/mod/scripts/vscripts/ui/menu_stats_titans.nut +++ b/mod/scripts/vscripts/ui/menu_stats_titans.nut @@ -175,7 +175,7 @@ void function UpdateStatsForTitan( string titanRef, int loadoutIndex ) int aiKills foreach ( weaponRef in file.titanStatLoadout[ titanRef ] ) { - totalKills += getWeaponKillsFromToneAPI(weaponRef) + totalKills += getFromToneAPI(weaponRef, globalToneAPIKillData) pilotKills += GetPlayerStatInt( player, "weapon_kill_stats", "pilots", weaponRef ) titanKills += GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) aiKills += GetPlayerStatInt( player, "weapon_kill_stats", "ai", weaponRef ) diff --git a/mod/scripts/vscripts/ui/menu_stats_utility.nut b/mod/scripts/vscripts/ui/menu_stats_utility.nut index 31b271c..6eddad7 100644 --- a/mod/scripts/vscripts/ui/menu_stats_utility.nut +++ b/mod/scripts/vscripts/ui/menu_stats_utility.nut @@ -338,7 +338,7 @@ table function GetOverviewWeaponData() if ( !PersistenceEnumValueIsValid( "loadoutWeaponsAndAbilities", weaponName ) ) continue - int val = getWeaponKillsFromToneAPI(weaponName) + int val = getFromToneAPI(weaponName, globalToneAPIKillData) if ( val > Table[ "most_kills" ].val ) { Table[ "most_kills" ].ref = weaponName @@ -346,7 +346,7 @@ table function GetOverviewWeaponData() Table[ "most_kills" ].val = val } - int nval = getNemesisWeaponFromToneAPI(weaponName) + int nval = getFromToneAPI(weaponName, globalToneAPIDeathData) if ( nval > Table[ "nemesis_weapon" ].val ) { Table[ "nemesis_weapon" ].ref = weaponName @@ -357,9 +357,9 @@ table function GetOverviewWeaponData() float kdval = 0 float kval = 0 float dval = 0 - if( getWeaponKillsFromToneAPI(weaponName) != 0 && getDWEFromToneAPI(weaponName) != 0){ - kval = float(getWeaponKillsFromToneAPI(weaponName)) - dval = float(getDWEFromToneAPI(weaponName)) + if( getFromToneAPI(weaponName, globalToneAPIKillData) != 0 && getFromToneAPI(weaponName, globalToneAPIDWEData) != 0){ + kval = float(getFromToneAPI(weaponName, globalToneAPIKillData)) + dval = float(getFromToneAPI(weaponName, globalToneAPIDWEData)) if (kval / dval > kdval){ kdval = kval / dval } diff --git a/mod/scripts/vscripts/ui/menu_stats_weapons.nut b/mod/scripts/vscripts/ui/menu_stats_weapons.nut index 114f202..c37c533 100644 --- a/mod/scripts/vscripts/ui/menu_stats_weapons.nut +++ b/mod/scripts/vscripts/ui/menu_stats_weapons.nut @@ -180,8 +180,8 @@ void function UpdateStatsForWeapon( string weaponRef ) } // Total Kills Stats - SetStatsLabelValue( file.menu, "KillsValue0", getWeaponKillsFromToneAPI(weaponRef) ) - SetStatsLabelValue( file.menu, "KillsValue1", getWeaponKillsFromToneAPI(weaponRef) ) + SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(weaponRef, globalToneAPIKillData) ) + SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(weaponRef, globalToneAPIKillData) ) SetStatsLabelValue( file.menu, "KillsValue2", GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) ) - SetStatsLabelValue( file.menu, "KillsValue3", getDWEFromToneAPI(weaponRef)) + SetStatsLabelValue( file.menu, "KillsValue3", getFromToneAPI(weaponRef, globalToneAPIDWEData)) } From aedfc9afc096f68bc7bdfa25d7066b8b43905806 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 5 May 2023 23:19:28 +0200 Subject: [PATCH 02/71] Rework request functions into GetStatsFromToneAPI #8 --- mod/scripts/vscripts/pulse.gnut | 154 +++++++------------------ mod/scripts/vscripts/ui/menu_stats.nut | 5 +- 2 files changed, 40 insertions(+), 119 deletions(-) diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index c6f185d..ede0e53 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -1,8 +1,5 @@ global function pulseInit -global function GetWeaponStatsFromToneAPI -global function GetGlobalDataFromToneAPI -global function GetMapStatsFromToneAPI -global function GetGamemodeStatsFromToneAPI +global function GetStatsFromToneAPI global function getFromToneAPI global function fetchGamemodeStatsFromToneAPI @@ -17,6 +14,8 @@ global table globalToneAPIGamemodeData = {} global table globalToneAPIAllPlayerKillData = {} global table globalToneAPIAllPlayerDeathData = {} global table< table > globalToneAPIGamemodeMapData = {} +array allHttpRequests = ["/weapons", "/weapons", "/maps", "/gamemodes"] +array isGlobal = [0, 1, 0, 0] string prefix = "default" string HTTPrequestURL = "default" @@ -54,122 +53,47 @@ void function pulseInit() NSHttpRequest(getVersion, onSuccess, onFailure) } -void function GetWeaponStatsFromToneAPI() +void function GetStatsFromToneAPI() { - print(prefix + "Getting kill data...") - weaponEntries = 0 - HttpRequest getWeaponStats - getWeaponStats.method = HttpRequestMethod.GET - getWeaponStats.url = HTTPrequestURL + "/weapons" - getWeaponStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - print(prefix + "Kill data received, processing...") - table JSONForConversion = DecodeJSON(response.body) - foreach (var key, var value in JSONForConversion) { - table test = expect table(value) - globalToneAPIKillData[string(key)] <- test.kills - globalToneAPIDeathData[string(key)] <- test.deaths - globalToneAPIDWEData[string(key)] <- test.deaths_while_equipped - weaponEntries += 1 + for (int i; i < allHttpRequests.len(); i++) { + HttpRequest getStats + getStats.method = HttpRequestMethod.GET + getStats.url = HTTPrequestURL + allHttpRequests[i] + if (isGlobal[i] == 1) { + getStats.queryParameters["player"] <- ["!" + NSGetLocalPlayerUID()] + } else { + getStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] } - print(prefix + "Kill data has been processed with a total of " + string(weaponEntries) + " entries.") - } - - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + "Encountered an error getting kill data...") - } - - NSHttpRequest(getWeaponStats, onSuccess, onFailure) -} - -void function GetGlobalDataFromToneAPI() -{ - print(prefix + "Getting global data...") - weaponEntries = 0 - HttpRequest getGlobalStats - getGlobalStats.method = HttpRequestMethod.GET - getGlobalStats.url = HTTPrequestURL + "/weapons" - getGlobalStats.queryParameters["player"] <- ["!" + NSGetLocalPlayerUID()] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - print(prefix + "Global data received, processing...") - table JSONForConversion = DecodeJSON(response.body) - foreach (var key, var value in JSONForConversion) { - table test = expect table(value) - globalToneAPIAllPlayerKillData[string(key)] <- test.kills - globalToneAPIAllPlayerDeathData[string(key)] <- test.deaths - weaponEntries += 1 + void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i) + { + table DecodedJSON = DecodeJSON(response.body) + foreach (var key, var value in DecodedJSON) { + table test = expect table(value) + switch (i) { + case 0: + globalToneAPIKillData[string(key)] <- test.kills + globalToneAPIDeathData[string(key)] <- test.deaths + globalToneAPIDWEData[string(key)] <- test.deaths_while_equipped + case 1: + globalToneAPIAllPlayerKillData[string(key)] <- test.kills + globalToneAPIAllPlayerDeathData[string(key)] <- test.deaths + case 2: + globalToneAPIMapKillData[string(key)] <- test.kills + globalToneAPIMapDeathData[string(key)] <- test.deaths + globalToneAPIMapDistData[string(key)] <- test.total_distance + globalToneAPIMapMDistData[string(key)] <- test.max_distance + case 3: + globalToneAPIGamemodeData[string(key)] <- test.kills + } + } + print(prefix + "has succeeded in getting stats for " + allHttpRequests[i].slice(1)) } - print(prefix + "Global data has been processed with a total of " + string(weaponEntries) + " entries.") - } - - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + "Encountered an error getting global data...") - } - - NSHttpRequest(getGlobalStats, onSuccess, onFailure) -} - -void function GetMapStatsFromToneAPI() -{ - print(prefix + "Getting map data...") - mapEntries = 0 - HttpRequest getMapStats - getMapStats.method = HttpRequestMethod.GET - getMapStats.url = HTTPrequestURL + "/maps" - getMapStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - print(prefix + "Map data received, processing...") - table JSONForConversion = DecodeJSON(response.body) - foreach (var key, var value in JSONForConversion) { - table test = expect table(value) - globalToneAPIMapKillData[string(key)] <- test.kills - globalToneAPIMapDeathData[string(key)] <- test.deaths - globalToneAPIMapDistData[string(key)] <- test.total_distance - globalToneAPIMapMDistData[string(key)] <- test.max_distance - mapEntries += 1 + void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (i) + { + print(prefix + "has encountered an error getting stats for " + allHttpRequests[i].slice(1)) } - print(prefix + "Map data has been processed with a total of " + string(mapEntries) + " entries.") + NSHttpRequest(getStats, onSuccess, onFailure) } - - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + "Encountered an error getting map data...") - } - - NSHttpRequest(getMapStats, onSuccess, onFailure) -} - -void function GetGamemodeStatsFromToneAPI() -{ - print(prefix + "Getting gamemode data...") - gamemodeEntries = 0 - HttpRequest getGamemodeStats - getGamemodeStats.method = HttpRequestMethod.GET - getGamemodeStats.url = HTTPrequestURL + "/gamemodes" - getGamemodeStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - print(prefix + "Gamemode data received, processing...") - table JSONForConversion = DecodeJSON(response.body) - foreach (var key, var value in JSONForConversion) { - table test = expect table(value) - globalToneAPIGamemodeData[string(key)] <- test.kills - gamemodeEntries += 1 - } - print(prefix + "Gamemode data has been processed with a total of " + string(gamemodeEntries) + " entries.") - } - - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + "Encountered an error getting gamemode data...") - } - - NSHttpRequest(getGamemodeStats, onSuccess, onFailure) } void function fetchGamemodeStatsFromToneAPI(string mapName) diff --git a/mod/scripts/vscripts/ui/menu_stats.nut b/mod/scripts/vscripts/ui/menu_stats.nut index 65bef5e..2cae746 100644 --- a/mod/scripts/vscripts/ui/menu_stats.nut +++ b/mod/scripts/vscripts/ui/menu_stats.nut @@ -45,10 +45,7 @@ void function OnViewStats_Open() string mapName = expect string(file.allMaps[ elemNum ]) fetchGamemodeStatsFromToneAPI(mapName) } - GetWeaponStatsFromToneAPI() - GetGlobalDataFromToneAPI() - GetMapStatsFromToneAPI() - GetGamemodeStatsFromToneAPI() + GetStatsFromToneAPI() UI_SetPresentationType( ePresentationType.DEFAULT ) //UpdateViewStatsKillsMenu() From 2466febd4e7f1d8119f0afbe7ad49da0c3701959 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sat, 6 May 2023 14:10:47 +0200 Subject: [PATCH 03/71] Refactoring #8 --- mod/scripts/vscripts/pulse.gnut | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index ede0e53..666beda 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -14,15 +14,10 @@ global table globalToneAPIGamemodeData = {} global table globalToneAPIAllPlayerKillData = {} global table globalToneAPIAllPlayerDeathData = {} global table< table > globalToneAPIGamemodeMapData = {} -array allHttpRequests = ["/weapons", "/weapons", "/maps", "/gamemodes"] -array isGlobal = [0, 1, 0, 0] string prefix = "default" string HTTPrequestURL = "default" string currentVersion = "default" -int weaponEntries = 0 -int mapEntries = 0 -int gamemodeEntries = 0 int mapGamemodeEntries = 0 struct { @@ -55,16 +50,15 @@ void function pulseInit() void function GetStatsFromToneAPI() { + string UID = NSGetLocalPlayerUID() + array allHttpRequests = ["/weapons", "/weapons", "/maps", "/gamemodes"] + array allHttpParameters = [UID, "!" + UID, UID, UID] for (int i; i < allHttpRequests.len(); i++) { HttpRequest getStats getStats.method = HttpRequestMethod.GET getStats.url = HTTPrequestURL + allHttpRequests[i] - if (isGlobal[i] == 1) { - getStats.queryParameters["player"] <- ["!" + NSGetLocalPlayerUID()] - } else { - getStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] - } - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i) + getStats.queryParameters["player"] <- [allHttpParameters[i]] + void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i, allHttpRequests) { table DecodedJSON = DecodeJSON(response.body) foreach (var key, var value in DecodedJSON) { @@ -88,7 +82,7 @@ void function GetStatsFromToneAPI() } print(prefix + "has succeeded in getting stats for " + allHttpRequests[i].slice(1)) } - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (i) + void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (i, allHttpRequests) { print(prefix + "has encountered an error getting stats for " + allHttpRequests[i].slice(1)) } From 550c8993235a73a129626faac45a39646855c9da Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 14 May 2023 12:53:04 +0200 Subject: [PATCH 04/71] Complete refactor #8 --- mod/scripts/vscripts/pulse.gnut | 51 +++++------- mod/scripts/vscripts/ui/menu_stats_maps.nut | 8 +- .../vscripts/ui/menu_stats_overview.nut | 78 +++++++++++-------- mod/scripts/vscripts/ui/menu_stats_time.nut | 20 ++--- mod/scripts/vscripts/ui/menu_stats_titans.nut | 2 +- .../vscripts/ui/menu_stats_utility.nut | 10 +-- .../vscripts/ui/menu_stats_weapons.nut | 8 +- 7 files changed, 90 insertions(+), 87 deletions(-) diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index 666beda..e609542 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -3,16 +3,7 @@ global function GetStatsFromToneAPI global function getFromToneAPI global function fetchGamemodeStatsFromToneAPI -global table globalToneAPIKillData = {} -global table globalToneAPIDeathData = {} -global table globalToneAPIDWEData = {} -global table globalToneAPIMapDeathData = {} -global table globalToneAPIMapDistData = {} -global table globalToneAPIMapKillData = {} -global table globalToneAPIMapMDistData = {} -global table globalToneAPIGamemodeData = {} -global table globalToneAPIAllPlayerKillData = {} -global table globalToneAPIAllPlayerDeathData = {} +global table pulseData = {} global table< table > globalToneAPIGamemodeMapData = {} string prefix = "default" @@ -51,35 +42,23 @@ void function pulseInit() void function GetStatsFromToneAPI() { string UID = NSGetLocalPlayerUID() - array allHttpRequests = ["/weapons", "/weapons", "/maps", "/gamemodes"] + array allHttpRequests = ["/weapons", "/weapons", "/gamemodes", "/maps"] array allHttpParameters = [UID, "!" + UID, UID, UID] + array keyValues = ["weaponsLocal", "weaponsGlobal", "gamemodes", "maps"] for (int i; i < allHttpRequests.len(); i++) { HttpRequest getStats getStats.method = HttpRequestMethod.GET getStats.url = HTTPrequestURL + allHttpRequests[i] getStats.queryParameters["player"] <- [allHttpParameters[i]] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i, allHttpRequests) + void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i, allHttpRequests, keyValues) { table DecodedJSON = DecodeJSON(response.body) + table keyandvalues = {} foreach (var key, var value in DecodedJSON) { - table test = expect table(value) - switch (i) { - case 0: - globalToneAPIKillData[string(key)] <- test.kills - globalToneAPIDeathData[string(key)] <- test.deaths - globalToneAPIDWEData[string(key)] <- test.deaths_while_equipped - case 1: - globalToneAPIAllPlayerKillData[string(key)] <- test.kills - globalToneAPIAllPlayerDeathData[string(key)] <- test.deaths - case 2: - globalToneAPIMapKillData[string(key)] <- test.kills - globalToneAPIMapDeathData[string(key)] <- test.deaths - globalToneAPIMapDistData[string(key)] <- test.total_distance - globalToneAPIMapMDistData[string(key)] <- test.max_distance - case 3: - globalToneAPIGamemodeData[string(key)] <- test.kills + table values = expect table(value) + keyandvalues[string(key)] <- values } - } + pulseData[keyValues[i]] <- keyandvalues print(prefix + "has succeeded in getting stats for " + allHttpRequests[i].slice(1)) } void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (i, allHttpRequests) @@ -122,13 +101,19 @@ void function fetchGamemodeStatsFromToneAPI(string mapName) NSHttpRequest(getMapGamemodeStats, onSuccess, onFailure) } -int function getFromToneAPI(string parameter, table data){ +int function getFromToneAPI(string parameter, string key, string value){ - if (file.allMaps.find(parameter) != -1) { + if (key == "maps") { parameter = parameter.slice(3) } - if (parameter in data) { - return expect int(data[parameter]) + if (key in pulseData) { + table keyandvalTable = expect table(pulseData[key]) + // look to array keyValues for possible values for key + if (parameter in keyandvalTable) { + table valTable = expect table(keyandvalTable[parameter]) + return expect int(valTable[value]) + // possible values for parameter: kills, deaths, deaths_while_equipped, total_distance, max_distance + } } return 0 } diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mod/scripts/vscripts/ui/menu_stats_maps.nut index 388897a..9777e1f 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -155,16 +155,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(mapName, globalToneAPIMapKillData) ) + SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(mapName, "maps", "kills") ) SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(mapName, globalToneAPIMapDeathData) ) + SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(mapName, "maps", "deaths") ) SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(getFromToneAPI(mapName, globalToneAPIMapDistData) ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(getFromToneAPI(mapName, "maps", "total_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(getFromToneAPI(mapName, globalToneAPIMapMDistData) ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(getFromToneAPI(mapName, "maps", "max_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) SetStatsLabelValue( file.menu, "KillsValue4", "--" ) diff --git a/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mod/scripts/vscripts/ui/menu_stats_overview.nut index 3b4197c..4d3d9d8 100644 --- a/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -6,11 +6,13 @@ struct { var menu array allTitans + array allPilotWeapons table > titanStatLoadout } file const MAX_DOTS_ON_GRAPH = 10 table titanKillData = {} +table pilotKillData = {} const IMAGE_TITAN_STRYDER = $"ui/menu/personal_stats/ps_titan_icon_stryder" const IMAGE_TITAN_ATLAS = $"ui/menu/personal_stats/ps_titan_icon_atlas" @@ -34,7 +36,7 @@ void function GetTitanKills( string titanName ) { file.allTitans = GetVisibleItemsOfType( eItemTypes.TITAN ) var dataTable = GetDataTable( $"datatable/titan_properties.rpak" ) - + foreach ( titan in file.allTitans ) { file.titanStatLoadout[ titan.ref ] <- [] @@ -50,10 +52,19 @@ void function GetTitanKills( string titanName ) foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - titanKillData[weaponRef] <- getFromToneAPI(weaponRef, globalToneAPIKillData) + titanKillData[weaponRef] <- getFromToneAPI(weaponRef, "weaponsLocal", "kills") } } +void function GetAllPilotWeapons() +{ + file.allPilotWeapons = GetVisibleItemsOfType( eItemTypes.PILOT_PRIMARY) + file.allPilotWeapons.extend(GetVisibleItemsOfType( eItemTypes.PILOT_SECONDARY) ) + file.allPilotWeapons.extend(GetVisibleItemsOfType( eItemTypes.PILOT_ORDNANCE) ) + file.allPilotWeapons.extend( GetVisibleItemsOfType( eItemTypes.PILOT_SPECIAL ) ) +} + + void function OnStatsOverview_Open() { UI_SetPresentationType( ePresentationType.NO_MODELS ) @@ -288,40 +299,45 @@ function UpdateViewStatsOverviewMenu() //######################### // Lifetime - + table playerweaponData = expect table(pulseData["weaponsLocal"]) + table globalweaponData = expect table(pulseData["weaponsGlobal"]) var totalPilotKills = 0 - - foreach (var key, var value in globalToneAPIKillData) { - totalPilotKills += value + + foreach (var key, var value in playerweaponData) { + table values = expect table(value) + totalPilotKills += values["kills"] } var totalGlobalKills = 0 - foreach (var key, var value in globalToneAPIAllPlayerKillData) { - totalGlobalKills += value - } - - var totalGlobalDeaths = 0 - foreach (var key, var value in globalToneAPIAllPlayerDeathData) { - totalGlobalDeaths += value + foreach (var key, var value in globalweaponData) { + table values = expect table(value) + totalGlobalKills += values["kills"] } var totalPilotDeaths = 0 - - foreach (var key, var value in globalToneAPIDeathData) { - totalPilotDeaths += value + foreach (var key, var value in playerweaponData) { + table values = expect table(value) + totalPilotDeaths += values["deaths"] } + var totalGlobalDeaths = 0 + foreach (var key, var value in globalweaponData) { + table values = expect table(value) + totalGlobalDeaths += values["deaths"] + } + + var killsAsPilot = 0 - foreach (var key, var value in globalToneAPIKillData) { + foreach (var key, var value in playerweaponData) { if (key in titanKillData) { continue } else { - killsAsPilot += getFromToneAPI(string(key), globalToneAPIKillData) + killsAsPilot += getFromToneAPI(string(key), "weaponsLocal", "kills") } } var killsAsTitan = 0 - foreach (var key, var value in globalToneAPIKillData) { + foreach (var key, var value in playerweaponData) { if (key in titanKillData) { killsAsTitan += titanKillData[string(key)] } @@ -391,27 +407,27 @@ function UpdateViewStatsOverviewMenu() Hud_SetText( GetElem( file.menu, "KillsAsPilotValue0" ), string( killsAsPilot ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsPilot" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue2" ), string( GetPlayerStatInt( player, "kills_stats", "totalNPC" ) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( getFromToneAPI("pilot_emptyhanded", globalToneAPIKillData) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( getFromToneAPI("human_execution", globalToneAPIKillData) ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( getFromToneAPI("pilot_emptyhanded", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( getFromToneAPI("human_execution", "weaponsLocal", "kills") ) ) // Hud_SetText( GetElem( file.menu, "KillsAsPilotValue5" ), string( GetPlayerStatInt( player, "kills_stats", "titanFallKill" ) ) ) var titanMeleeKills = 0 - titanMeleeKills += getFromToneAPI("titan_punch_ion", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_punch_scorch", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_punch_northstar", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_sword", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_punch_tone", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_punch_legion", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("titan_punch_vanguard", globalToneAPIKillData) - titanMeleeKills += getFromToneAPI("auto_titan_melee", globalToneAPIKillData) + titanMeleeKills += getFromToneAPI("titan_punch_ion", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_punch_scorch", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_punch_northstar", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_sword", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_punch_tone", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_punch_legion", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("titan_punch_vanguard", "weaponsLocal", "kills") + titanMeleeKills += getFromToneAPI("auto_titan_melee", "weaponsLocal", "kills") - var titanExecutions = getFromToneAPI("titan_execution", globalToneAPIKillData) + var titanExecutions = getFromToneAPI("titan_execution", "weaponsLocal", "kills") Hud_SetText( GetElem( file.menu, "KillsAsTitanValue0" ), string( killsAsTitan ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsTitan" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue2" ), string( titanExecutions ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue3" ), string( titanMeleeKills ) ) - Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( getFromToneAPI("damagedef_titan_step", globalToneAPIKillData) ) ) + Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( getFromToneAPI("damagedef_titan_step", "weaponsLocal", "kills") ) ) } function PlotKDPointsOnGraph( menu, graphIndex, values, dottedAverage ) diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mod/scripts/vscripts/ui/menu_stats_time.nut index f517eaa..1bd3f2a 100644 --- a/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -49,7 +49,7 @@ float function GetTitanKills( string titanName) float weaponKills = 0 foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - weaponKills += float(getFromToneAPI(weaponRef, globalToneAPIKillData)) + weaponKills += float(getFromToneAPI(weaponRef, "weaponsLocal", "kills")) } return weaponKills } @@ -79,11 +79,13 @@ void function UpdateViewStatsTimeMenu() //######################################### // Time By Class Pie Chart //######################################### - + var totalPilotKills = 0 - - foreach (var key, var value in globalToneAPIKillData) { - totalPilotKills += value + table playerweaponData = expect table(pulseData["weaponsLocal"]) + + foreach (var key, var value in playerweaponData) { + table values = expect table(value) + totalPilotKills += values["kills"] } float hoursAsPilot = float(totalPilotKills) float hoursAsTitan = killsAsTitan @@ -153,10 +155,10 @@ void function UpdateViewStatsTimeMenu() for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( modeName in globalToneAPIGamemodeData ) + if ( getFromToneAPI(modeName, "gamemodes", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(globalToneAPIGamemodeData[modeName]) + modePlayedTime = float(getFromToneAPI(modeName, "gamemodes", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -164,10 +166,10 @@ void function UpdateViewStatsTimeMenu() } foreach (string key, array value in customGamemodeList) { - if ( key in globalToneAPIGamemodeData) + if ( getFromToneAPI(key, "gamemodes", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(globalToneAPIGamemodeData[key]) + modePlayedTime = float(getFromToneAPI(key, "gamemodes", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, key, modePlayedTime, value) } diff --git a/mod/scripts/vscripts/ui/menu_stats_titans.nut b/mod/scripts/vscripts/ui/menu_stats_titans.nut index b7912a3..e9cd6f8 100644 --- a/mod/scripts/vscripts/ui/menu_stats_titans.nut +++ b/mod/scripts/vscripts/ui/menu_stats_titans.nut @@ -175,7 +175,7 @@ void function UpdateStatsForTitan( string titanRef, int loadoutIndex ) int aiKills foreach ( weaponRef in file.titanStatLoadout[ titanRef ] ) { - totalKills += getFromToneAPI(weaponRef, globalToneAPIKillData) + totalKills += getFromToneAPI(weaponRef, "weaponsLocal", "kills") pilotKills += GetPlayerStatInt( player, "weapon_kill_stats", "pilots", weaponRef ) titanKills += GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) aiKills += GetPlayerStatInt( player, "weapon_kill_stats", "ai", weaponRef ) diff --git a/mod/scripts/vscripts/ui/menu_stats_utility.nut b/mod/scripts/vscripts/ui/menu_stats_utility.nut index 6eddad7..29be870 100644 --- a/mod/scripts/vscripts/ui/menu_stats_utility.nut +++ b/mod/scripts/vscripts/ui/menu_stats_utility.nut @@ -338,7 +338,7 @@ table function GetOverviewWeaponData() if ( !PersistenceEnumValueIsValid( "loadoutWeaponsAndAbilities", weaponName ) ) continue - int val = getFromToneAPI(weaponName, globalToneAPIKillData) + int val = getFromToneAPI(weaponName, "weaponsLocal", "kills") if ( val > Table[ "most_kills" ].val ) { Table[ "most_kills" ].ref = weaponName @@ -346,7 +346,7 @@ table function GetOverviewWeaponData() Table[ "most_kills" ].val = val } - int nval = getFromToneAPI(weaponName, globalToneAPIDeathData) + int nval = getFromToneAPI(weaponName, "weaponsLocal", "deaths") if ( nval > Table[ "nemesis_weapon" ].val ) { Table[ "nemesis_weapon" ].ref = weaponName @@ -357,9 +357,9 @@ table function GetOverviewWeaponData() float kdval = 0 float kval = 0 float dval = 0 - if( getFromToneAPI(weaponName, globalToneAPIKillData) != 0 && getFromToneAPI(weaponName, globalToneAPIDWEData) != 0){ - kval = float(getFromToneAPI(weaponName, globalToneAPIKillData)) - dval = float(getFromToneAPI(weaponName, globalToneAPIDWEData)) + if( getFromToneAPI(weaponName, "weaponsLocal", "kills") != 0 && getFromToneAPI(weaponName, "weaponsLocal", "deaths_while_equipped") != 0){ + kval = float(getFromToneAPI(weaponName, "weaponsLocal", "kills")) + dval = float(getFromToneAPI(weaponName, "weaponsLocal", "deaths_while_equipped")) if (kval / dval > kdval){ kdval = kval / dval } diff --git a/mod/scripts/vscripts/ui/menu_stats_weapons.nut b/mod/scripts/vscripts/ui/menu_stats_weapons.nut index c37c533..6fcc252 100644 --- a/mod/scripts/vscripts/ui/menu_stats_weapons.nut +++ b/mod/scripts/vscripts/ui/menu_stats_weapons.nut @@ -180,8 +180,8 @@ void function UpdateStatsForWeapon( string weaponRef ) } // Total Kills Stats - SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(weaponRef, globalToneAPIKillData) ) - SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(weaponRef, globalToneAPIKillData) ) - SetStatsLabelValue( file.menu, "KillsValue2", GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) ) - SetStatsLabelValue( file.menu, "KillsValue3", getFromToneAPI(weaponRef, globalToneAPIDWEData)) + SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(weaponRef, "weaponsLocal", "kills") ) //Total kills + SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(weaponRef, "weaponsLocal", "kills") ) //Pilots + SetStatsLabelValue( file.menu, "KillsValue2", GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) ) //Titans + SetStatsLabelValue( file.menu, "KillsValue3", getFromToneAPI(weaponRef, "weaponsLocal", "deaths_while_equipped")) // Deaths with weapon } From 240a07d9fa138c738aabef40936db1349b94e8fc Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 14 May 2023 13:48:49 +0200 Subject: [PATCH 05/71] Add clearer gamemode names to "Maps" and "Time" --- mod/scripts/vscripts/ui/menu_stats_maps.nut | 7 ++++++- mod/scripts/vscripts/ui/menu_stats_time.nut | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mod/scripts/vscripts/ui/menu_stats_maps.nut index 9777e1f..49d72b4 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -185,6 +185,11 @@ void function UpdateStatsForMap( string mapName ) fw = [147, 204, 57, 255], gg = [14, 87, 132, 255] } + table< string, string > customGamemodeNames = { + sns = "Sticks and Stones" + fw = "Frontier War" + gg = "Gun Game" + } for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) @@ -204,7 +209,7 @@ void function UpdateStatsForMap( string mapName ) float modePlayedTime = 0 modePlayedTime = float(globalToneAPIGamemodeMapData[mapName][key]) if ( modePlayedTime > 0 ) { - AddPieChartEntry( modes, key, modePlayedTime, value) + AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } } } diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mod/scripts/vscripts/ui/menu_stats_time.nut index 1bd3f2a..3030481 100644 --- a/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -152,6 +152,11 @@ void function UpdateViewStatsTimeMenu() fw = [147, 204, 57, 255], gg = [14, 87, 132, 255] } + table< string, string > customGamemodeNames = { + sns = "Sticks and Stones" + fw = "Frontier War" + gg = "Gun Game" + } for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) @@ -171,7 +176,7 @@ void function UpdateViewStatsTimeMenu() float modePlayedTime = 0 modePlayedTime = float(getFromToneAPI(key, "gamemodes", "kills")) if ( modePlayedTime > 0 ) { - AddPieChartEntry( modes, key, modePlayedTime, value) + AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } } } From 413d9f6cf3ce0356ae1c1004e2a0f812c0c6c27c Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 14 May 2023 13:55:31 +0200 Subject: [PATCH 06/71] Globalise prefix --- mod/scripts/vscripts/pulse.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index e609542..4afeeb5 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -6,7 +6,8 @@ global function fetchGamemodeStatsFromToneAPI global table pulseData = {} global table< table > globalToneAPIGamemodeMapData = {} -string prefix = "default" +global string prefix = "\x1b[38;2;255;178;102m[PULSE]\x1b[0m " + string HTTPrequestURL = "default" string currentVersion = "default" int mapGamemodeEntries = 0 @@ -17,7 +18,6 @@ struct { void function pulseInit() { - prefix = "\x1b[38;2;255;178;102m[PULSE]\x1b[0m " HTTPrequestURL = GetConVarString("ToneURL") currentVersion = "v" + GetConVarString("MajorVersion") + "." + GetConVarString("MinorVersion") + "." + GetConVarString("PatchVersion") HttpRequest getVersion From 1b914dc5cf48247d3817f39cfbea55c394b50c42 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 11:08:37 +0200 Subject: [PATCH 07/71] Bump version number --- mod.json | 8 ++++---- version.json | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mod.json b/mod.json index a3c0074..ee14667 100644 --- a/mod.json +++ b/mod.json @@ -1,7 +1,7 @@ { "Name": "ToneAPI.pulse", "Description": "Displays Tone API kill data in the Stats tab.", - "Version": "1.2.2", + "Version": "2.0.0", "LoadPriority": 1, "ConVars": [ { @@ -14,15 +14,15 @@ }, { "Name": "MajorVersion", - "DefaultValue": "1" + "DefaultValue": "2" }, { "Name": "MinorVersion", - "DefaultValue": "2" + "DefaultValue": "0" }, { "Name": "PatchVersion", - "DefaultValue": "2" + "DefaultValue": "0" } ], "Scripts": [ diff --git a/version.json b/version.json index 1d6e638..d3c0ffc 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "Major": "1", - "Minor": "2", - "Patch": "1" + "Major": "2", + "Minor": "0", + "Patch": "0" } \ No newline at end of file From 90401c85675c4dc97924d874479cb359c2647aab Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 11:58:02 +0200 Subject: [PATCH 08/71] Begin porting common functions to common file For easier readability and expandability --- mod.json | 14 ++++--- mod/scripts/vscripts/pulse-common-func.gnut | 42 +++++++++++++++++++++ version.json | 6 +-- 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 mod/scripts/vscripts/pulse-common-func.gnut diff --git a/mod.json b/mod.json index ee14667..248814a 100644 --- a/mod.json +++ b/mod.json @@ -27,11 +27,15 @@ ], "Scripts": [ { - "Path": "pulse.gnut", - "RunOn": "UI", - "UICallback": { - "After": "pulseInit" - } + "Path":"pulse-common-func.gnut", + "RunOn":"UI" + }, + { + "Path": "pulse.gnut", + "RunOn": "UI", + "UICallback": { + "After": "pulseInit" + } } ] } diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut new file mode 100644 index 0000000..95afc27 --- /dev/null +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -0,0 +1,42 @@ +globalize_all_functions + + +void function pulsePrintt (string content) +{ + printt(format("%s " + content, pulsePrefix)) +} + +table function pulseGetCurrentVersionAsTable +{ + table result = ["MajorVersion" = GetConVarString("MajorVersion"), "MinorVersion" = GetConVarString("MinorVersion"), "PatchVersion" = GetConVarString("PatchVersion")] + return result +} + +string function pulseFormatAsVersion(table Version) +{ + return format("v%s.%s.%s", Version["MajorVersion"], Version["MinorVersion"], Version["PatchVersion"]) +} + +bool function pulseIsUpToDate(string givenURL) +{ + bool result = false + HttpRequest versionreq + versionreq.method = HttpRequestMethod.GET + versionreq.url = givenURL + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) + { + table DecodedJSON = DecodeJSON(response.body) + if (pulseFormatAsVersion(DecodedJSON) == pulseFormatAsVersion(pulseGetCurrentVersionAsTable())) + { + result = true + } else { + result = false + } + } + void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) + { + pulsePrintt("Something went wrong while getting latest version.") + } + NSHttpRequest(versionreq, onSuccess, onFailure) + return result +} \ No newline at end of file diff --git a/version.json b/version.json index d3c0ffc..d2cae6f 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "Major": "2", - "Minor": "0", - "Patch": "0" + "MajorVersion": "2", + "MinorVersion": "0", + "PatchVersion": "0" } \ No newline at end of file From 748981160a51ee60b1834c0caea7310abcb47cc8 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:03:54 +0200 Subject: [PATCH 09/71] Add comment descriptions to pulse-common-func.gnut --- mod/scripts/vscripts/pulse-common-func.gnut | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index 95afc27..68992ca 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -1,23 +1,23 @@ globalize_all_functions -void function pulsePrintt (string content) +void function pulsePrintt (string content) //Prints whatever we want printed with given prefix (by standard [PULSE]). { printt(format("%s " + content, pulsePrefix)) } -table function pulseGetCurrentVersionAsTable +table function pulseGetCurrentVersionAsTable //Gets our version numbers from mod.json and puts them in a table for use with pulseFormatAsVersion(). { table result = ["MajorVersion" = GetConVarString("MajorVersion"), "MinorVersion" = GetConVarString("MinorVersion"), "PatchVersion" = GetConVarString("PatchVersion")] return result } -string function pulseFormatAsVersion(table Version) +string function pulseFormatAsVersion(table Version) //Formats given version numbers into one neat string (example: v2.0.0). { return format("v%s.%s.%s", Version["MajorVersion"], Version["MinorVersion"], Version["PatchVersion"]) } -bool function pulseIsUpToDate(string givenURL) +bool function pulseIsUpToDate(string givenURL) //Compares version contained in our mod.json with a version.json contained on a remote GitHub repo (see VersionURL within mod.json). { bool result = false HttpRequest versionreq From 6f4425872bc3d8da2094c28ca002d2941e2a1bca Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:29:29 +0200 Subject: [PATCH 10/71] Move prefix definition to common file --- mod/scripts/vscripts/pulse-common-func.gnut | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index 68992ca..06fe0a7 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -1,6 +1,12 @@ globalize_all_functions + +string pulsePrefix +void function pulsePrefixSet { + pulsePrefix = format("\x1b[38;2;%i;%i;%im[PULSE]\x1b[0m", 255, 178, 102) +} + void function pulsePrintt (string content) //Prints whatever we want printed with given prefix (by standard [PULSE]). { printt(format("%s " + content, pulsePrefix)) From a5844b6be41c55855056da56fdcdecd53879f27e Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:57:19 +0200 Subject: [PATCH 11/71] Initial function for getting data --- mod/scripts/vscripts/pulse-common-func.gnut | 26 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index 06fe0a7..3c826af 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -3,16 +3,17 @@ globalize_all_functions string pulsePrefix -void function pulsePrefixSet { +void function pulsePrefixSet() //Sets our prefix +{ pulsePrefix = format("\x1b[38;2;%i;%i;%im[PULSE]\x1b[0m", 255, 178, 102) } -void function pulsePrintt (string content) //Prints whatever we want printed with given prefix (by standard [PULSE]). +void function pulsePrintt(string content) //Prints whatever we want printed with given prefix (by standard [PULSE]). { printt(format("%s " + content, pulsePrefix)) } -table function pulseGetCurrentVersionAsTable //Gets our version numbers from mod.json and puts them in a table for use with pulseFormatAsVersion(). +table function pulseGetCurrentVersionAsTable() //Gets our version numbers from mod.json and puts them in a table for use with pulseFormatAsVersion(). { table result = ["MajorVersion" = GetConVarString("MajorVersion"), "MinorVersion" = GetConVarString("MinorVersion"), "PatchVersion" = GetConVarString("PatchVersion")] return result @@ -45,4 +46,23 @@ bool function pulseIsUpToDate(string givenURL) //Compares version contained in o } NSHttpRequest(versionreq, onSuccess, onFailure) return result +} + +bool function pulseRequestData(string givenURL, table parameterTable) //Gets all data from API (see ToneURL within mod.json) and puts it into one table for processing. +{ + table > params + foreach (parameter in paramTable) + { + params[parameter] <- [paramTable(parameter)] + } + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) + { + table DecodedJSON = DecodeJSON(response.body) + pulseData += DecodedJSON + } + void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) + { + pulsePrintt("Something went wrong while getting data.") + } + return NSHttpGet(givenURL, params, onSuccess, onFailure) } \ No newline at end of file From 2d2d456a8505b63655af6c1800cf2455cd3f0aaf Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:58:35 +0200 Subject: [PATCH 12/71] Replace NSHttpRequest with NSHttpGet --- mod/scripts/vscripts/pulse-common-func.gnut | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index 3c826af..f739707 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -27,9 +27,6 @@ string function pulseFormatAsVersion(table Version) //Formats given version numb bool function pulseIsUpToDate(string givenURL) //Compares version contained in our mod.json with a version.json contained on a remote GitHub repo (see VersionURL within mod.json). { bool result = false - HttpRequest versionreq - versionreq.method = HttpRequestMethod.GET - versionreq.url = givenURL void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) { table DecodedJSON = DecodeJSON(response.body) @@ -44,7 +41,7 @@ bool function pulseIsUpToDate(string givenURL) //Compares version contained in o { pulsePrintt("Something went wrong while getting latest version.") } - NSHttpRequest(versionreq, onSuccess, onFailure) + NSHttpGet(givenURL, onSuccess, onFailure) return result } From 5735e67c2f78f24ecc4477b3fe7c564fe52389d5 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:06:32 +0200 Subject: [PATCH 13/71] Copy getFromToneAPI to common file as pulseParse --- mod/scripts/vscripts/pulse-common-func.gnut | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index f739707..f291ef0 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -45,7 +45,7 @@ bool function pulseIsUpToDate(string givenURL) //Compares version contained in o return result } -bool function pulseRequestData(string givenURL, table parameterTable) //Gets all data from API (see ToneURL within mod.json) and puts it into one table for processing. +bool function pulseRequestData(string givenURL, table parameterTable) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > params foreach (parameter in paramTable) @@ -62,4 +62,19 @@ bool function pulseRequestData(string givenURL, table parameterTable) //Gets all pulsePrintt("Something went wrong while getting data.") } return NSHttpGet(givenURL, params, onSuccess, onFailure) +} + +int function pulseParse(string parameter, string key, string value) +{ + if (key == "maps") { + parameter = parameter.slice(3) + } + if (key in pulseData) { + table keyandvalTable = expect table(pulseData[key]) + if (parameter in keyandvalTable) { + table valTable = expect table(keyandvalTable[parameter]) + return expect int(valTable[value]) + } + } + return 0 } \ No newline at end of file From 42f8c0d0f4bff19a3ed36c0fa6f020243d72b1ef Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:12:26 +0200 Subject: [PATCH 14/71] Globalise prefix to avoid future issues --- mod/scripts/vscripts/pulse-common-func.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index f291ef0..ec76644 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -2,7 +2,7 @@ globalize_all_functions -string pulsePrefix +global string pulsePrefix void function pulsePrefixSet() //Sets our prefix { pulsePrefix = format("\x1b[38;2;%i;%i;%im[PULSE]\x1b[0m", 255, 178, 102) From 1a0b074816a746c049f249fd452f4388450cf047 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:21:01 +0200 Subject: [PATCH 15/71] Get current and latest version as string --- mod/scripts/vscripts/pulse-common-func.gnut | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index ec76644..d2d9600 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -24,6 +24,27 @@ string function pulseFormatAsVersion(table Version) //Formats given version numb return format("v%s.%s.%s", Version["MajorVersion"], Version["MinorVersion"], Version["PatchVersion"]) } +string function pulseGetCurrentVersionAsString() +{ + return pulseFormatAsVersion(pulseGetCurrentVersionAsTable()) +} + +string function pulseGetLatestVersionAsString() +{ + string result = "" + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) + { + table DecodedJSON = DecodeJSON(response.body) + result = pulseFormatAsVersion(DecodedJSON) + } + void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) + { + pulsePrintt("Something went wrong while getting latest version.") + } + NSHttpGet(givenURL, onSuccess, onFailure) + return result +} + bool function pulseIsUpToDate(string givenURL) //Compares version contained in our mod.json with a version.json contained on a remote GitHub repo (see VersionURL within mod.json). { bool result = false From 30be7f5bf51aea608d01a427fb761fd4bd67ed39 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:48:16 +0200 Subject: [PATCH 16/71] Remove version check Is unnecessary --- mod/scripts/vscripts/pulse-common-func.gnut | 53 ---------- mod/scripts/vscripts/pulse.gnut | 110 +------------------- 2 files changed, 2 insertions(+), 161 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index d2d9600..6bf7d12 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -13,59 +13,6 @@ void function pulsePrintt(string content) //Prints whatever we want printed with printt(format("%s " + content, pulsePrefix)) } -table function pulseGetCurrentVersionAsTable() //Gets our version numbers from mod.json and puts them in a table for use with pulseFormatAsVersion(). -{ - table result = ["MajorVersion" = GetConVarString("MajorVersion"), "MinorVersion" = GetConVarString("MinorVersion"), "PatchVersion" = GetConVarString("PatchVersion")] - return result -} - -string function pulseFormatAsVersion(table Version) //Formats given version numbers into one neat string (example: v2.0.0). -{ - return format("v%s.%s.%s", Version["MajorVersion"], Version["MinorVersion"], Version["PatchVersion"]) -} - -string function pulseGetCurrentVersionAsString() -{ - return pulseFormatAsVersion(pulseGetCurrentVersionAsTable()) -} - -string function pulseGetLatestVersionAsString() -{ - string result = "" - void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - table DecodedJSON = DecodeJSON(response.body) - result = pulseFormatAsVersion(DecodedJSON) - } - void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - pulsePrintt("Something went wrong while getting latest version.") - } - NSHttpGet(givenURL, onSuccess, onFailure) - return result -} - -bool function pulseIsUpToDate(string givenURL) //Compares version contained in our mod.json with a version.json contained on a remote GitHub repo (see VersionURL within mod.json). -{ - bool result = false - void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - table DecodedJSON = DecodeJSON(response.body) - if (pulseFormatAsVersion(DecodedJSON) == pulseFormatAsVersion(pulseGetCurrentVersionAsTable())) - { - result = true - } else { - result = false - } - } - void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - pulsePrintt("Something went wrong while getting latest version.") - } - NSHttpGet(givenURL, onSuccess, onFailure) - return result -} - bool function pulseRequestData(string givenURL, table parameterTable) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > params diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index 4afeeb5..1244bbc 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -1,16 +1,6 @@ global function pulseInit -global function GetStatsFromToneAPI -global function getFromToneAPI -global function fetchGamemodeStatsFromToneAPI global table pulseData = {} -global table< table > globalToneAPIGamemodeMapData = {} - -global string prefix = "\x1b[38;2;255;178;102m[PULSE]\x1b[0m " - -string HTTPrequestURL = "default" -string currentVersion = "default" -int mapGamemodeEntries = 0 struct { array allMaps @@ -18,102 +8,6 @@ struct { void function pulseInit() { - HTTPrequestURL = GetConVarString("ToneURL") - currentVersion = "v" + GetConVarString("MajorVersion") + "." + GetConVarString("MinorVersion") + "." + GetConVarString("PatchVersion") - HttpRequest getVersion - getVersion.method = HttpRequestMethod.GET - getVersion.url = GetConVarString("VersionURL") - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) - { - table JSONDecoded = DecodeJSON(response.body) - if (JSONDecoded["Major"] == GetConVarString("MajorVersion") && JSONDecoded["Minor"] == GetConVarString("MinorVersion") && JSONDecoded["Patch"] == GetConVarString("PatchVersion")) { - print(prefix + currentVersion + " has been loaded and is up to date.") - } else { - print(prefix + currentVersion + " has been loaded. Recommend updating to latest version: v" + JSONDecoded["Major"] + "." + JSONDecoded["Minor"] + "." + JSONDecoded["Patch"] + ".") - } - } - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + currentVersion + " has been loaded and has encountered an error getting latest version data.") - } - NSHttpRequest(getVersion, onSuccess, onFailure) -} - -void function GetStatsFromToneAPI() -{ - string UID = NSGetLocalPlayerUID() - array allHttpRequests = ["/weapons", "/weapons", "/gamemodes", "/maps"] - array allHttpParameters = [UID, "!" + UID, UID, UID] - array keyValues = ["weaponsLocal", "weaponsGlobal", "gamemodes", "maps"] - for (int i; i < allHttpRequests.len(); i++) { - HttpRequest getStats - getStats.method = HttpRequestMethod.GET - getStats.url = HTTPrequestURL + allHttpRequests[i] - getStats.queryParameters["player"] <- [allHttpParameters[i]] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (i, allHttpRequests, keyValues) - { - table DecodedJSON = DecodeJSON(response.body) - table keyandvalues = {} - foreach (var key, var value in DecodedJSON) { - table values = expect table(value) - keyandvalues[string(key)] <- values - } - pulseData[keyValues[i]] <- keyandvalues - print(prefix + "has succeeded in getting stats for " + allHttpRequests[i].slice(1)) - } - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (i, allHttpRequests) - { - print(prefix + "has encountered an error getting stats for " + allHttpRequests[i].slice(1)) - } - NSHttpRequest(getStats, onSuccess, onFailure) - } -} - -void function fetchGamemodeStatsFromToneAPI(string mapName) -{ - mapGamemodeEntries = 0 - string mapNameSliced = mapName.slice(3) - HttpRequest getMapGamemodeStats - getMapGamemodeStats.method = HttpRequestMethod.GET - getMapGamemodeStats.url = HTTPrequestURL + "/gamemodes" - getMapGamemodeStats.queryParameters["map"] <- [mapNameSliced] - getMapGamemodeStats.queryParameters["player"] <- [NSGetLocalPlayerUID()] - void functionref(HttpRequestResponse) onSuccess = void function(HttpRequestResponse response):(mapName) - { - table JSONForConversion = DecodeJSON(response.body) - table mapData = {} - foreach (var gamemode, var value in JSONForConversion) { - table test = expect table(value) - mapData[string(gamemode)] <- test.kills - mapGamemodeEntries += 1 - } - - globalToneAPIGamemodeMapData[mapName] <- mapData - - print(prefix + "Map gamemode data has been processed with a total of " + string(mapGamemodeEntries) + " entries.") - } - - void functionref(HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) - { - print(prefix + "Encountered an error getting map gamemode data...") - } - - NSHttpRequest(getMapGamemodeStats, onSuccess, onFailure) -} - -int function getFromToneAPI(string parameter, string key, string value){ - - if (key == "maps") { - parameter = parameter.slice(3) - } - if (key in pulseData) { - table keyandvalTable = expect table(pulseData[key]) - // look to array keyValues for possible values for key - if (parameter in keyandvalTable) { - table valTable = expect table(keyandvalTable[parameter]) - return expect int(valTable[value]) - // possible values for parameter: kills, deaths, deaths_while_equipped, total_distance, max_distance - } - } - return 0 + pulsePrefixSet() + pulsePrintt("Initialized.") } From ae963b245fd036161696ee4c74aeb94eefd7e1d3 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:55:36 +0200 Subject: [PATCH 17/71] Remove version.json and version ConVars --- mod.json | 12 ------------ version.json | 5 ----- 2 files changed, 17 deletions(-) delete mode 100644 version.json diff --git a/mod.json b/mod.json index 248814a..9ad4981 100644 --- a/mod.json +++ b/mod.json @@ -11,18 +11,6 @@ { "Name": "VersionURL", "DefaultValue": "https://raw.githubusercontent.com/ToneAPI/pulse/main/version.json" - }, - { - "Name": "MajorVersion", - "DefaultValue": "2" - }, - { - "Name": "MinorVersion", - "DefaultValue": "0" - }, - { - "Name": "PatchVersion", - "DefaultValue": "0" } ], "Scripts": [ diff --git a/version.json b/version.json deleted file mode 100644 index d2cae6f..0000000 --- a/version.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "MajorVersion": "2", - "MinorVersion": "0", - "PatchVersion": "0" -} \ No newline at end of file From 3985b3dd5cd60bc0b68db76835619b6f756e73d1 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:00:38 +0200 Subject: [PATCH 18/71] pulseGetData() function --- mod/scripts/vscripts/pulse.gnut | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index 1244bbc..e3538de 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -11,3 +11,17 @@ void function pulseInit() pulsePrefixSet() pulsePrintt("Initialized.") } + +void function pulseGetData() +{ + string URL = GetConVarString("ToneURL") + array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] + pulseRequestData(URL + URLpath[1], ["uid" = NSGetLocalPlayerUID()]) + pulseRequestData(URL + URLpath[2], ["uid" = "!" + NSGetLocalPlayerUID()]) + pulseRequestData(URL + URLpath[3], ["uid" = NSGetLocalPlayerUID()]) + foreach (map in file.allMaps) + { + pulseRequestData(URL + URLpath[4], ["uid" = NSGetLocalPlayerUID(), "map" = map.slice(3)]) + } + pulseRequestData(URL + URLpath[5], ["uid" = NSGetLocalPlayerUID()]) +} \ No newline at end of file From 2fdcf288d4bd0ac1bc70b153047b3f80686a2ce5 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:03:43 +0200 Subject: [PATCH 19/71] Create menu_lobby.nut --- mod/scripts/vscripts/ui/menu_lobby.nut | 1585 ++++++++++++++++++++++++ 1 file changed, 1585 insertions(+) create mode 100644 mod/scripts/vscripts/ui/menu_lobby.nut diff --git a/mod/scripts/vscripts/ui/menu_lobby.nut b/mod/scripts/vscripts/ui/menu_lobby.nut new file mode 100644 index 0000000..4206363 --- /dev/null +++ b/mod/scripts/vscripts/ui/menu_lobby.nut @@ -0,0 +1,1585 @@ +untyped + + +global function MenuLobby_Init + +global function InitLobbyMenu +global function UICodeCallback_SetupPlayerListGenElements +global function UpdateAnnouncementDialog +global function EnableButton +global function DisableButton + +global function UICodeCallback_CommunityUpdated +global function UICodeCallback_FactionUpdated +global function Lobby_UpdateInboxButtons + +global function GetTimeToRestartMatchMaking + +global function RefreshCreditsAvailable + +global function InviteFriendsIfAllowed +global function SetPutPlayerInMatchmakingAfterDelay + +global function DLCStoreShouldBeMarkedAsNew + +global function SetNextAutoMatchmakingPlaylist +global function GetNextAutoMatchmakingPlaylist + +global function OnDpadCommsButton_Activate + +global function GetActiveSearchingPlaylist + +global function Lobby_SetFDModeBasedOnSearching +global function Lobby_IsFDMode +global function Lobby_SetAutoFDOpen +global function Lobby_SetFDMode +global function Lobby_ToggleFDMode +global function Lobby_CallsignButton3EventHandler +global function Lobby_RefreshButtons + +global function OnStoreButton_Activate +global function OnStoreBundlesButton_Activate +global function OnStoreNewReleasesButton_Activate + +const string MATCHMAKING_AUDIO_CONNECTING = "menu_campaignsummary_titanunlocked" + +struct +{ + struct { + string playlistName = "" + int mapIdx = -1 + int modeIdx = -1 + } preCacheInfo + + array searchIconElems + array searchTextElems + array matchStartCountdownElems + array matchStatusRuis + + array creditsAvailableElems + + var chatroomMenu + var chatroomMenu_chatroomWidget + + var findGameButton + var inviteRoomButton + var inviteFriendsButton + var inviteFriendsToNetworkButton + var toggleMenuModeButton + + var networksMoreButton + + int inboxHeaderIndex + var inboxButton + + int customizeHeaderIndex + var pilotButton + var titanButton + var boostsButton + var storeButton + var storeNewReleasesButton + var storeBundlesButton + var factionButton + var bannerButton + var patchButton + var statsButton + var networksHeader + var settingsHeader + var storeHeader + var browseNetworkButton + var faqButton + var dpadCommsButton + + var genUpButton + + array lobbyButtons + var playHeader + var customizeHeader + var callsignHeader + + float timeToRestartMatchMaking = 0 + + string nextAutoMatchmakingPlaylist + + var callsignCard + + bool putPlayerInMatchmakingAfterDelay = false + float matchmakingStartTime = 0.0 + int etaTime = 0 + int etaMaxMinutes = 15 + string lastMixtapeMatchmakingStatus + + ComboStruct &lobbyComboStruct + + bool isFDMode = false + bool shouldAutoOpenFDMenu = false +} file + +void function MenuLobby_Init() +{ + PrecacheHUDMaterial( $"ui/menu/lobby/player_hover" ) + PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_player" ) + PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_hover" ) + PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background" ) + PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background_happyhour" ) + + AddUICallback_OnLevelInit( OnLobbyLevelInit ) +} + + +bool function ChatroomIsVisibleAndFocused() +{ + return Hud_IsVisible( file.chatroomMenu ) && Hud_IsFocused( file.chatroomMenu_chatroomWidget ); +} + +bool function ChatroomIsVisibleAndNotFocused() +{ + return Hud_IsVisible( file.chatroomMenu ) && !Hud_IsFocused( file.chatroomMenu_chatroomWidget ); +} + +void function Lobby_UpdateInboxButtons() +{ + var menu = GetMenu( "LobbyMenu" ) + if ( GetUIPlayer() == null || !IsPersistenceAvailable() ) + return + + bool hasNewMail = (Inbox_HasUnreadMessages() && Inbox_GetTotalMessageCount() > 0) || PlayerRandomUnlock_GetTotal( GetUIPlayer() ) > 0 + if ( hasNewMail ) + { + int messageCount = Inbox_GetTotalMessageCount() + int lootCount = PlayerRandomUnlock_GetTotal( GetUIPlayer() ) + int totalCount = messageCount + lootCount + + string countString + if ( totalCount >= MAX_MAIL_COUNT ) + countString = MAX_MAIL_COUNT + "+" + else + countString = string( totalCount ) + + SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS_NEW_MSGS", countString ) ) + ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_INBOX_NEW_MSGS", countString ) ) + } + else + { + SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS" ) ) + ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_READ" ) ) + } + + ComboButton_SetNewMail( file.inboxButton, hasNewMail ) +} + +void function InitLobbyMenu() +{ + var menu = GetMenu( "LobbyMenu" ) + + InitOpenInvitesMenu() + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT", "", null, ChatroomIsVisibleAndNotFocused ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + AddMenuFooterOption( menu, BUTTON_BACK, "#BACK_BUTTON_POSTGAME_REPORT", "#POSTGAME_REPORT", OpenPostGameMenu, IsPostGameMenuValid ) + AddMenuFooterOption( menu, BUTTON_TRIGGER_RIGHT, "#R_TRIGGER_CHAT", "", null, IsVoiceChatPushToTalk ) + + InitChatroom( menu ) + + file.chatroomMenu = Hud_GetChild( menu, "ChatRoomPanel" ) + file.chatroomMenu_chatroomWidget = Hud_GetChild( file.chatroomMenu, "ChatRoom" ) + file.genUpButton = Hud_GetChild( menu, "GenUpButton" ) + + SetupComboButtonTest( menu ) + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnLobbyMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnLobbyMenu_Close ) + AddMenuEventHandler( menu, eUIEvent.MENU_NAVIGATE_BACK, OnLobbyMenu_NavigateBack ) + + RegisterUIVarChangeCallback( "gameStartTime", GameStartTime_Changed ) + + RegisterUIVarChangeCallback( "showGameSummary", ShowGameSummary_Changed ) + + file.searchIconElems = GetElementsByClassnameForMenus( "SearchIconClass", uiGlobal.allMenus ) + file.searchTextElems = GetElementsByClassnameForMenus( "SearchTextClass", uiGlobal.allMenus ) + file.matchStartCountdownElems = GetElementsByClassnameForMenus( "MatchStartCountdownClass", uiGlobal.allMenus ) + file.matchStatusRuis = GetElementsByClassnameForMenus( "MatchmakingStatusRui", uiGlobal.allMenus ) + file.creditsAvailableElems = GetElementsByClassnameForMenus( "CreditsAvailableClass", uiGlobal.allMenus ) + + file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) + + AddEventHandlerToButton( menu, "GenUpButton", UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "Generation_Respawn" ) ) ) + + AddMenuVarChangeHandler( "focus", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isFullyConnected", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isPartyLeader", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isPrivateMatch", UpdateFooterOptions ) + #if DURANGO_PROG + AddMenuVarChangeHandler( "DURANGO_canInviteFriends", UpdateFooterOptions ) + AddMenuVarChangeHandler( "DURANGO_isJoinable", UpdateFooterOptions ) + AddMenuVarChangeHandler( "DURANGO_isGameFullyInstalled", UpdateFooterOptions ) + #elseif PS4_PROG + AddMenuVarChangeHandler( "PS4_canInviteFriends", UpdateFooterOptions ) + #elseif PC_PROG + AddMenuVarChangeHandler( "ORIGIN_isEnabled", UpdateFooterOptions ) + AddMenuVarChangeHandler( "ORIGIN_isJoinable", UpdateFooterOptions ) + #endif + + RegisterSignal( "BypassWaitBeforeRestartingMatchmaking" ) + RegisterSignal( "PutPlayerInMatchmakingAfterDelay" ) + RegisterSignal( "CancelRestartingMatchmaking" ) + RegisterSignal( "LeaveParty" ) +} + +void function SetupComboButtonTest( var menu ) +{ + ComboStruct comboStruct = ComboButtons_Create( menu ) + file.lobbyComboStruct = comboStruct + + int headerIndex = 0 + int buttonIndex = 0 + file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" ) + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) + + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) + + file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) + Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed ) + + // file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" ) + // Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode ) + + headerIndex++ + buttonIndex = 0 + file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" ) + file.customizeHeaderIndex = headerIndex + var pilotButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PILOT" ) + file.pilotButton = pilotButton + file.lobbyButtons.append( pilotButton ) + Hud_AddEventHandler( pilotButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditPilotLoadoutsMenu" ) ) ) + var titanButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_TITAN" ) + file.titanButton = titanButton + Hud_AddEventHandler( titanButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditTitanLoadoutsMenu" ) ) ) + file.boostsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BOOSTS" ) + Hud_AddEventHandler( file.boostsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "BurnCardMenu" ) ) ) + + headerIndex++ + buttonIndex = 0 + file.callsignHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_CALLSIGN" ) + file.bannerButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BANNER" ) + file.lobbyButtons.append( file.bannerButton ) + Hud_AddEventHandler( file.bannerButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignCardSelectMenu" ) ) ) + file.patchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PATCH" ) + Hud_AddEventHandler( file.patchButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignIconSelectMenu" ) ) ) + file.factionButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FACTION" ) + Hud_AddEventHandler( file.factionButton, UIE_CLICK, Lobby_CallsignButton3EventHandler ) + file.statsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STATS" ) + Hud_AddEventHandler( file.statsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStatsMenu" ) ) ) + + file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) + + headerIndex++ + buttonIndex = 0 + file.networksHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_NETWORKS" ) + file.inboxHeaderIndex = headerIndex + var networksInbox = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INBOX" ) + file.inboxButton = networksInbox + file.lobbyButtons.append( networksInbox ) + Hud_AddEventHandler( networksInbox, UIE_CLICK, OnInboxButton_Activate ) + var switchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_SWITCHCOMMUNITY" ) + Hud_AddEventHandler( switchButton, UIE_CLICK, OnSwitchButton_Activate ) + var browseButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_BROWSE_NETWORKS" ) + file.lobbyButtons.append( browseButton ) + Hud_AddEventHandler( browseButton, UIE_CLICK, OnBrowseNetworksButton_Activate ) + file.browseNetworkButton = browseButton + #if NETWORK_INVITE + file.inviteFriendsToNetworkButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#INVITE_FRIENDS" ) + file.lobbyButtons.append( file.inviteFriendsToNetworkButton ) + Hud_AddEventHandler( file.inviteFriendsToNetworkButton, UIE_CLICK, OnInviteFriendsToNetworkButton_Activate ) + #endif + + headerIndex++ + buttonIndex = 0 + file.storeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_STORE" ) + SetComboButtonHeaderTint( GetMenu( "LobbyMenu" ), headerIndex, true ) + file.storeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BROWSE" ) + Hud_AddEventHandler( file.storeButton, UIE_CLICK, OnStoreButton_Activate ) + file.storeNewReleasesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_NEW_RELEASES" ) + Hud_AddEventHandler( file.storeNewReleasesButton, UIE_CLICK, OnStoreNewReleasesButton_Activate ) + file.storeBundlesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BUNDLES" ) + Hud_AddEventHandler( file.storeBundlesButton, UIE_CLICK, OnStoreBundlesButton_Activate ) + + headerIndex++ + buttonIndex = 0 + file.settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + file.lobbyButtons.append( controlsButton ) + #if CONSOLE_PROG + var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) + Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) + #elseif PC_PROG + var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) + Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) + var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) + Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) + #endif + file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) + Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) + + comboStruct.navUpButtonDisabled = true + comboStruct.navDownButton = file.genUpButton + + ComboButtons_Finalize( comboStruct ) +} + +bool function MatchResultsExist() +{ + return true // TODO +} + +void function DoRoomInviteIfAllowed( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + if ( !DoesCurrentCommunitySupportInvites() ) + { + OnBrowseNetworksButton_Activate( button ) + return + } + + entity player = GetUIPlayer() + + if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) + { + DisplayMatchmakingPenaltyDialog( player ) + return + } + + SendOpenInvite( true ) + OpenSelectedPlaylistMenu() +} + +void function DisplayMatchmakingPenaltyDialog( entity player ) +{ + int minutesRemaining = int( ceil( Player_GetRemainingMatchmakingDelay( player ) / 60) ) + if ( minutesRemaining <= 1 ) + ServerCallback_GenericDialog( 30, 31, true ) + else if ( minutesRemaining == 2 ) + ServerCallback_GenericDialog( 30, 32, true ) + else if ( minutesRemaining == 3 ) + ServerCallback_GenericDialog( 30, 33, true ) + else if ( minutesRemaining == 4 ) + ServerCallback_GenericDialog( 30, 34, true ) + else if ( minutesRemaining == 5 ) + ServerCallback_GenericDialog( 30, 35, true ) + else + ServerCallback_GenericDialog( 30, 36, true ) +} + +void function CreatePartyAndInviteFriends() +{ + if ( CanInvite() ) + { + while ( !PartyHasMembers() && !AmIPartyLeader() ) + { + ClientCommand( "createparty" ) + WaitFrameOrUntilLevelLoaded() + } + InviteFriends( file.inviteFriendsButton ) + } + else + { + printt( "Not inviting friends - CanInvite() returned false" ); + } +} + +void function ToggleLobbyMode( var button ) +{ + Lobby_ToggleFDMode() +} + +void function Lobby_ToggleFDMode() +{ + Hud_SetFocused( file.findGameButton ) + ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) + file.isFDMode = !file.isFDMode + Lobby_RefreshButtons() +} + +void function Lobby_CallsignButton3EventHandler( var button ) +{ + if ( Lobby_IsFDMode() ) + { + AdvanceMenu( GetMenu( "ViewStatsMenu" ) ) + } + else + { + AdvanceMenu( GetMenu( "FactionChoiceMenu" ) ) + } +} + +void function InviteFriendsIfAllowed( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + entity player = GetUIPlayer() + if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) + { + DisplayMatchmakingPenaltyDialog( player ) + return + } + + #if PC_PROG + if ( !Origin_IsOverlayAvailable() ) + { + PopUpOriginOverlayDisabledDialog() + return + } + #endif + + thread CreatePartyAndInviteFriends() +} + +bool function CanInvite() +{ + if ( Player_NextAvailableMatchmakingTime( GetUIPlayer() ) > 0 ) + return false + +#if DURANGO_PROG + return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "DURANGO_canInviteFriends" ) && GetMenuVarBool( "DURANGO_isJoinable" ) && GetMenuVarBool( "DURANGO_isGameFullyInstalled" ) ) + #elseif PS4_PROG + return GetMenuVarBool( "PS4_canInviteFriends" ) + #elseif PC_PROG + return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "ORIGIN_isEnabled" ) && GetMenuVarBool( "ORIGIN_isJoinable" ) && Origin_IsOverlayAvailable() ) + #endif +} + +void function Lobby_RefreshButtons() +{ + bool fdMode = Lobby_IsFDMode() + var menu = GetMenu( "LobbyMenu" ) + + if ( GetTopNonDialogMenu() == GetMenu( "LobbyMenu" ) ) + { + if ( fdMode ) + UI_SetPresentationType( ePresentationType.FD_MAIN ) + else + UI_SetPresentationType( ePresentationType.DEFAULT ) + } + + string buttonString = fdMode ? "#MENU_LOBBY_SWITCH_DEFAULT" : "#MENU_LOBBY_SWITCH_FD" + // ComboButton_SetText( file.toggleMenuModeButton, buttonString ) + + buttonString = fdMode ? "" : "#MENU_TITLE_BOOSTS" + Hud_SetEnabled( file.boostsButton, !fdMode ) + ComboButton_SetText( file.boostsButton, buttonString ) + + buttonString = fdMode ? "#MENU_TITLE_STATS" : "#MENU_TITLE_FACTION" + ComboButton_SetText( file.factionButton, buttonString ) + + buttonString = fdMode ? "" : "#MENU_TITLE_STATS" + Hud_SetEnabled( file.statsButton, !fdMode ) + ComboButton_SetText( file.statsButton, buttonString ) + + buttonString = fdMode ? "#MENU_HEADER_PLAY_FD" : "#MENU_HEADER_PLAY" + SetComboButtonHeaderTitle( menu, 0, buttonString ) + + if ( fdMode ) + Hud_Hide( Hud_GetChild( menu, "ImgTopBar" ) ) + else + Hud_Show( Hud_GetChild( menu, "ImgTopBar" ) ) + + ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) + + if ( fdMode ) + { + Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "" ) + } + else + { + Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "#MULTIPLAYER" ) + } +} + +void function OnLobbyMenu_Open() +{ + Assert( IsConnected() ) + + // code will start loading DLC info from first party unless already done + InitDLCStore() + + thread UpdateCachedNewItems() + if ( file.putPlayerInMatchmakingAfterDelay ) + { + entity player = GetUIPlayer() + if (IsValid( player )) + { + string playlistToSearch = expect string( player.GetPersistentVar( "lastPlaylist" ) ) + string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() + if ( nextAutoPlaylist.len() > 0 ) + playlistToSearch = nextAutoPlaylist + + Lobby_SetFDModeBasedOnSearching( playlistToSearch ) + } + AdvanceMenu( GetMenu( "SearchMenu" ) ) + thread PutPlayerInMatchmakingAfterDelay() + file.putPlayerInMatchmakingAfterDelay = false + } + else if ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) ) + Lobby_SetFDMode( false ) + + thread UpdateLobbyUI() + thread LobbyMenuUpdate( GetMenu( "LobbyMenu" ) ) + + Hud_Show( file.chatroomMenu ) + + Lobby_RefreshButtons() + + if ( IsFullyConnected() ) + { + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + + while ( IsPersistenceAvailable() && (player.GetPersistentVarAsInt( "initializedVersion" ) < PERSISTENCE_INIT_VERSION) ) + { + WaitFrame() + } + if ( !IsPersistenceAvailable() ) + return + + // Clear hidden boosts + array boosts = GetAllItemsOfType( eItemTypes.BURN_METER_REWARD ) + foreach ( boost in boosts ) + { + if ( boost.hidden ) + { + ClearNewStatus( null, boost.ref ) + } + } + + UpdateCallsignElement( file.callsignCard ) + RefreshCreditsAvailable() + + bool emotesAreEnabled = EmotesEnabled() + // "Customize" + { + bool anyNewPilotItems = HasAnyNewPilotItems( player ) + bool anyNewTitanItems = HasAnyNewTitanItems( player ) + bool anyNewBoosts = HasAnyNewBoosts( player ) + bool anyNewCommsIcons = emotesAreEnabled ? HasAnyNewDpadCommsIcons( player ) : false + bool anyNewCustomizeHeader = (anyNewPilotItems || anyNewTitanItems || anyNewBoosts || anyNewCommsIcons) + + RuiSetBool( Hud_GetRui( file.customizeHeader ), "isNew", anyNewCustomizeHeader ) + ComboButton_SetNew( file.pilotButton, anyNewPilotItems ) + ComboButton_SetNew( file.titanButton, anyNewTitanItems ) + ComboButton_SetNew( file.boostsButton, anyNewBoosts ) + } + + // "Store" + { + bool storeIsNew = DLCStoreShouldBeMarkedAsNew() + RuiSetBool( Hud_GetRui( file.storeHeader ), "isNew", storeIsNew ) + ComboButton_SetNew( file.storeButton, storeIsNew ) + } + + // "Callsign" + { + bool anyNewBanners = HasAnyNewCallsignBanners( player ) + bool anyNewPatches = HasAnyNewCallsignPatches( player ) + bool anyNewFactions = HasAnyNewFactions( player ) && Lobby_IsFDMode() + bool anyNewCallsignHeader = (anyNewBanners || anyNewPatches || anyNewFactions) + + RuiSetBool( Hud_GetRui( file.callsignHeader ), "isNew", anyNewCallsignHeader ) + ComboButton_SetNew( file.bannerButton, anyNewBanners ) + ComboButton_SetNew( file.patchButton, anyNewPatches ) + ComboButton_SetNew( file.factionButton, anyNewFactions ) + } + + bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew ) + + TryUnlockSRSCallsign() + + Lobby_UpdateInboxButtons() + + if ( file.shouldAutoOpenFDMenu ) + { + file.shouldAutoOpenFDMenu = false + AdvanceMenu( GetMenu( GetPlaylistMenuName() ) ) + AdvanceMenu( GetMenu( "FDMenu" ) ) + } + } +} + +bool function DLCStoreShouldBeMarkedAsNew() +{ + if ( !IsFullyConnected() ) + return false + + if ( !IsPersistenceAvailable() ) + return false + + bool hasSeenStore = expect bool( GetPersistentVar( "hasSeenStore" ) ) + bool result = (!hasSeenStore) + return result +} + +void function LobbyMenuUpdate( var menu ) +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + while ( GetTopNonDialogMenu() == menu ) + { + bool inPendingOpenInvite = InPendingOpenInvite() + Hud_SetLocked( file.findGameButton, !IsPartyLeader() || inPendingOpenInvite ) + Hud_SetLocked( file.inviteRoomButton, IsOpenInviteVisible() || GetPartySize() > 1 || inPendingOpenInvite ) + Hud_SetLocked( file.inviteFriendsButton, inPendingOpenInvite ) + + bool canGenUp = false + if ( GetUIPlayer() ) + canGenUp = GetPersistentVarAsInt( "xp" ) == GetMaxPlayerXP() && GetGen() < MAX_GEN + + Hud_SetVisible( file.genUpButton, canGenUp ) + Hud_SetEnabled( file.genUpButton, canGenUp ) + + WaitFrame() + } +} + +void function SetNextAutoMatchmakingPlaylist( string playlistName ) +{ + file.nextAutoMatchmakingPlaylist = playlistName +} + +string function GetNextAutoMatchmakingPlaylist() +{ + return file.nextAutoMatchmakingPlaylist +} + +void function PutPlayerInMatchmakingAfterDelay() +{ + Signal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) + EndSignal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) + EndSignal( uiGlobal.signalDummy, "CancelRestartingMatchmaking" ) + EndSignal( uiGlobal.signalDummy, "LeaveParty" ) + EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + if ( AreWeMatchmaking() ) //Party member, party leader is already searching + return + + entity player = GetUIPlayer() + if ( !player ) + return + + string lastPlaylist = expect string( player.GetPersistentVar( "lastPlaylist" ) ) + + //Bump player out of match making if they were playing coliseum and are out of tickets. + if ( ("coliseum" == lastPlaylist) && Player_GetColiseumTicketCount( GetLocalClientPlayer() ) <= 0 ) + { + SetNextAutoMatchmakingPlaylist( "" ) + return + } + + // Need to know if you were a party member before the countdown starts in case you leave + bool wasAPartyMemberThatIsNotLeader = AmIPartyMember() + waitthread WaitBeforeRestartingMatchmaking() + // Only the leader should proceed to start matchmaking + if ( wasAPartyMemberThatIsNotLeader ) + return + + if ( !Console_HasPermissionToPlayMultiplayer() ) + { + ClientCommand( "disconnect" ) + return + } + + string playlistToSearch = lastPlaylist + string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() + if ( nextAutoPlaylist.len() > 0 ) + playlistToSearch = nextAutoPlaylist + + StartMatchmakingPlaylists( playlistToSearch ) +} + +void function WaitBeforeRestartingMatchmaking() +{ + Signal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) + EndSignal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) + + float timeToWait + + bool isPartyMemberThatIsNotLeader = AmIPartyMember() + SetPutPlayerInMatchmakingAfterDelay( !isPartyMemberThatIsNotLeader ) + + if ( isPartyMemberThatIsNotLeader ) + timeToWait = 99999 //HACK, JFS + else + timeToWait = GetCurrentPlaylistVarFloat( "wait_before_restarting_matchmaking_time", 30.0 ) + + float timeToEnd = Time() + timeToWait + + UpdateTimeToRestartMatchmaking( timeToEnd ) + + OnThreadEnd( + function() : ( ) + { + UpdateTimeToRestartMatchmaking( 0.0 ) + UpdateFooterOptions() + } + ) + + if ( isPartyMemberThatIsNotLeader ) + { + while( Time() < timeToEnd ) //Hack hack, JFS. No appropriate signals for StartMatchmaking() being called. Replace when code gives us notifications about it + { + if ( isPartyMemberThatIsNotLeader != ( AmIPartyMember() ) ) //Party Status changed. Party leader probably left? + break + + if ( AreWeMatchmaking() ) //Need to break out if Party Leader brings us into matchmaking + break + + WaitFrame() + } + + } + else + { + wait timeToWait + } +} + +void function OnLobbyMenu_Close() +{ + Signal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) +} + +void function OnLobbyMenu_NavigateBack() +{ + if ( ChatroomIsVisibleAndFocused() ) + { + foreach ( button in file.lobbyButtons ) + { + if ( Hud_IsVisible( button ) && Hud_IsEnabled( button ) && !Hud_IsLocked( button ) ) + { + Hud_SetFocused( button ) + return + } + } + } + + if ( InPendingOpenInvite() ) + LeaveOpenInvite() + else + LeaveDialog() +} + +function GameStartTime_Changed() +{ + UpdateGameStartTimeCounter() +} + +function ShowGameSummary_Changed() +{ + if ( level.ui.showGameSummary ) + uiGlobal.EOGOpenInLobby = true +} + +function UpdateGameStartTimeCounter() +{ + if ( level.ui.gameStartTime == null ) + return + + MatchmakingSetSearchText( "#STARTING_IN_LOBBY" ) + MatchmakingSetCountdownTimer( expect float( level.ui.gameStartTime + 0.0 ), true ) + + HideMatchmakingStatusIcons() +} + +bool function MatchmakingStatusShouldShowAsActiveSearch( string matchmakingStatus ) +{ + if ( matchmakingStatus == "#MATCHMAKING_QUEUED" ) + return true + if ( matchmakingStatus == "#MATCHMAKING_ALLOCATING_SERVER" ) + return true + if ( matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" ) + return true + + return false +} + +string function GetActiveSearchingPlaylist() +{ + if ( !IsConnected() ) + return "" + if ( !AreWeMatchmaking() ) + return "" + + string matchmakingStatus = GetMyMatchmakingStatus() + if ( !MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) + return "" + + string param1 = GetMyMatchmakingStatusParam( 1 ) + return param1 +} + +float function CalcMatchmakingWaitTime() +{ + float result = ((file.matchmakingStartTime > 0.01) ? (Time() - file.matchmakingStartTime) : 0.0) + return result +} + +float function GetMixtapeWaitTimeForPlaylist( string playlistName ) +{ + float maxWaitTime = float( GetPlaylistVarOrUseValue( playlistName, "mixtape_timeout", "0" ) ) + return maxWaitTime +} + +void function UpdateRestartMatchmakingStatus( float time ) +{ + if ( AmIPartyMember() ) + { + MatchmakingSetSearchText( "#MATCHMAKING_WAIT_ON_PARTY_LEADER_RESTARTING_MATCHMAKING" ) + } + else + { + string statusText = "#MATCHMAKING_WAIT_BEFORE_RESTARTING_MATCHMAKING" + string matchmakeNowText = "" + if ( uiGlobal.activeMenu == GetMenu( "SearchMenu" ) ) + matchmakeNowText = Localize( "#MATCHMAKING_WAIT_MATCHMAKE_NOW" ) + MatchmakingSetSearchText( statusText, matchmakeNowText ) + MatchmakingSetCountdownTimer( time, false ) + } +} + +void function UpdateMatchmakingStatus() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + OnThreadEnd( + function() : () + { + printt( "Hiding all matchmaking elems due to UpdateMatchmakingStatus thread ending" ) + + HideMatchmakingStatusIcons() + + MatchmakingSetSearchText( "" ) + MatchmakingSetCountdownTimer( 0.0, true ) + + MatchmakingSetSearchVisible( false ) + MatchmakingSetCountdownVisible( false ) + } + ) + + MatchmakingSetSearchVisible( true ) + MatchmakingSetCountdownVisible( true ) + + var lobbyMenu = GetMenu( "LobbyMenu" ) + var searchMenu = GetMenu( "SearchMenu" ) + var postGameMenu = GetMenu( "PostGameMenu" ) + + string lastActiveSearchingPlaylist + file.matchmakingStartTime = 0.0 + file.etaTime = 0 + file.etaMaxMinutes = int( GetCurrentPlaylistVarOrUseValue( "etaMaxMinutes", file.etaMaxMinutes ) ) + file.lastMixtapeMatchmakingStatus = "" + + while ( true ) + { + int lobbyType = GetLobbyTypeScript() + string matchmakingStatus = GetMyMatchmakingStatus() + bool isConnectingToMatch = matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" + + { + string activeSearchingPlaylist = GetActiveSearchingPlaylist() + if ( lastActiveSearchingPlaylist != activeSearchingPlaylist ) + { + if ( activeSearchingPlaylist.len() > 0 ) + { + lastActiveSearchingPlaylist = activeSearchingPlaylist + file.matchmakingStartTime = Time() + } + else + { + lastActiveSearchingPlaylist = "" + file.matchmakingStartTime = 0.0 + } + } + + if ( isConnectingToMatch && (matchmakingStatus != file.lastMixtapeMatchmakingStatus) ) + { + EmitUISound( MATCHMAKING_AUDIO_CONNECTING ) + + int mixtape_version = GetMixtapeMatchmakingVersion() + if ( IsMixtapeVersionNew() ) + LogMixtapeHasNew( mixtape_version ) + } + + file.lastMixtapeMatchmakingStatus = matchmakingStatus + } + + if ( level.ui.gameStartTime != null || lobbyType == eLobbyType.PRIVATE_MATCH ) + { + if ( level.ui.gameStartTimerComplete ) + { + MatchmakingSetSearchText( matchmakingStatus, GetMyMatchmakingStatusParam( 1 ), GetMyMatchmakingStatusParam( 2 ), GetMyMatchmakingStatusParam( 3 ), GetMyMatchmakingStatusParam( 4 ) ) + } + + if ( uiGlobal.activeMenu == searchMenu ) + CloseActiveMenu() + } + else if ( GetTimeToRestartMatchMaking() > 0 ) + { + UpdateRestartMatchmakingStatus( GetTimeToRestartMatchMaking() ) + } + else if ( level.ui.gameStartTime == null ) + { + MatchmakingSetCountdownTimer( 0.0, true ) + MatchmakingSetSearchText( "" ) + HideMatchmakingStatusIcons() + + if ( !IsConnected() || !AreWeMatchmaking() ) + { + if ( uiGlobal.activeMenu == searchMenu ) + CloseActiveMenu() + } + else + { + ShowMatchmakingStatusIcons() + + if ( GetActiveMenu() == lobbyMenu && !IsMenuInMenuStack( searchMenu ) ) + { + CloseAllDialogs() + AdvanceMenu( searchMenu ) + } + + var statusEl = Hud_GetChild( searchMenu, "MatchmakingStatusBig" ) + if ( matchmakingStatus == "#MATCH_NOTHING" ) + { + Hud_Hide( statusEl ) + } + else if ( MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) + { + string playlistName = GetMyMatchmakingStatusParam( 1 ) + int etaSeconds = int( GetMyMatchmakingStatusParam( 2 ) ) + int mapIdx = int( GetMyMatchmakingStatusParam( 3 ) ) + int modeIdx = int( GetMyMatchmakingStatusParam( 4 ) ) + string playlistList = GetMyMatchmakingStatusParam( 5 ) + + { + string statusText = Localize( "#MATCHMAKING_PLAYLISTS" ) + RuiSetString( Hud_GetRui( statusEl ), "statusText", statusText ) + for ( int idx = 1; idx <= 5; ++idx ) + RuiSetString( Hud_GetRui( statusEl ), ("bulletPointText" + idx), "" ) + + const int MAX_SHOWN_PLAYLISTS = 9 + array< string > searchingPlaylists = split( playlistList, "," ) + int searchingCount = minint( searchingPlaylists.len(), MAX_SHOWN_PLAYLISTS ) + RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", searchingCount ) + for( int idx = 0; idx < searchingCount; ++idx ) + { + asset playlistThumbnail = GetPlaylistThumbnailImage( searchingPlaylists[idx] ) + RuiSetImage( Hud_GetRui( statusEl ), format( "playlistIcon%d", idx ), playlistThumbnail ) + } + } + + Hud_Show( statusEl ) + + if ( mapIdx > -1 && modeIdx > -1 ) + { + if ( file.preCacheInfo.playlistName != playlistName || file.preCacheInfo.mapIdx != mapIdx || file.preCacheInfo.modeIdx != modeIdx ) + { + file.preCacheInfo.playlistName = playlistName + file.preCacheInfo.mapIdx = mapIdx + file.preCacheInfo.modeIdx = modeIdx + } + } + + string etaStr = "" + if ( !etaSeconds && !isConnectingToMatch ) + { + matchmakingStatus = "#MATCHMAKING_SEARCHING_FOR_MATCH" + } + else + { + int now = int( Time() ) + int etaTime = now + etaSeconds + if ( !file.etaTime || etaTime < file.etaTime ) + file.etaTime = etaTime + + int etaSeconds = file.etaTime - now + if ( etaSeconds <= 0 ) + file.etaTime = etaTime + + etaSeconds = file.etaTime - now + if ( etaSeconds <= 90 ) + { + etaStr = Localize( "#MATCHMAKING_ETA_SECONDS", etaSeconds ) + } + else + { + int etaMinutes = int( ceil( etaSeconds / 60.0 ) ) + if ( etaMinutes < file.etaMaxMinutes ) + etaStr = Localize( "#MATCHMAKING_ETA_MINUTES", etaMinutes ) + else + etaStr = Localize( "#MATCHMAKING_ETA_UNKNOWN", etaMinutes ) + } + } + + MatchmakingSetSearchText( matchmakingStatus, etaStr ) + } + else + { + Hud_Show( statusEl ) + RuiSetString( Hud_GetRui( statusEl ), "statusText", "" ) + RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", 0 ) + } + } + } + + WaitFrameOrUntilLevelLoaded() + } +} + +void function UpdateAnnouncementDialog() +{ + while ( IsLobby() && IsFullyConnected() ) + { + // Only safe on these menus. Not safe if these variables are true because they indicate the search menu or postgame menu are going to be opened. + if ( ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) || uiGlobal.activeMenu == GetMenu( "PrivateLobbyMenu" ) ) && !file.putPlayerInMatchmakingAfterDelay && !uiGlobal.EOGOpenInLobby ) + { + entity player = GetUIPlayer() + + // Only initialize here, CloseAnnouncementDialog() handles setting it when closing + if ( uiGlobal.announcementVersionSeen == -1 ) + uiGlobal.announcementVersionSeen = player.GetPersistentVarAsInt( "announcementVersionSeen" ) + + int announcementVersion = GetConVarInt( "announcementVersion" ) + if ( announcementVersion > uiGlobal.announcementVersionSeen ) + { + OpenAnnouncementDialog() + } + else if ( uiGlobal.activeMenu != "AnnouncementDialog" && ShouldShowEmotesAnnouncement( player ) ) + { + OpenCommsIntroDialog() + } + } + + WaitFrame() + } +} + +bool function CurrentMenuIsPVEMenu() +{ + var topMenu = GetTopNonDialogMenu() + if ( topMenu == null ) + return false + + return (uiGlobal.menuData[topMenu].isPVEMenu) +} + +void function RefreshCreditsAvailable( int creditsOverride = -1 ) +{ + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + if ( !IsPersistenceAvailable() ) + return + + int credits = creditsOverride >= 0 ? creditsOverride : GetAvailableCredits( GetLocalClientPlayer() ) + string pveTitle = "" + int pveCredits = 0 + bool isPVE = CurrentMenuIsPVEMenu() + if ( isPVE ) + { + TitanLoadoutDef loadout = GetCachedTitanLoadout( uiGlobal.editingLoadoutIndex ) + pveCredits = GetAvailableFDUnlockPoints( player, loadout.titanClass ) + pveTitle = GetTitanLoadoutName( loadout ) + } + + foreach ( elem in file.creditsAvailableElems ) + { + SetUIPlayerCreditsInfo( elem, credits, GetLocalClientPlayer().GetXP(), GetGen(), GetLevel(), GetNextLevel( GetLocalClientPlayer() ), isPVE, pveCredits, pveTitle ) + } +} + +void function SetUIPlayerCreditsInfo( var infoElement, int credits, int xp, int gen, int level, int nextLevel, bool isPVE, int pveCredits, string pveTitle ) +{ + var rui = Hud_GetRui( infoElement ) + RuiSetInt( rui, "credits", credits ) + RuiSetString( rui, "nameText", GetPlayerName() ) + + RuiSetBool( rui, "isPVE", isPVE ) + if ( isPVE ) + { + RuiSetInt( rui, "pveCredits", pveCredits ) + RuiSetString( rui, "pveTitle", pveTitle ) + } + + if ( xp == GetMaxPlayerXP() && gen < MAX_GEN ) + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", Localize( "#REGEN_AVAILABLE" ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) + RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) + } + else if ( xp == GetMaxPlayerXP() && gen == MAX_GEN ) + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", Localize( "#MAX_GEN" ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) + RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) + } + else + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", PlayerXPDisplayGenAndLevel( gen, nextLevel ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level ) ) + RuiSetInt( rui, "filledLevelPips", GetXPFilledPipsForXP( xp ) ) + } + + CallsignIcon callsignIcon = PlayerCallsignIcon_GetActive( GetLocalClientPlayer() ) + + RuiSetImage( rui, "callsignIcon", callsignIcon.image ) +} + +void function BigPlayButton1_Activate( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + SendOpenInvite( false ) + OpenSelectedPlaylistMenu() +} + +function EnableButton( button ) +{ + Hud_SetEnabled( button, true ) + Hud_Show( button ) +} + +function DisableButton( button ) +{ + Hud_SetEnabled( button, false ) + Hud_Hide( button ) +} + +void function OpenSelectedPlaylistMenu() +{ + if ( Lobby_IsFDMode() ) + { + AdvanceMenu( GetMenu( "FDMenu" ) ) + } + else + { + string playlistMenuName = GetPlaylistMenuName() + AdvanceMenu( GetMenu( playlistMenuName ) ) + } +} + +function UpdateLobbyUI() +{ + if ( uiGlobal.updatingLobbyUI ) + return + uiGlobal.updatingLobbyUI = true + + thread UpdateLobbyType() + thread UpdateMatchmakingStatus() + thread UpdateChatroomThread() + thread UpdateInviteJoinButton() + thread UpdateInviteFriendsToNetworkButton() + thread UpdatePlayerInfo() + + if ( uiGlobal.menuToOpenFromPromoButton != null ) + { + // Special case because this menu needs a few properties set before opening + + if ( IsStoreMenu( uiGlobal.menuToOpenFromPromoButton ) ) + { + string menuName = expect string( uiGlobal.menuToOpenFromPromoButton._name ) + + void functionref() preOpenfunc = null + if ( uiGlobal.menuToOpenFromPromoButton == GetMenu( "StoreMenu_WeaponSkins" ) ) // Hardcoded special case for now + preOpenfunc = DefaultToDLC11WeaponWarpaintBundle + + OpenStoreMenu( [ menuName ], preOpenfunc ) + } + else + { + AdvanceMenu( uiGlobal.menuToOpenFromPromoButton ) + } + + uiGlobal.menuToOpenFromPromoButton = null + } + else if ( uiGlobal.EOGOpenInLobby ) + { + EOGOpen() + } + + WaitSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + uiGlobal.updatingLobbyUI = false +} + +void function UpdateInviteJoinButton() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + var menu = GetMenu( "LobbyMenu" ) + + while ( true ) + { + if ( DoesCurrentCommunitySupportInvites() ) + ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_INVITE_ROOM" ) ) + else + ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_JOIN_NETWORK" ) ) + + WaitFrame() + } +} + +void function UpdateInviteFriendsToNetworkButton() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + var menu = GetMenu( "LobbyMenu" ) + + while ( true ) + { + bool areInvitesToNetworkNotAllowed = !DoesCurrentCommunitySupportChat() + if ( areInvitesToNetworkNotAllowed || ( IsCurrentCommunityInviteOnly() && !AreWeAdminInCurrentCommunity() ) ) + DisableButton( file.inviteFriendsToNetworkButton ) + else + EnableButton( file.inviteFriendsToNetworkButton ) + + WaitFrame() + } +} + +function UpdateLobbyType() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + var menu = GetMenu( "LobbyMenu" ) + int lobbyType + local lastType + local partySize + local lastPartySize + local debugArray = [ "SOLO", "PARTY_LEADER", "PARTY_MEMBER", "MATCH", "PRIVATE_MATCH" ] // Must match enum + + WaitFrameOrUntilLevelLoaded() + + while ( true ) + { + lobbyType = GetLobbyTypeScript() + partySize = GetPartySize() + + if ( IsConnected() && ((lobbyType != lastType) || (partySize != lastPartySize)) ) + { + if ( lastType == null ) + printt( "Lobby lobbyType changing from:", lastType, "to:", debugArray[lobbyType] ) + else + printt( "Lobby lobbyType changing from:", debugArray[lastType], "to:", debugArray[lobbyType] ) + + local animation = null + + switch ( lobbyType ) + { + case eLobbyType.SOLO: + animation = "SoloLobby" + break + + case eLobbyType.PARTY_LEADER: + animation = "PartyLeaderLobby" + break + + case eLobbyType.PARTY_MEMBER: + animation = "PartyMemberLobby" + break + + case eLobbyType.MATCH: + animation = "MatchLobby" + break + + case eLobbyType.PRIVATE_MATCH: + animation = "PrivateMatchLobby" + break + } + + if ( animation != null ) + { + menu.RunAnimationScript( animation ) + } + + // Force the animation scripts (which have zero duration) to complete before anything can cancel them. + ForceUpdateHUDAnimations() + + lastType = lobbyType + lastPartySize = partySize + } + + WaitFrameOrUntilLevelLoaded() + } +} + +void function UICodeCallback_CommunityUpdated() +{ + Community_CommunityUpdated() + UpdateChatroomUI() +} + +void function UICodeCallback_FactionUpdated() +{ + printt( "Faction changed! to " + GetCurrentFaction() ); +} + +void function UICodeCallback_SetupPlayerListGenElements( table params, int gen, int rank, bool isPlayingRanked, int pilotClassIndex ) +{ + params.image = "" + params.label = "" + params.imageOverlay = "" +} + +float function GetTimeToRestartMatchMaking() +{ + return file.timeToRestartMatchMaking +} + +void function UpdateTimeToRestartMatchmaking( float time )//JFS: This uses UI time instead of server time, which leads to awkwardness in MatchmakingSetCountdownTimer() and the rui involved +{ + file.timeToRestartMatchMaking = time + + if ( time > 0 ) + { + UpdateRestartMatchmakingStatus( time ) + ShowMatchmakingStatusIcons() + } + else + { + MatchmakingSetSearchText( "" ) + MatchmakingSetCountdownTimer( 0.0, true ) + HideMatchmakingStatusIcons() + } +} + +void function HideMatchmakingStatusIcons() +{ + foreach ( element in file.searchIconElems ) + Hud_Hide( element ) + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "iconVisible", false ) +} + +void function ShowMatchmakingStatusIcons() +{ + //foreach ( element in file.searchIconElems ) + // Hud_Show( element ) + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "iconVisible", true ) +} + +void function MatchmakingSetSearchVisible( bool state ) +{ + foreach ( el in file.searchTextElems ) + { + //if ( state ) + // Hud_Show( el ) + //else + Hud_Hide( el ) + } + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "statusVisible", state ) +} + +void function MatchmakingSetSearchText( string searchText, var param1 = "", var param2 = "", var param3 = "", var param4 = "" ) +{ + foreach ( el in file.searchTextElems ) + { + Hud_SetText( el, searchText, param1, param2, param3, param4 ) + } + + foreach ( element in file.matchStatusRuis ) + { + RuiSetBool( Hud_GetRui( element ), "statusHasText", searchText != "" ) + + RuiSetString( Hud_GetRui( element ), "statusText", Localize( searchText, param1, param2, param3, param4 ) ) + } +} + + +void function MatchmakingSetCountdownVisible( bool state ) +{ + foreach ( el in file.matchStartCountdownElems ) + { + //if ( state ) + // Hud_Show( el ) + //else + Hud_Hide( el ) + } + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "timerVisible", state ) +} + +void function MatchmakingSetCountdownTimer( float time, bool useServerTime = true ) //JFS: useServerTime bool is awkward, comes from level.ui.gameStartTime using server time and UpdateTimeToRestartMatchmaking() uses UI time. +{ + foreach ( element in file.matchStatusRuis ) + { + RuiSetBool( Hud_GetRui( element ), "timerHasText", time != 0.0 ) + RuiSetGameTime( Hud_GetRui( element ), "startTime", Time() ) + RuiSetBool( Hud_GetRui( element ), "useServerTime", useServerTime ) + RuiSetGameTime( Hud_GetRui( element ), "timerEndTime", time ) + } +} + +void function OnLobbyLevelInit() +{ + UpdateCallsignElement( file.callsignCard ) + RefreshCreditsAvailable() +} + +function UpdatePlayerInfo() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + var menu = GetMenu( "LobbyMenu" ) + + WaitFrameOrUntilLevelLoaded() + + while ( true ) + { + RefreshCreditsAvailable() + WaitFrame() + } +} + +void function TryUnlockSRSCallsign() +{ + if ( Script_IsRunningTrialVersion() ) + return + + int numCallsignsToUnlock = 0 + + if ( GetTotalLionsCollected() >= GetTotalLionsInGame() ) + numCallsignsToUnlock = 3 + else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_2_COUNT ) + numCallsignsToUnlock = 2 + else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_1_COUNT ) + numCallsignsToUnlock = 1 + else + numCallsignsToUnlock = 0 + + if ( numCallsignsToUnlock > 0 ) + ClientCommand( "UnlockSRSCallsign " + numCallsignsToUnlock ) +} + +void function SetPutPlayerInMatchmakingAfterDelay( bool value ) +{ + file.putPlayerInMatchmakingAfterDelay = value +} + +void function OnStoreButton_Activate( var button ) +{ + LaunchGamePurchaseOrDLCStore() +} + +void function OnStoreNewReleasesButton_Activate( var button ) +{ + //LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_NewReleases" ] ) + LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_WeaponSkins" ] ) +} + +void function OnStoreBundlesButton_Activate( var button ) +{ + LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_Sales" ] ) +} + +void function OnDpadCommsButton_Activate( var button ) +{ + AdvanceMenu( GetMenu( "EditDpadCommsMenu" ) ) +} + +void function OpenCommsIntroDialog() +{ + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#DPAD_COMMS_ANNOUNCEMENT_HEADER" + dialogData.ruiMessage.message = "#DPAD_COMMS_ANNOUNCEMENT" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B1" , OpenDpadCommsMenu ) + AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B2" ) + + AddDialogPCBackButton( dialogData ) + AddDialogFooter( dialogData, "#A_BUTTON_ACCEPT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) + + ClientCommand( "SetCommsIntroSeen" ) +} + +void function OpenDpadCommsMenu() +{ + OnDpadCommsButton_Activate( null ) +} + +bool function ShouldShowEmotesAnnouncement( entity player ) +{ + if ( !EmotesEnabled() ) + return false + + if ( player.GetPersistentVarAsInt( "numTimesUsedComms" ) > 2 ) + return false + + if ( player.GetPersistentVar( "hasBeenIntroducedToComms" ) ) + return false + + #if !DEV + if ( PlayerGetRawLevel( player ) <= 2 ) + return false + #endif + + return true +} + +void function Lobby_SetFDMode( bool mode ) +{ + file.isFDMode = mode +} + +//Function returns whether lobby is currently in "Frontier Defense" lobby mode. +bool function Lobby_IsFDMode() +{ + return file.isFDMode +} + +void function Lobby_SetAutoFDOpen( bool autoFD ) +{ + Lobby_SetFDMode( autoFD ) + file.shouldAutoOpenFDMenu = autoFD +} + +void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) +{ + array< string > searchingPlaylists = split( playlistToSearch, "," ) + + bool isFDMode = false + int searchingCount = searchingPlaylists.len() + for( int idx = 0; idx < searchingCount; ++idx ) + { + isFDMode = isFDMode || IsFDMode( searchingPlaylists[idx] ) + if ( isFDMode ) + break + } + + Lobby_SetFDMode( isFDMode ) +} + +void function pulseRefresh +{ + pulseGetData() +} \ No newline at end of file From c41173ad13af7c34bd3f4b806362835865ee24af Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:05:00 +0200 Subject: [PATCH 20/71] Delete menu_stats.nut --- mod/scripts/vscripts/ui/menu_stats.nut | 53 -------------------------- 1 file changed, 53 deletions(-) delete mode 100644 mod/scripts/vscripts/ui/menu_stats.nut diff --git a/mod/scripts/vscripts/ui/menu_stats.nut b/mod/scripts/vscripts/ui/menu_stats.nut deleted file mode 100644 index 2cae746..0000000 --- a/mod/scripts/vscripts/ui/menu_stats.nut +++ /dev/null @@ -1,53 +0,0 @@ - -global function InitViewStatsMenu - -struct{ - array allMaps -} file - -void function InitViewStatsMenu() -{ - var menu = GetMenu( "ViewStatsMenu" ) - - AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnViewStats_Open ) - - var button = Hud_GetChild( menu, "BtnOverview" ) - SetButtonRuiText( button, Localize( "#STATS_OVERVIEW" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Overview_Menu" ) ) ) - - button = Hud_GetChild( menu, "BtnTime" ) - SetButtonRuiText( button, Localize( "#STATS_TIME" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Time_Menu" ) ) ) - - button = Hud_GetChild( menu, "BtnPilotWeapons" ) - SetButtonRuiText( button, Localize( "#STATS_PILOT_WEAPONS" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Weapons_Menu" ) ) ) - - button = Hud_GetChild( menu, "BtnTitans" ) - SetButtonRuiText( button, Localize( "#STATS_TITANS" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Titans_Menu" ) ) ) - - button = Hud_GetChild( menu, "BtnMaps" ) - SetButtonRuiText( button, Localize( "#STATS_MAPS" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Maps_Menu" ) ) ) - - button = Hud_GetChild( menu, "BtnMisc" ) - SetButtonRuiText( button, Localize( "#STATS_MISC" ) ) - AddButtonEventHandler( button, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStats_Misc_Menu" ) ) ) - - AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) - AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) -} - -void function OnViewStats_Open() -{ - foreach(elemNum in file.allMaps){ - string mapName = expect string(file.allMaps[ elemNum ]) - fetchGamemodeStatsFromToneAPI(mapName) - } - GetStatsFromToneAPI() - UI_SetPresentationType( ePresentationType.DEFAULT ) - - //UpdateViewStatsKillsMenu() - //UpdateViewStatsDistanceMenu() -} From 84ab278d927f8424988c9e751b938a6f50b41857 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:48:40 +0200 Subject: [PATCH 21/71] Update nut files to work with refactor --- mod/scripts/vscripts/pulse-common-func.gnut | 33 ++++++++++++++----- mod/scripts/vscripts/pulse.gnut | 11 ++++--- mod/scripts/vscripts/ui/menu_stats_maps.nut | 18 +++++----- .../vscripts/ui/menu_stats_overview.nut | 28 ++++++++-------- mod/scripts/vscripts/ui/menu_stats_time.nut | 10 +++--- mod/scripts/vscripts/ui/menu_stats_titans.nut | 2 +- .../vscripts/ui/menu_stats_utility.nut | 10 +++--- .../vscripts/ui/menu_stats_weapons.nut | 6 ++-- 8 files changed, 66 insertions(+), 52 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index 6bf7d12..e64229f 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -13,17 +13,23 @@ void function pulsePrintt(string content) //Prints whatever we want printed with printt(format("%s " + content, pulsePrefix)) } -bool function pulseRequestData(string givenURL, table parameterTable) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. +bool function pulseRequestData(string givenURL, table parameterTable, string tablepath) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > params foreach (parameter in paramTable) { params[parameter] <- [paramTable(parameter)] } - void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (params, tablepath) { table DecodedJSON = DecodeJSON(response.body) - pulseData += DecodedJSON + if (params["map"]) + { + table map[params["map"]] <- DecodedJSON + pulseData[tablepath] <- map + } else { + pulseData[tablepath] <- DecodedJSON + } } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) { @@ -32,16 +38,25 @@ bool function pulseRequestData(string givenURL, table parameterTable) //Gets dat return NSHttpGet(givenURL, params, onSuccess, onFailure) } -int function pulseParse(string parameter, string key, string value) +int function pulseParse(string parameter, string key, string value, string opt = "none") { - if (key == "maps") { + if (key == "maps") + { parameter = parameter.slice(3) } - if (key in pulseData) { + if (key in pulseData) + { table keyandvalTable = expect table(pulseData[key]) - if (parameter in keyandvalTable) { - table valTable = expect table(keyandvalTable[parameter]) - return expect int(valTable[value]) + if (parameter in keyandvalTable) + { + table valTable = expect table(keyandvalTable[parameter]) + if (opt == "none") + { + return expect int(valTable[value]) + } else { + actualValTable = expect table(valTable[value]) + return expect int(actualValTable[opt]) + } } } return 0 diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index e3538de..fa965bd 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -16,12 +16,13 @@ void function pulseGetData() { string URL = GetConVarString("ToneURL") array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] - pulseRequestData(URL + URLpath[1], ["uid" = NSGetLocalPlayerUID()]) - pulseRequestData(URL + URLpath[2], ["uid" = "!" + NSGetLocalPlayerUID()]) - pulseRequestData(URL + URLpath[3], ["uid" = NSGetLocalPlayerUID()]) + array tablepath = ["weaponsLocal", "weaponsGlobal", "gamemodesAll", "gamemodesSeparated", "maps"] + pulseRequestData(URL + URLpath[1], ["uid" = NSGetLocalPlayerUID()], tablepath[1]) + pulseRequestData(URL + URLpath[2], ["uid" = "!" + NSGetLocalPlayerUID()], tablepath[2]) + pulseRequestData(URL + URLpath[3], ["uid" = NSGetLocalPlayerUID()], tablepath[3]) foreach (map in file.allMaps) { - pulseRequestData(URL + URLpath[4], ["uid" = NSGetLocalPlayerUID(), "map" = map.slice(3)]) + pulseRequestData(URL + URLpath[4], ["uid" = NSGetLocalPlayerUID(), "map" = map.slice(3)], tablepath[4]) } - pulseRequestData(URL + URLpath[5], ["uid" = NSGetLocalPlayerUID()]) + pulseRequestData(URL + URLpath[5], ["uid" = NSGetLocalPlayerUID()], tablepath[5]) } \ No newline at end of file diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mod/scripts/vscripts/ui/menu_stats_maps.nut index 49d72b4..67d1d7f 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -140,8 +140,6 @@ void function UpdateStatsForMap( string mapName ) Hud_SetText( Hud_GetChild( file.menu, "WeaponName" ), GetMapDisplayName( mapName ) ) - fetchGamemodeStatsFromToneAPI(mapName) - // Image var imageElem = Hud_GetRui( Hud_GetChild( file.menu, "WeaponImageLarge" ) ) RuiSetImage( imageElem, "basicImage", GetMapImageForMapName( mapName ) ) @@ -155,16 +153,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(mapName, "maps", "kills") ) + SetStatsLabelValue( file.menu, "KillsValue0", pulseParse(mapName, "maps", "kills") ) SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(mapName, "maps", "deaths") ) + SetStatsLabelValue( file.menu, "KillsValue1", pulseParse(mapName, "maps", "deaths") ) SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(getFromToneAPI(mapName, "maps", "total_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse(mapName, "maps", "total_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(getFromToneAPI(mapName, "maps", "max_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse(mapName, "maps", "max_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) SetStatsLabelValue( file.menu, "KillsValue4", "--" ) @@ -193,10 +191,10 @@ void function UpdateStatsForMap( string mapName ) for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( mapName in globalToneAPIGamemodeMapData && modeName in globalToneAPIGamemodeMapData[mapName] ) + if ( mapName in pulseData && modeName in pulseData[mapName] ) { float modePlayedTime = 0 - modePlayedTime = float(globalToneAPIGamemodeMapData[mapName][modeName]) + modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", modeName, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -204,10 +202,10 @@ void function UpdateStatsForMap( string mapName ) } foreach (string key, array value in customGamemodeList) { - if ( mapName in globalToneAPIGamemodeMapData && key in globalToneAPIGamemodeMapData[mapName]) + if ( mapName in pulseData && key in pulseData[mapName]) { float modePlayedTime = 0 - modePlayedTime = float(globalToneAPIGamemodeMapData[mapName][key]) + modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", modeName, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } diff --git a/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mod/scripts/vscripts/ui/menu_stats_overview.nut index 4d3d9d8..43810b2 100644 --- a/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -52,7 +52,7 @@ void function GetTitanKills( string titanName ) foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - titanKillData[weaponRef] <- getFromToneAPI(weaponRef, "weaponsLocal", "kills") + titanKillData[weaponRef] <- pulseParse(weaponRef, "weaponsLocal", "kills") } } @@ -332,7 +332,7 @@ function UpdateViewStatsOverviewMenu() if (key in titanKillData) { continue } else { - killsAsPilot += getFromToneAPI(string(key), "weaponsLocal", "kills") + killsAsPilot += pulseParse(string(key), "weaponsLocal", "kills") } } @@ -407,27 +407,27 @@ function UpdateViewStatsOverviewMenu() Hud_SetText( GetElem( file.menu, "KillsAsPilotValue0" ), string( killsAsPilot ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsPilot" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue2" ), string( GetPlayerStatInt( player, "kills_stats", "totalNPC" ) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( getFromToneAPI("pilot_emptyhanded", "weaponsLocal", "kills") ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( getFromToneAPI("human_execution", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( pulseParse("pilot_emptyhanded", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( pulseParse("human_execution", "weaponsLocal", "kills") ) ) // Hud_SetText( GetElem( file.menu, "KillsAsPilotValue5" ), string( GetPlayerStatInt( player, "kills_stats", "titanFallKill" ) ) ) var titanMeleeKills = 0 - titanMeleeKills += getFromToneAPI("titan_punch_ion", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_punch_scorch", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_punch_northstar", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_sword", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_punch_tone", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_punch_legion", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("titan_punch_vanguard", "weaponsLocal", "kills") - titanMeleeKills += getFromToneAPI("auto_titan_melee", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_ion", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_scorch", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_northstar", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_sword", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_tone", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_legion", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("titan_punch_vanguard", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("auto_titan_melee", "weaponsLocal", "kills") - var titanExecutions = getFromToneAPI("titan_execution", "weaponsLocal", "kills") + var titanExecutions = pulseParse("titan_execution", "weaponsLocal", "kills") Hud_SetText( GetElem( file.menu, "KillsAsTitanValue0" ), string( killsAsTitan ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsTitan" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue2" ), string( titanExecutions ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue3" ), string( titanMeleeKills ) ) - Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( getFromToneAPI("damagedef_titan_step", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( pulseParse("damagedef_titan_step", "weaponsLocal", "kills") ) ) } function PlotKDPointsOnGraph( menu, graphIndex, values, dottedAverage ) diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mod/scripts/vscripts/ui/menu_stats_time.nut index 3030481..157e4bd 100644 --- a/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -49,7 +49,7 @@ float function GetTitanKills( string titanName) float weaponKills = 0 foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - weaponKills += float(getFromToneAPI(weaponRef, "weaponsLocal", "kills")) + weaponKills += float(pulseParse(weaponRef, "weaponsLocal", "kills")) } return weaponKills } @@ -160,10 +160,10 @@ void function UpdateViewStatsTimeMenu() for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( getFromToneAPI(modeName, "gamemodes", "kills") != 0 ) + if ( pulseParse(modeName, "gamemodes", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(getFromToneAPI(modeName, "gamemodes", "kills")) + modePlayedTime = float(pulseParse(modeName, "gamemodes", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -171,10 +171,10 @@ void function UpdateViewStatsTimeMenu() } foreach (string key, array value in customGamemodeList) { - if ( getFromToneAPI(key, "gamemodes", "kills") != 0 ) + if ( pulseParse(key, "gamemodes", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(getFromToneAPI(key, "gamemodes", "kills")) + modePlayedTime = float(pulseParse(key, "gamemodes", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } diff --git a/mod/scripts/vscripts/ui/menu_stats_titans.nut b/mod/scripts/vscripts/ui/menu_stats_titans.nut index e9cd6f8..f401e10 100644 --- a/mod/scripts/vscripts/ui/menu_stats_titans.nut +++ b/mod/scripts/vscripts/ui/menu_stats_titans.nut @@ -175,7 +175,7 @@ void function UpdateStatsForTitan( string titanRef, int loadoutIndex ) int aiKills foreach ( weaponRef in file.titanStatLoadout[ titanRef ] ) { - totalKills += getFromToneAPI(weaponRef, "weaponsLocal", "kills") + totalKills += pulseParse(weaponRef, "weaponsLocal", "kills") pilotKills += GetPlayerStatInt( player, "weapon_kill_stats", "pilots", weaponRef ) titanKills += GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) aiKills += GetPlayerStatInt( player, "weapon_kill_stats", "ai", weaponRef ) diff --git a/mod/scripts/vscripts/ui/menu_stats_utility.nut b/mod/scripts/vscripts/ui/menu_stats_utility.nut index 29be870..c53e458 100644 --- a/mod/scripts/vscripts/ui/menu_stats_utility.nut +++ b/mod/scripts/vscripts/ui/menu_stats_utility.nut @@ -338,7 +338,7 @@ table function GetOverviewWeaponData() if ( !PersistenceEnumValueIsValid( "loadoutWeaponsAndAbilities", weaponName ) ) continue - int val = getFromToneAPI(weaponName, "weaponsLocal", "kills") + int val = pulseParse(weaponName, "weaponsLocal", "kills") if ( val > Table[ "most_kills" ].val ) { Table[ "most_kills" ].ref = weaponName @@ -346,7 +346,7 @@ table function GetOverviewWeaponData() Table[ "most_kills" ].val = val } - int nval = getFromToneAPI(weaponName, "weaponsLocal", "deaths") + int nval = pulseParse(weaponName, "weaponsLocal", "deaths") if ( nval > Table[ "nemesis_weapon" ].val ) { Table[ "nemesis_weapon" ].ref = weaponName @@ -357,9 +357,9 @@ table function GetOverviewWeaponData() float kdval = 0 float kval = 0 float dval = 0 - if( getFromToneAPI(weaponName, "weaponsLocal", "kills") != 0 && getFromToneAPI(weaponName, "weaponsLocal", "deaths_while_equipped") != 0){ - kval = float(getFromToneAPI(weaponName, "weaponsLocal", "kills")) - dval = float(getFromToneAPI(weaponName, "weaponsLocal", "deaths_while_equipped")) + if( pulseParse(weaponName, "weaponsLocal", "kills") != 0 && pulseParse(weaponName, "weaponsLocal", "deaths_while_equipped") != 0){ + kval = float(pulseParse(weaponName, "weaponsLocal", "kills")) + dval = float(pulseParse(weaponName, "weaponsLocal", "deaths_while_equipped")) if (kval / dval > kdval){ kdval = kval / dval } diff --git a/mod/scripts/vscripts/ui/menu_stats_weapons.nut b/mod/scripts/vscripts/ui/menu_stats_weapons.nut index 6fcc252..4b4c95a 100644 --- a/mod/scripts/vscripts/ui/menu_stats_weapons.nut +++ b/mod/scripts/vscripts/ui/menu_stats_weapons.nut @@ -180,8 +180,8 @@ void function UpdateStatsForWeapon( string weaponRef ) } // Total Kills Stats - SetStatsLabelValue( file.menu, "KillsValue0", getFromToneAPI(weaponRef, "weaponsLocal", "kills") ) //Total kills - SetStatsLabelValue( file.menu, "KillsValue1", getFromToneAPI(weaponRef, "weaponsLocal", "kills") ) //Pilots + SetStatsLabelValue( file.menu, "KillsValue0", pulseParse(weaponRef, "weaponsLocal", "kills") ) //Total kills + SetStatsLabelValue( file.menu, "KillsValue1", pulseParse(weaponRef, "weaponsLocal", "kills") ) //Pilots SetStatsLabelValue( file.menu, "KillsValue2", GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) ) //Titans - SetStatsLabelValue( file.menu, "KillsValue3", getFromToneAPI(weaponRef, "weaponsLocal", "deaths_while_equipped")) // Deaths with weapon + SetStatsLabelValue( file.menu, "KillsValue3", pulseParse(weaponRef, "weaponsLocal", "deaths_while_equipped")) // Deaths with weapon } From da25a4dd29c3af525e0d08e54ca6be94d79ad160 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:40:52 +0200 Subject: [PATCH 22/71] Bug fixes --- mod/scripts/vscripts/pulse-common-func.gnut | 22 ++++--- mod/scripts/vscripts/pulse.gnut | 15 ++--- mod/scripts/vscripts/ui/menu_lobby.nut | 68 +++++++++++++++++---- mod/scripts/vscripts/ui/menu_stats_maps.nut | 2 +- 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mod/scripts/vscripts/pulse-common-func.gnut index e64229f..83d1bf0 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mod/scripts/vscripts/pulse-common-func.gnut @@ -15,17 +15,15 @@ void function pulsePrintt(string content) //Prints whatever we want printed with bool function pulseRequestData(string givenURL, table parameterTable, string tablepath) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { - table > params - foreach (parameter in paramTable) - { - params[parameter] <- [paramTable(parameter)] - } - void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (params, tablepath) + table > requestTable + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (parameterTable, requestTable, tablepath) { table DecodedJSON = DecodeJSON(response.body) - if (params["map"]) + if ("map" in parameterTable) { - table map[params["map"]] <- DecodedJSON + table map + map[expect string(parameterTable["map"])] <- DecodedJSON + pulsePrintt(tablepath) pulseData[tablepath] <- map } else { pulseData[tablepath] <- DecodedJSON @@ -35,7 +33,11 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab { pulsePrintt("Something went wrong while getting data.") } - return NSHttpGet(givenURL, params, onSuccess, onFailure) + foreach (key, value in parameterTable) + { + requestTable[string(key)] <- [expect string(parameterTable[string(key)])] + } + return NSHttpGet(givenURL, requestTable, onSuccess, onFailure) } int function pulseParse(string parameter, string key, string value, string opt = "none") @@ -54,7 +56,7 @@ int function pulseParse(string parameter, string key, string value, string opt = { return expect int(valTable[value]) } else { - actualValTable = expect table(valTable[value]) + table actualValTable = expect table(valTable[value]) return expect int(actualValTable[opt]) } } diff --git a/mod/scripts/vscripts/pulse.gnut b/mod/scripts/vscripts/pulse.gnut index fa965bd..9a9d1d2 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mod/scripts/vscripts/pulse.gnut @@ -1,4 +1,5 @@ global function pulseInit +global function pulseGetData global table pulseData = {} @@ -15,14 +16,14 @@ void function pulseInit() void function pulseGetData() { string URL = GetConVarString("ToneURL") - array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] - array tablepath = ["weaponsLocal", "weaponsGlobal", "gamemodesAll", "gamemodesSeparated", "maps"] - pulseRequestData(URL + URLpath[1], ["uid" = NSGetLocalPlayerUID()], tablepath[1]) - pulseRequestData(URL + URLpath[2], ["uid" = "!" + NSGetLocalPlayerUID()], tablepath[2]) - pulseRequestData(URL + URLpath[3], ["uid" = NSGetLocalPlayerUID()], tablepath[3]) + array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] + array tablepath = ["weaponsLocal", "weaponsGlobal", "gamemodesAll", "gamemodesSeparated", "maps"] + pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0]) + pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1]) + pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2]) foreach (map in file.allMaps) { - pulseRequestData(URL + URLpath[4], ["uid" = NSGetLocalPlayerUID(), "map" = map.slice(3)], tablepath[4]) + pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3]) } - pulseRequestData(URL + URLpath[5], ["uid" = NSGetLocalPlayerUID()], tablepath[5]) + pulseRequestData(URL + URLpath[4], {["player"] = NSGetLocalPlayerUID()}, tablepath[4]) } \ No newline at end of file diff --git a/mod/scripts/vscripts/ui/menu_lobby.nut b/mod/scripts/vscripts/ui/menu_lobby.nut index 4206363..96eea60 100644 --- a/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mod/scripts/vscripts/ui/menu_lobby.nut @@ -124,6 +124,7 @@ void function MenuLobby_Init() PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background_happyhour" ) AddUICallback_OnLevelInit( OnLobbyLevelInit ) + pulseGetData() } @@ -234,16 +235,46 @@ void function SetupComboButtonTest( var menu ) int headerIndex = 0 int buttonIndex = 0 file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" ) - file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) - file.lobbyButtons.append( file.findGameButton ) - Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) - file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) - Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) + bool isModded = IsNorthstarServer() + + + // this will be the server browser + if ( isModded ) + { + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_SetLocked( file.findGameButton, true ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser ) + } + else + { + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) + } + + // this is used for launching private matches now + if ( isModded ) + { + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) + } + else + { + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) + } file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed ) + if ( isModded ) + { + Hud_SetEnabled( file.inviteFriendsButton, false ) + Hud_SetVisible( file.inviteFriendsButton, false ) + } + // file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" ) // Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode ) @@ -336,6 +367,16 @@ bool function MatchResultsExist() return true // TODO } +void function StartPrivateMatch( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + ClientCommand( "StartPrivateMatchSearch" ) + NSSetLoading(true) + NSUpdateListenServer() +} + void function DoRoomInviteIfAllowed( var button ) { if ( Hud_IsLocked( button ) ) @@ -1146,6 +1187,16 @@ void function SetUIPlayerCreditsInfo( var infoElement, int credits, int xp, int RuiSetImage( rui, "callsignIcon", callsignIcon.image ) } +void function OpenServerBrowser( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + // nothing here yet lol + // look at OpenSelectedPlaylistMenu for advancing to server browser menu probably + AdvanceMenu( GetMenu( "ServerBrowserMenu" ) ) +} + void function BigPlayButton1_Activate( var button ) { if ( Hud_IsLocked( button ) ) @@ -1189,7 +1240,7 @@ function UpdateLobbyUI() thread UpdateLobbyType() thread UpdateMatchmakingStatus() thread UpdateChatroomThread() - thread UpdateInviteJoinButton() + //thread UpdateInviteJoinButton() thread UpdateInviteFriendsToNetworkButton() thread UpdatePlayerInfo() @@ -1578,8 +1629,3 @@ void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) Lobby_SetFDMode( isFDMode ) } - -void function pulseRefresh -{ - pulseGetData() -} \ No newline at end of file diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mod/scripts/vscripts/ui/menu_stats_maps.nut index 67d1d7f..974d378 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -205,7 +205,7 @@ void function UpdateStatsForMap( string mapName ) if ( mapName in pulseData && key in pulseData[mapName]) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", modeName, "kills")) + modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", key, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } From a262c7ff45b1db4784b2b4cca371c52ddfb98374 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:51:40 +0200 Subject: [PATCH 23/71] Fix arbitrary data display --- mod/scripts/vscripts/ui/menu_lobby.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/scripts/vscripts/ui/menu_lobby.nut b/mod/scripts/vscripts/ui/menu_lobby.nut index 96eea60..4df0ab1 100644 --- a/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mod/scripts/vscripts/ui/menu_lobby.nut @@ -124,7 +124,6 @@ void function MenuLobby_Init() PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background_happyhour" ) AddUICallback_OnLevelInit( OnLobbyLevelInit ) - pulseGetData() } @@ -549,6 +548,7 @@ void function OnLobbyMenu_Open() // code will start loading DLC info from first party unless already done InitDLCStore() + pulseGetData() thread UpdateCachedNewItems() if ( file.putPlayerInMatchmakingAfterDelay ) From 739b265fab309e76e5a278c7642390ad0fbb2f9a Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:58:11 +0200 Subject: [PATCH 24/71] Fix missing Kills by Gamemode piechart data --- mod/scripts/vscripts/ui/menu_stats_time.nut | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mod/scripts/vscripts/ui/menu_stats_time.nut index 157e4bd..b84a99c 100644 --- a/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -160,10 +160,10 @@ void function UpdateViewStatsTimeMenu() for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( pulseParse(modeName, "gamemodes", "kills") != 0 ) + if ( pulseParse(modeName, "gamemodesAll", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(modeName, "gamemodes", "kills")) + modePlayedTime = float(pulseParse(modeName, "gamemodesAll", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -171,10 +171,10 @@ void function UpdateViewStatsTimeMenu() } foreach (string key, array value in customGamemodeList) { - if ( pulseParse(key, "gamemodes", "kills") != 0 ) + if ( pulseParse(key, "gamemodesAll", "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(key, "gamemodes", "kills")) + modePlayedTime = float(pulseParse(key, "gamemodesAll", "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } From ddfb34a9f8213d196c66feef6b6274c742f0436b Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 7 Jun 2023 19:15:14 +0200 Subject: [PATCH 25/71] Change to Thunderstore template For easier publishing to both platforms --- icon.png | Bin 0 -> 53440 bytes manifest.json | 7 ++ mods/ToneAPI.pulse/README.md | 80 ++++++++++++++++++ mod.json => mods/ToneAPI.pulse/mod.json | 0 .../resource/ui/menus/viewstats_maps.menu | 0 .../resource/ui/menus/viewstats_overview.menu | 0 .../resource/ui/menus/viewstats_weapons.menu | 0 .../scripts/vscripts/pulse-common-func.gnut | 6 +- .../mod}/scripts/vscripts/pulse.gnut | 2 +- .../mod}/scripts/vscripts/ui/menu_lobby.nut | 0 .../scripts/vscripts/ui/menu_stats_maps.nut | 4 +- .../vscripts/ui/menu_stats_overview.nut | 0 .../scripts/vscripts/ui/menu_stats_time.nut | 0 .../scripts/vscripts/ui/menu_stats_titans.nut | 0 .../vscripts/ui/menu_stats_utility.nut | 0 .../vscripts/ui/menu_stats_weapons.nut | 0 16 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 icon.png create mode 100644 manifest.json create mode 100644 mods/ToneAPI.pulse/README.md rename mod.json => mods/ToneAPI.pulse/mod.json (100%) rename {mod => mods/ToneAPI.pulse/mod}/resource/ui/menus/viewstats_maps.menu (100%) rename {mod => mods/ToneAPI.pulse/mod}/resource/ui/menus/viewstats_overview.menu (100%) rename {mod => mods/ToneAPI.pulse/mod}/resource/ui/menus/viewstats_weapons.menu (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/pulse-common-func.gnut (92%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/pulse.gnut (96%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_lobby.nut (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_maps.nut (98%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_overview.nut (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_time.nut (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_titans.nut (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_utility.nut (100%) rename {mod => mods/ToneAPI.pulse/mod}/scripts/vscripts/ui/menu_stats_weapons.nut (100%) diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..081973f05aeac51b824701a0bed70c1e4c98ba74 GIT binary patch literal 53440 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 P00000NkvXXu0mjf0=E#6 literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..af52acd --- /dev/null +++ b/manifest.json @@ -0,0 +1,7 @@ +{ + "name": "Pulse", + "description": "Pulse is a clientside mod for Titanfall 2 letting you view killstats collected by the Tone API using the otherwise non-functional Stats tab.", + "version_number": "2.0.0", + "website_url": "https://github.com/ToneAPI/pulse", + "dependencies": [] +} \ No newline at end of file diff --git a/mods/ToneAPI.pulse/README.md b/mods/ToneAPI.pulse/README.md new file mode 100644 index 0000000..28d57de --- /dev/null +++ b/mods/ToneAPI.pulse/README.md @@ -0,0 +1,80 @@ +# Pulse + +Pulse is a clientside mod for [TF|2 + Northstar](https://github.com/R2Northstar/Northstar) letting you view killstats collected by [the Tone API](https://toneapi.github.io/ToneAPI_webclient/) using the otherwise non-functional `Stats` tab. + +## Currently, features include: +- mostly functional `Overview` tab, +- functional `Time` tab, +- Pilot weapon data displayed in `Pilot Weapons` tab, +- Titan kills displayed in `Titans` tab, +- functional `Maps` tab, +- real-time updates. + +Want to know what we have planned for future updates? See [here.](https://github.com/ToneAPI/pulse/projects?query=is%3Aopen) + +Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/issues/new) + +
+Features, more in-depth: + +### `Overview` +- Most Kills - shows the weapon with most accumulated kills. +- Nemesis Weapon - shows the weapon that has killed you the most. +- Most Effective - shows weapon with the highest K/D ratio. +- Kill/Death Ratio - shows the overall K/D ratio of player compared to global K/D. +- Kills as Pilot - shows general kill data for player as Pilot, visualised in the table below: + + | Name | Description | + |--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + | Pilots |Shows **ALL KILLS** accumulated by player as Pilot. Differentiating Pilot and Titan kills will come in a later Tone API update.| + | Titans |Non-functional, see line above.| + | AI kills |Non-functional, Tone API does not collect AI kill data.| + | Pilot melee kills |Shows only melee kills accumulated by player as Pilot.| + | Pilot executions |Shows only executions accumulated by player as Pilot.| + +- Kills as Titan - shows general kill data for player as Titan, visualised in the table below: + + | Name | Description | + |--------------------|------------------------------------------------------| + | Pilots |Shows **ALL KILLS** accumulated by player as Titan. Differentiating Pilot and Titan kills will come in a later Tone API update.| + | Titans |Non-functional, see line above.| + | Titan executions |Shows only executions accumulated by player as Titan.| + | Pilots meleed |Shows only melee kills accumulated by player as Titan.| + | Pilot roadkills |Shows only roadkills accumulated by player as Titan.| + +- Upper statbox values have been zeroed out, these don't yet work and are set to 0 to avoid confusion. + +### `Time` + +- Kills by Class shows kills by Pilot and Titan on a piechart. +- Kills by Titan shows kills by all Titan classes on a piechart. +- Kills by Gamemode shows kills on each gamemode played on a piechart. + +### `Pilot Weapons` + +- shows total accumulated kills per weapon under Total Kills. +- shows deaths with given weapon equipped under Deaths with Weapon. + +### `Titans` + +- shows total accumulated kills per Titan under Total Kills. + +### `Maps` + +- Player Map Stats - shows general data for player on chosen map, visualised in the table below: + + | Name | Description | + |-----------------------|------------------------------------------------------- | + | Kills on Map |Shows all kills accumulated by player on chosen map.| + | Deaths on Map |Shows all deaths accumulated by player on chosen map.| + | Total Shot Distance |Shows total distance of kills accumulated by player on chosen map.| + | Maximum Shot Distance |Shows highest distance kill by player on chosen map.| + +- Kills by Gamemode - piechart showing all kills (in percent) on chosen map by gamemode. +
+ +## DISCLAIMER + +The Tone API is NOT used by every server, view a list of supported servers [here.](https://tone.sleepycat.date/v2/client/servers) + +Pulse is very much a W.I.P as of right now, features may be missing/nonfunctional. diff --git a/mod.json b/mods/ToneAPI.pulse/mod.json similarity index 100% rename from mod.json rename to mods/ToneAPI.pulse/mod.json diff --git a/mod/resource/ui/menus/viewstats_maps.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu similarity index 100% rename from mod/resource/ui/menus/viewstats_maps.menu rename to mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu diff --git a/mod/resource/ui/menus/viewstats_overview.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu similarity index 100% rename from mod/resource/ui/menus/viewstats_overview.menu rename to mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu diff --git a/mod/resource/ui/menus/viewstats_weapons.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu similarity index 100% rename from mod/resource/ui/menus/viewstats_weapons.menu rename to mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu diff --git a/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut similarity index 92% rename from mod/scripts/vscripts/pulse-common-func.gnut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 83d1bf0..8d9d81b 100644 --- a/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -21,10 +21,8 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab table DecodedJSON = DecodeJSON(response.body) if ("map" in parameterTable) { - table map - map[expect string(parameterTable["map"])] <- DecodedJSON - pulsePrintt(tablepath) - pulseData[tablepath] <- map + string mapName = expect string(parameterTable["map"]) + pulseData[tablepath] <- {mapName = DecodedJSON} } else { pulseData[tablepath] <- DecodedJSON } diff --git a/mod/scripts/vscripts/pulse.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut similarity index 96% rename from mod/scripts/vscripts/pulse.gnut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut index 9a9d1d2..cd67e04 100644 --- a/mod/scripts/vscripts/pulse.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut @@ -21,7 +21,7 @@ void function pulseGetData() pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0]) pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1]) pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2]) - foreach (map in file.allMaps) + foreach (string map in file.allMaps) { pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3]) } diff --git a/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_lobby.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut diff --git a/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut similarity index 98% rename from mod/scripts/vscripts/ui/menu_stats_maps.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index 974d378..e6bef01 100644 --- a/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -191,7 +191,7 @@ void function UpdateStatsForMap( string mapName ) for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( mapName in pulseData && modeName in pulseData[mapName] ) + if (mapName in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", modeName, "kills")) @@ -202,7 +202,7 @@ void function UpdateStatsForMap( string mapName ) } foreach (string key, array value in customGamemodeList) { - if ( mapName in pulseData && key in pulseData[mapName]) + if (mapName in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", key, "kills")) diff --git a/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_stats_overview.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut diff --git a/mod/scripts/vscripts/ui/menu_stats_time.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_stats_time.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut diff --git a/mod/scripts/vscripts/ui/menu_stats_titans.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_stats_titans.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut diff --git a/mod/scripts/vscripts/ui/menu_stats_utility.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_stats_utility.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut diff --git a/mod/scripts/vscripts/ui/menu_stats_weapons.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut similarity index 100% rename from mod/scripts/vscripts/ui/menu_stats_weapons.nut rename to mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut From 1109be0ece2cbff7233bd7ae5607268f046289d7 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 7 Jun 2023 21:18:35 +0200 Subject: [PATCH 26/71] Parser rewrite --- .../scripts/vscripts/pulse-common-func.gnut | 33 ++++++++----------- .../scripts/vscripts/ui/menu_stats_maps.nut | 12 +++---- .../vscripts/ui/menu_stats_overview.nut | 28 ++++++++-------- .../scripts/vscripts/ui/menu_stats_time.nut | 10 +++--- .../scripts/vscripts/ui/menu_stats_titans.nut | 2 +- .../vscripts/ui/menu_stats_utility.nut | 10 +++--- .../vscripts/ui/menu_stats_weapons.nut | 6 ++-- 7 files changed, 47 insertions(+), 54 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 8d9d81b..39d8b50 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -22,7 +22,7 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab if ("map" in parameterTable) { string mapName = expect string(parameterTable["map"]) - pulseData[tablepath] <- {mapName = DecodedJSON} + pulseData["mp_" + mapName] <- DecodedJSON } else { pulseData[tablepath] <- DecodedJSON } @@ -38,26 +38,19 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab return NSHttpGet(givenURL, requestTable, onSuccess, onFailure) } -int function pulseParse(string parameter, string key, string value, string opt = "none") +int function pulseParse(...) //Returns data from our pulseData table. { - if (key == "maps") - { - parameter = parameter.slice(3) - } - if (key in pulseData) - { - table keyandvalTable = expect table(pulseData[key]) - if (parameter in keyandvalTable) - { - table valTable = expect table(keyandvalTable[parameter]) - if (opt == "none") - { - return expect int(valTable[value]) - } else { - table actualValTable = expect table(valTable[value]) - return expect int(actualValTable[opt]) - } + table parser = pulseData + int result = 0 + for (int i; i < vargc; i++) { + print (vargc) + if (i < expect int(vargc) - 1) { + if (expect string (vargv[i]) in parser) { + parser = expect table(parser[expect string(vargv[i])]) + } else {break} + } else { + result = expect int(parser[expect string(vargv[i])]) } } - return 0 + return result } \ No newline at end of file diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index e6bef01..58bd751 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -153,16 +153,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue0", pulseParse(mapName, "maps", "kills") ) + SetStatsLabelValue( file.menu, "KillsValue0", pulseParse("maps", mapName, "kills") ) SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue1", pulseParse(mapName, "maps", "deaths") ) + SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("maps", mapName, "deaths") ) SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse(mapName, "maps", "total_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse("maps", mapName, "total_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse(mapName, "maps", "max_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse("maps", mapName, "max_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) SetStatsLabelValue( file.menu, "KillsValue4", "--" ) @@ -194,7 +194,7 @@ void function UpdateStatsForMap( string mapName ) if (mapName in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", modeName, "kills")) + modePlayedTime = float(pulseParse("gamemodesSeparated", mapName, modeName, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -205,7 +205,7 @@ void function UpdateStatsForMap( string mapName ) if (mapName in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(mapName, "gamemodesSeparated", key, "kills")) + modePlayedTime = float(pulseParse("gamemodesSeparated", mapName, key, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut index 43810b2..b8db39e 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -52,7 +52,7 @@ void function GetTitanKills( string titanName ) foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - titanKillData[weaponRef] <- pulseParse(weaponRef, "weaponsLocal", "kills") + titanKillData[weaponRef] <- pulseParse("weaponsLocal", weaponRef, "kills") } } @@ -332,7 +332,7 @@ function UpdateViewStatsOverviewMenu() if (key in titanKillData) { continue } else { - killsAsPilot += pulseParse(string(key), "weaponsLocal", "kills") + killsAsPilot += pulseParse("weaponsLocal", string(key), "kills") } } @@ -407,27 +407,27 @@ function UpdateViewStatsOverviewMenu() Hud_SetText( GetElem( file.menu, "KillsAsPilotValue0" ), string( killsAsPilot ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsPilot" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue2" ), string( GetPlayerStatInt( player, "kills_stats", "totalNPC" ) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( pulseParse("pilot_emptyhanded", "weaponsLocal", "kills") ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( pulseParse("human_execution", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( pulseParse("weaponsLocal", "pilot_emptyhanded", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( pulseParse("weaponsLocal", "human_execution", "kills") ) ) // Hud_SetText( GetElem( file.menu, "KillsAsPilotValue5" ), string( GetPlayerStatInt( player, "kills_stats", "titanFallKill" ) ) ) var titanMeleeKills = 0 - titanMeleeKills += pulseParse("titan_punch_ion", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_punch_scorch", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_punch_northstar", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_sword", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_punch_tone", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_punch_legion", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("titan_punch_vanguard", "weaponsLocal", "kills") - titanMeleeKills += pulseParse("auto_titan_melee", "weaponsLocal", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_ion", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_scorch", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_northstar", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_sword", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_tone", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_legion", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "titan_punch_vanguard", "kills") + titanMeleeKills += pulseParse("weaponsLocal", "auto_titan_melee", "kills") - var titanExecutions = pulseParse("titan_execution", "weaponsLocal", "kills") + var titanExecutions = pulseParse("weaponsLocal", "titan_execution", "kills") Hud_SetText( GetElem( file.menu, "KillsAsTitanValue0" ), string( killsAsTitan ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsTitan" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue2" ), string( titanExecutions ) ) Hud_SetText( GetElem( file.menu, "KillsAsTitanValue3" ), string( titanMeleeKills ) ) - Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( pulseParse("damagedef_titan_step", "weaponsLocal", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsTitanValue4" ), string( pulseParse("weaponsLocal", "damagedef_titan_step", "kills") ) ) } function PlotKDPointsOnGraph( menu, graphIndex, values, dottedAverage ) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut index b84a99c..6a240ee 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -49,7 +49,7 @@ float function GetTitanKills( string titanName) float weaponKills = 0 foreach ( weaponRef in file.titanStatLoadout[ titanName ]) { - weaponKills += float(pulseParse(weaponRef, "weaponsLocal", "kills")) + weaponKills += float(pulseParse("weaponsLocal", weaponRef, "kills")) } return weaponKills } @@ -160,10 +160,10 @@ void function UpdateViewStatsTimeMenu() for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if ( pulseParse(modeName, "gamemodesAll", "kills") != 0 ) + if ( pulseParse("gamemodesAll", modeName, "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(modeName, "gamemodesAll", "kills")) + modePlayedTime = float(pulseParse("gamemodesAll", modeName, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } @@ -171,10 +171,10 @@ void function UpdateViewStatsTimeMenu() } foreach (string key, array value in customGamemodeList) { - if ( pulseParse(key, "gamemodesAll", "kills") != 0 ) + if ( pulseParse("gamemodesAll", key, "kills") != 0 ) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse(key, "gamemodesAll", "kills")) + modePlayedTime = float(pulseParse("gamemodesAll", key, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut index f401e10..da87817 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_titans.nut @@ -175,7 +175,7 @@ void function UpdateStatsForTitan( string titanRef, int loadoutIndex ) int aiKills foreach ( weaponRef in file.titanStatLoadout[ titanRef ] ) { - totalKills += pulseParse(weaponRef, "weaponsLocal", "kills") + totalKills += pulseParse("weaponsLocal", weaponRef, "kills") pilotKills += GetPlayerStatInt( player, "weapon_kill_stats", "pilots", weaponRef ) titanKills += GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) aiKills += GetPlayerStatInt( player, "weapon_kill_stats", "ai", weaponRef ) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut index c53e458..bc22ea6 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_utility.nut @@ -338,7 +338,7 @@ table function GetOverviewWeaponData() if ( !PersistenceEnumValueIsValid( "loadoutWeaponsAndAbilities", weaponName ) ) continue - int val = pulseParse(weaponName, "weaponsLocal", "kills") + int val = pulseParse("weaponsLocal", weaponName, "kills") if ( val > Table[ "most_kills" ].val ) { Table[ "most_kills" ].ref = weaponName @@ -346,7 +346,7 @@ table function GetOverviewWeaponData() Table[ "most_kills" ].val = val } - int nval = pulseParse(weaponName, "weaponsLocal", "deaths") + int nval = pulseParse("weaponsLocal", weaponName, "deaths") if ( nval > Table[ "nemesis_weapon" ].val ) { Table[ "nemesis_weapon" ].ref = weaponName @@ -357,9 +357,9 @@ table function GetOverviewWeaponData() float kdval = 0 float kval = 0 float dval = 0 - if( pulseParse(weaponName, "weaponsLocal", "kills") != 0 && pulseParse(weaponName, "weaponsLocal", "deaths_while_equipped") != 0){ - kval = float(pulseParse(weaponName, "weaponsLocal", "kills")) - dval = float(pulseParse(weaponName, "weaponsLocal", "deaths_while_equipped")) + if( pulseParse("weaponsLocal", weaponName, "kills") != 0 && pulseParse("weaponsLocal", weaponName, "deaths_while_equipped") != 0){ + kval = float(pulseParse("weaponsLocal", weaponName, "kills")) + dval = float(pulseParse("weaponsLocal", weaponName, "deaths_while_equipped")) if (kval / dval > kdval){ kdval = kval / dval } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut index 4b4c95a..6340a5a 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_weapons.nut @@ -180,8 +180,8 @@ void function UpdateStatsForWeapon( string weaponRef ) } // Total Kills Stats - SetStatsLabelValue( file.menu, "KillsValue0", pulseParse(weaponRef, "weaponsLocal", "kills") ) //Total kills - SetStatsLabelValue( file.menu, "KillsValue1", pulseParse(weaponRef, "weaponsLocal", "kills") ) //Pilots + SetStatsLabelValue( file.menu, "KillsValue0", pulseParse("weaponsLocal", weaponRef, "kills") ) //Total kills + SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("weaponsLocal", weaponRef, "kills") ) //Pilots SetStatsLabelValue( file.menu, "KillsValue2", GetPlayerStatInt( player, "weapon_kill_stats", "titansTotal", weaponRef ) ) //Titans - SetStatsLabelValue( file.menu, "KillsValue3", pulseParse(weaponRef, "weaponsLocal", "deaths_while_equipped")) // Deaths with weapon + SetStatsLabelValue( file.menu, "KillsValue3", pulseParse("weaponsLocal", weaponRef, "deaths_while_equipped")) // Deaths with weapon } From 908a875f6d43016d46ae7ed73c782f7163565e87 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:28:01 +0200 Subject: [PATCH 27/71] Work on making map piecharts function again... --- .../scripts/vscripts/pulse-common-func.gnut | 6 ++++-- .../mod/scripts/vscripts/pulse.gnut | 3 ++- .../scripts/vscripts/ui/menu_stats_maps.nut | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 39d8b50..6c576cd 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -16,13 +16,16 @@ void function pulsePrintt(string content) //Prints whatever we want printed with bool function pulseRequestData(string givenURL, table parameterTable, string tablepath) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > requestTable + pulsePrintt(tablepath) void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (parameterTable, requestTable, tablepath) { table DecodedJSON = DecodeJSON(response.body) if ("map" in parameterTable) { string mapName = expect string(parameterTable["map"]) - pulseData["mp_" + mapName] <- DecodedJSON + table withMapName = {} + withMapName[mapName] <- DecodedJSON + pulseData[tablepath] <- withMapName } else { pulseData[tablepath] <- DecodedJSON } @@ -43,7 +46,6 @@ int function pulseParse(...) //Returns data from our pulseData table. table parser = pulseData int result = 0 for (int i; i < vargc; i++) { - print (vargc) if (i < expect int(vargc) - 1) { if (expect string (vargv[i]) in parser) { parser = expect table(parser[expect string(vargv[i])]) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut index cd67e04..a2efbe9 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut @@ -10,6 +10,7 @@ struct { void function pulseInit() { pulsePrefixSet() + file.allMaps = GetPrivateMatchMaps() pulsePrintt("Initialized.") } @@ -21,7 +22,7 @@ void function pulseGetData() pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0]) pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1]) pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2]) - foreach (string map in file.allMaps) + foreach (map in file.allMaps) { pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3]) } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index 58bd751..455a047 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -153,16 +153,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue0", pulseParse("maps", mapName, "kills") ) + SetStatsLabelValue( file.menu, "KillsValue0", pulseParse("maps", mapName.slice(3), "kills") ) SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) - SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("maps", mapName, "deaths") ) + SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("maps", mapName.slice(3), "deaths") ) SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse("maps", mapName, "total_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "total_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse("maps", mapName, "max_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "max_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) SetStatsLabelValue( file.menu, "KillsValue4", "--" ) @@ -191,21 +191,23 @@ void function UpdateStatsForMap( string mapName ) for ( int modeId = 0; modeId < enumCount; modeId++ ) { string modeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeId ) - if (mapName in pulseData["gamemodesSeparated"]) + if (mapName.slice(3) in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse("gamemodesSeparated", mapName, modeName, "kills")) + modePlayedTime = float(pulseParse("gamemodesSeparated", mapName.slice(3), modeName, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } + } else { + pulsePrintt("No " + mapName.slice(3) + " in pulseData") } } foreach (string key, array value in customGamemodeList) { - if (mapName in pulseData["gamemodesSeparated"]) + if (mapName.slice(3) in pulseData["gamemodesSeparated"]) { float modePlayedTime = 0 - modePlayedTime = float(pulseParse("gamemodesSeparated", mapName, key, "kills")) + modePlayedTime = float(pulseParse("gamemodesSeparated", mapName.slice(3), key, "kills")) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, customGamemodeNames[key], modePlayedTime, value) } From d74c57ec2bbaeea0a7a189ac87729ee8c15c74fc Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:33:06 +0200 Subject: [PATCH 28/71] Update pulse-common-func.gnut --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 6c576cd..2a12562 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -36,7 +36,7 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } foreach (key, value in parameterTable) { - requestTable[string(key)] <- [expect string(parameterTable[string(key)])] + requestTable[string(key)] <- [string(value)] } return NSHttpGet(givenURL, requestTable, onSuccess, onFailure) } From 2a1557382675390d573e794fdccf85164e2bd1c1 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:33:23 +0200 Subject: [PATCH 29/71] Thread pulseGetData function --- mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut index 4df0ab1..65a19a7 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut @@ -548,7 +548,7 @@ void function OnLobbyMenu_Open() // code will start loading DLC info from first party unless already done InitDLCStore() - pulseGetData() + waitthread pulseGetData() thread UpdateCachedNewItems() if ( file.putPlayerInMatchmakingAfterDelay ) From b2cb9586735c0ad4fa07d70a0cec03288d0d6c5d Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:56:38 +0200 Subject: [PATCH 30/71] Fix map piecharts --- .../ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 2a12562..499091b 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -3,6 +3,7 @@ globalize_all_functions global string pulsePrefix +table withMapName = {} void function pulsePrefixSet() //Sets our prefix { pulsePrefix = format("\x1b[38;2;%i;%i;%im[PULSE]\x1b[0m", 255, 178, 102) @@ -23,7 +24,6 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab if ("map" in parameterTable) { string mapName = expect string(parameterTable["map"]) - table withMapName = {} withMapName[mapName] <- DecodedJSON pulseData[tablepath] <- withMapName } else { @@ -37,6 +37,8 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab foreach (key, value in parameterTable) { requestTable[string(key)] <- [string(value)] + pulsePrintt(string(key)) + pulsePrintt(string(value)) } return NSHttpGet(givenURL, requestTable, onSuccess, onFailure) } From 40f1af931e1798234a51fe798d7a0a24d476ccfb Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:43:27 +0200 Subject: [PATCH 31/71] Bug fixes --- mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut index 65a19a7..cd743ed 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut @@ -372,8 +372,6 @@ void function StartPrivateMatch( var button ) return ClientCommand( "StartPrivateMatchSearch" ) - NSSetLoading(true) - NSUpdateListenServer() } void function DoRoomInviteIfAllowed( var button ) @@ -1628,4 +1626,4 @@ void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) } Lobby_SetFDMode( isFDMode ) -} +} \ No newline at end of file From a18c59931f936b24622d7ab1f71f0c1db4dd30c8 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:06:07 +0200 Subject: [PATCH 32/71] Clean up remaining test code --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 2 -- mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut | 2 -- 2 files changed, 4 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 499091b..ae409fb 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -37,8 +37,6 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab foreach (key, value in parameterTable) { requestTable[string(key)] <- [string(value)] - pulsePrintt(string(key)) - pulsePrintt(string(value)) } return NSHttpGet(givenURL, requestTable, onSuccess, onFailure) } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index 455a047..f5bfa07 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -198,8 +198,6 @@ void function UpdateStatsForMap( string mapName ) if ( modePlayedTime > 0 ) { AddPieChartEntry( modes, GameMode_GetName( modeName ), modePlayedTime, GetGameModeDisplayColor( modeName ) ) } - } else { - pulsePrintt("No " + mapName.slice(3) + " in pulseData") } } foreach (string key, array value in customGamemodeList) From aee8c916700a6a3fc9bb570b2c2c4e7da5ff3479 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:06:19 +0200 Subject: [PATCH 33/71] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 28d57de..de3a197 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,16 @@ Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/is The Tone API is NOT used by every server, view a list of supported servers [here.](https://tone.sleepycat.date/v2/client/servers) Pulse is very much a W.I.P as of right now, features may be missing/nonfunctional. + +## CHANGELOG + +
+ pulse v2.0.0 "Demeter" + + - Switched to Thunderstore template on the GitHub site for easier development. + - General code rewrite - lots of improvements for easier development. Rewrite includes: + - common code file, for better code readability and ease of development, + - new parser, allowing for better expandability and faster data processing (and much simpler implementation, unlike the hellspawn that was the previous `getFromToneAPI` function), + - new request function, more compact and simple than previous iterations, + - other functions that simplify the code and make it easier to read / develop +
From 96b7aaaa07b4af2c43644b2a3edbcb4496a28b18 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sat, 10 Jun 2023 11:11:08 +0200 Subject: [PATCH 34/71] Change typography to lowercase --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index de3a197..af245a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Pulse +# pulse -Pulse is a clientside mod for [TF|2 + Northstar](https://github.com/R2Northstar/Northstar) letting you view killstats collected by [the Tone API](https://toneapi.github.io/ToneAPI_webclient/) using the otherwise non-functional `Stats` tab. +**pulse** is a clientside mod for [TF|2 + Northstar](https://github.com/R2Northstar/Northstar) letting you view killstats collected by [the Tone API](https://toneapi.github.io/ToneAPI_webclient/) using the otherwise non-functional `Stats` tab. ## Currently, features include: - mostly functional `Overview` tab, @@ -76,8 +76,7 @@ Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/is ## DISCLAIMER The Tone API is NOT used by every server, view a list of supported servers [here.](https://tone.sleepycat.date/v2/client/servers) - -Pulse is very much a W.I.P as of right now, features may be missing/nonfunctional. +**pulse** is very much a W.I.P as of right now, features may be missing/nonfunctional. ## CHANGELOG From d372ecaff1dd430357f453cd15f17576264fceeb Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sat, 10 Jun 2023 14:03:23 +0200 Subject: [PATCH 35/71] Simplify description in manifest.json --- manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index af52acd..83c562f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Pulse", - "description": "Pulse is a clientside mod for Titanfall 2 letting you view killstats collected by the Tone API using the otherwise non-functional Stats tab.", + "description": "Adds stats (collected by the Tone API) back to the Stats tab.", "version_number": "2.0.0", "website_url": "https://github.com/ToneAPI/pulse", "dependencies": [] -} \ No newline at end of file +} From ffe6fec939db58cb560365e825a9170568b91e78 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sat, 10 Jun 2023 15:38:20 +0200 Subject: [PATCH 36/71] Remove testing code snippet --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index ae409fb..4c12684 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -17,7 +17,6 @@ void function pulsePrintt(string content) //Prints whatever we want printed with bool function pulseRequestData(string givenURL, table parameterTable, string tablepath) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > requestTable - pulsePrintt(tablepath) void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (parameterTable, requestTable, tablepath) { table DecodedJSON = DecodeJSON(response.body) From f2b09667e7ffd46496351471b8327803dfeeb5c0 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 11 Jun 2023 17:33:31 +0200 Subject: [PATCH 37/71] English localisation #30 --- mods/ToneAPI.pulse/mod.json | 3 +++ .../mod/resource/pulse_english.txt | Bin 0 -> 1036 bytes .../resource/ui/menus/viewstats_overview.menu | 2 +- .../resource/ui/menus/viewstats_weapons.menu | 2 +- .../mod/scripts/vscripts/ui/menu_stats_maps.nut | 16 ++++++++-------- .../scripts/vscripts/ui/menu_stats_overview.nut | 2 +- .../mod/scripts/vscripts/ui/menu_stats_time.nut | 12 ++++++------ 7 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/resource/pulse_english.txt diff --git a/mods/ToneAPI.pulse/mod.json b/mods/ToneAPI.pulse/mod.json index 9ad4981..46a716b 100644 --- a/mods/ToneAPI.pulse/mod.json +++ b/mods/ToneAPI.pulse/mod.json @@ -25,5 +25,8 @@ "After": "pulseInit" } } + ], + "Localisation": [ + "resource/pulse_%language%.txt" ] } diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_english.txt b/mods/ToneAPI.pulse/mod/resource/pulse_english.txt new file mode 100644 index 0000000000000000000000000000000000000000..179cb0daeb2df2d1f08bab2831628829910faeef GIT binary patch literal 1036 zcmb7D%TB{E5S%j-|6ut~N?Xy2xDASVogxlZK~(fmaYFrdV0LZGPGdw-`3Jk9B#P?7~y^5!1 z(ca^Rr-qMoFy%hssf+A6mbgpAf0(77CwFpY%v>Vs%sHpWHMvB;qub&^a3dp<-Z8Gu zUHT}KT&OGJ&m6b(d&#-BJkP4WXS}K4>lGb4Xw~(sdfbKFCBrTS8}53#DQUMcD)TG5 z2wdeqMsMc%Y@X^;zn-}=zlLf$x+A{~qjK}ZT&FsPzj}2Ar*!p521kG08N4O;QNQ>j FegN5Ld42!@ literal 0 HcmV?d00001 diff --git a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu index fda9289..b85bd1f 100644 --- a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu +++ b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_overview.menu @@ -323,7 +323,7 @@ resource/ui/menus/viewstats_overview.menu tall 45 visible 1 font Default_31 - labelText "NEMESIS WEAPON" + labelText "#NEMESIS_WEAPON" allcaps 1 wrap 1 textAlignment west diff --git a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu index 61f8546..9ff1c62 100644 --- a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu +++ b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_weapons.menu @@ -345,7 +345,7 @@ resource/ui/menus/viewstats_weapons.menu tall 36 visible 1 font Default_23 - labelText "DEATHS WITH WEAPON" + labelText "#DEATHS_WHILE_EQUIPPED" allcaps 1 textAlignment west fgcolor_override "255 255 255 255" diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index f5bfa07..e43ddca 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -152,16 +152,16 @@ void function UpdateStatsForMap( string mapName ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat2" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) //SetStatBoxDisplay( Hud_GetChild( file.menu, "Stat3" ), Localize( "#STATS_GAMES_PLAYED" ), gamesPlayed ) - SetStatsLabelValue( file.menu, "KillsLabel0", "KILLS ON MAP" ) + SetStatsLabelValue( file.menu, "KillsLabel0", Localize("#MAPS_KILLS") ) SetStatsLabelValue( file.menu, "KillsValue0", pulseParse("maps", mapName.slice(3), "kills") ) - SetStatsLabelValue( file.menu, "KillsLabel1", "DEATHS ON MAP" ) + SetStatsLabelValue( file.menu, "KillsLabel1", Localize("#MAPS_DEATHS") ) SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("maps", mapName.slice(3), "deaths") ) - SetStatsLabelValue( file.menu, "KillsLabel2", "TOTAL SHOT DISTANCE" ) + SetStatsLabelValue( file.menu, "KillsLabel2", Localize("#MAPS_TSD") ) SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "total_distance") ) ) )/100) + "m" ) - SetStatsLabelValue( file.menu, "KillsLabel3", "MAXIMUM SHOT DISTANCE" ) + SetStatsLabelValue( file.menu, "KillsLabel3", Localize("#MAPS_MSD") ) SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "max_distance") ) ) )/100) + "m" ) SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) @@ -184,9 +184,9 @@ void function UpdateStatsForMap( string mapName ) gg = [14, 87, 132, 255] } table< string, string > customGamemodeNames = { - sns = "Sticks and Stones" - fw = "Frontier War" - gg = "Gun Game" + sns = Localize("#GAMEMODE_sns") + fw = Localize("#GAMEMODE_fw") + gg = Localize("#GAMEMODE_gg") } for ( int modeId = 0; modeId < enumCount; modeId++ ) { @@ -231,7 +231,7 @@ void function UpdateStatsForMap( string mapName ) PieChartData modesPlayedData modesPlayedData.entries = modes modesPlayedData.labelColor = [ 255, 255, 255, 255 ] - SetPieChartData( file.menu, "ModesPieChart", "KILLS BY GAMEMODE", modesPlayedData ) + SetPieChartData( file.menu, "ModesPieChart", "#KILLS_GAMEMODE", modesPlayedData ) array fdMaps = GetPlaylistMaps( "fd" ) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut index b8db39e..23fe3a2 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -218,7 +218,7 @@ function UpdateViewStatsOverviewMenu() Hud_Show( weaponImageElem ) Hud_SetText( weaponNameElem, nemesisWeapon.printName ) Hud_Show( weaponNameElem ) - Hud_SetText( weaponDescElem, nemesisWeapon.val + " DEATHS BY WEAPON" ) + Hud_SetText( weaponDescElem, nemesisWeapon.val + " " + Localize("#NEMESIS_WEAPON_VALUE")) Hud_Show( weaponDescElem ) Hud_Hide( noDataElem ) } diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut index 6a240ee..eb1babc 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_time.nut @@ -103,7 +103,7 @@ void function UpdateViewStatsTimeMenu() PieChartData classTimeData classTimeData.entries = classes classTimeData.labelColor = [ 255, 255, 255, 255 ] - SetPieChartData( file.menu, "ClassPieChart", "KILLS BY CLASS", classTimeData ) + SetPieChartData( file.menu, "ClassPieChart", Localize("#TIME_KILLS_CLASS"), classTimeData ) //######################################### // Time By Chassis Pie Chart @@ -137,7 +137,7 @@ void function UpdateViewStatsTimeMenu() PieChartData chassisTimeData chassisTimeData.entries = titans chassisTimeData.labelColor = [ 255, 255, 255, 255 ] - SetPieChartData( file.menu, "ChassisPieChart", "KILLS BY TITAN", chassisTimeData ) + SetPieChartData( file.menu, "ChassisPieChart", Localize("#TIME_KILLS_TITAN"), chassisTimeData ) //######################################### // Time By Mode Pie Chart @@ -153,9 +153,9 @@ void function UpdateViewStatsTimeMenu() gg = [14, 87, 132, 255] } table< string, string > customGamemodeNames = { - sns = "Sticks and Stones" - fw = "Frontier War" - gg = "Gun Game" + sns = Localize("#GAMEMODE_sns") + fw = Localize("#GAMEMODE_fw") + gg = Localize("#GAMEMODE_gg") } for ( int modeId = 0; modeId < enumCount; modeId++ ) { @@ -184,7 +184,7 @@ void function UpdateViewStatsTimeMenu() PieChartData modesPlayedData modesPlayedData.entries = modes modesPlayedData.labelColor = [ 255, 255, 255, 255 ] - SetPieChartData( file.menu, "ModesPieChart", "KILLS BY GAMEMODE", modesPlayedData ) + SetPieChartData( file.menu, "ModesPieChart", Localize("#KILLS_GAMEMODE"), modesPlayedData ) //######################################### // Time Stats From 64f22ff64876f08f41fe875edc96438f68b49bc1 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 11 Jun 2023 17:52:28 +0200 Subject: [PATCH 38/71] Update pulse_english.txt --- .../mod/resource/pulse_english.txt | Bin 1036 -> 1006 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_english.txt b/mods/ToneAPI.pulse/mod/resource/pulse_english.txt index 179cb0daeb2df2d1f08bab2831628829910faeef..dcfcf51d5dfdfa1a52dee9e3e4bceb6e5a935bae 100644 GIT binary patch delta 21 dcmeC-c*nkB0u!Us#6t1O0?b^SFEH6K0sv0726_Mh delta 42 tcmaFI-ovqB0+Xx)LpXy6gC~OzgDZmq5C<}Z0(k*I=*r--xt}SX5dg@X2%`W1 From 283134f4557ceed9598deadac963c13cb5b09ad5 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 11 Jun 2023 17:57:16 +0200 Subject: [PATCH 39/71] German localisation #30 Courtesy of NoCatt https://github.com/NoCatt --- mods/ToneAPI.pulse/mod/resource/pulse_german.txt | Bin 0 -> 1064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/resource/pulse_german.txt diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_german.txt b/mods/ToneAPI.pulse/mod/resource/pulse_german.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b69447233b4dc0d045a2213f89d921c2b792a03 GIT binary patch literal 1064 zcmbtUK~BRk5S%j-f3W-$t4-S|34}PIh)cx*^#BwJ#0mB5!0g7x2_&KtvYcIe*W=k) zE1w@0kGR7Ddsv*~4Db3i=!ZoaqHnZ&+%wB?iuZyijrHf!i5AazVElmBfEi|q~|`ZqY@3%7E8I{*Lx literal 0 HcmV?d00001 From 52387afe33fbadf74f7fef90f2dee944f86c0d4b Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:18:59 +0200 Subject: [PATCH 40/71] Polish localisation #30 --- .../ToneAPI.pulse/mod/resource/pulse_polish..txt | Bin 0 -> 1120 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/resource/pulse_polish..txt diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_polish..txt b/mods/ToneAPI.pulse/mod/resource/pulse_polish..txt new file mode 100644 index 0000000000000000000000000000000000000000..a16931437574c046b0a946f15f34efc0f5e4e65e GIT binary patch literal 1120 zcmb7EO;3YB5Pc+`OuT#C@K2VHR9ZkRD1i&{&{SiihsKlXuk`<@Zx&WQENKl{W|^IN zZ{F;L?=KfSJmM8wxVXY4KFnL8eO$!d={xNf8%8Ovjmg;I8GAf+nSD-yH@ujb{p4(n z-e;r;k#OaRxEhq)Yh<`Z+A(@q^UHS>J;T_xYKvs8JBb=2Hh3Uc6{U&k({C@&;~mWPQF@?R z&yDF{Nh{ryzJ|DCUc@`fxDRYcM|U`fnh-NHh`kcm%=EDyrHoe8Cpj`7r%{Jhcetav zWPbmPS+HKKGN*E>N6}N6*^yh$IY}jbQw^u Date: Sun, 11 Jun 2023 18:28:46 +0200 Subject: [PATCH 41/71] Italian localisation #30 Courtesy of 4lready-taken (4lready-taken in-game) --- .../ToneAPI.pulse/mod/resource/pulse_italian.txt | Bin 0 -> 1092 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/resource/pulse_italian.txt diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt b/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt new file mode 100644 index 0000000000000000000000000000000000000000..dfa318d037b2f35019022adac6e6ed0e2490bf05 GIT binary patch literal 1092 zcmbVK!A^rf6r8h(|3LOnHpR3=CeLC)0oP%hZ`&R-hDW3|V$z-ceiFqA`oOYw`qd=2-f%r#bri zmqZnx{D^Zv88}=rlQ}QYv^=Qg1 z%}3$Tx|$5N7^02)pgB_CG*dpa;Q2guU$;l^PtSi*Yw8Y_#;m<+JACi-)$~yvmp{>o dYR;?9X7N?OrdBg8KaTwh6WX7kgPYj{egLRzf#3iD literal 0 HcmV?d00001 From 16ef610d57fee5f128abe51d83aac8c1d82784f6 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:46:01 +0200 Subject: [PATCH 42/71] Fix typo in polish localisation filename --- .../{pulse_polish..txt => pulse_polish.txt} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename mods/ToneAPI.pulse/mod/resource/{pulse_polish..txt => pulse_polish.txt} (100%) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_polish..txt b/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt similarity index 100% rename from mods/ToneAPI.pulse/mod/resource/pulse_polish..txt rename to mods/ToneAPI.pulse/mod/resource/pulse_polish.txt From 58a31f6b67d37985108662773acf205f8d706a5e Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Mon, 12 Jun 2023 21:55:25 +0200 Subject: [PATCH 43/71] French localisation #30 Courtesy of @Legonzaur Co-Authored-By: Legonzaur <34353603+Legonzaur@users.noreply.github.com> --- mods/ToneAPI.pulse/mod/resource/pulse_french.txt | Bin 0 -> 1034 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/resource/pulse_french.txt diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_french.txt b/mods/ToneAPI.pulse/mod/resource/pulse_french.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2a09b09027a7a11ed0cf709f6ad8ca26017dc2e GIT binary patch literal 1034 zcmb7D(N4oK47_I~{vpbrMC}-ZwkvJNc&iW^LjrBm5Km~o4xHVDbf`g^s>GgbpU>y) z`^(}DkJw=gi%VSKQ*VRevnYJ@gLaDzvkcEO4)k|;!i%qq6&?0?)#&@5*eQ0bs4zpx z(_+EXV@=69NRHF3v|eT^*{?xI28O+* zqtRQKr8;zEEb$(<^a_5$KcjW@TF?H9SdN^>$T8l{3&)|mHtE4)D<;e9~Raw)DMxxdXcdT1b=bC=*b&4BE>0J`9R Date: Mon, 12 Jun 2023 22:10:10 +0200 Subject: [PATCH 44/71] Update pulse_polish.txt #30 --- .../mod/resource/pulse_polish.txt | Bin 1120 -> 1064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt b/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt index a16931437574c046b0a946f15f34efc0f5e4e65e..7dd952ec4d33aa963dc3aacc1764be39dca01d5c 100644 GIT binary patch delta 115 zcmaFBv4UfR1f#ScgC_$EqXI)PLjZ$6LpTt-fN4htzsZfv(vw3Nt$1}A6d1f2d>9;o zsvIXClmrTjO}@dX0+tA2h-3%>O8J2#jF`;0L8?O-f`GzKK%vcZm?khX>PAAcT^L*$ zd>IrNyn#GNhG2%si3cSouVb{5#Z(f)5Xle%ROH9t2vWqyWQN6@5TJFDKube`N;YRO PO<-gNX$YSDlUW}C$4(wm From e361f4c5431446405d02e21c3b14be8d7cb076f6 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Mon, 12 Jun 2023 22:39:52 +0200 Subject: [PATCH 45/71] Update pulse_french.txt #30 Co-Authored-By: Legonzaur <34353603+Legonzaur@users.noreply.github.com> --- .../mod/resource/pulse_french.txt | Bin 1034 -> 1050 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_french.txt b/mods/ToneAPI.pulse/mod/resource/pulse_french.txt index f2a09b09027a7a11ed0cf709f6ad8ca26017dc2e..9831cc3365799325f392277bfe2d09dc999f01e8 100644 GIT binary patch delta 24 fcmeC;n8mR{f|1*q!I2@9A(-JLgX?Bt#_vo3NR Date: Tue, 13 Jun 2023 17:23:31 +0200 Subject: [PATCH 46/71] Delete README.md --- mods/ToneAPI.pulse/README.md | 80 ------------------------------------ 1 file changed, 80 deletions(-) delete mode 100644 mods/ToneAPI.pulse/README.md diff --git a/mods/ToneAPI.pulse/README.md b/mods/ToneAPI.pulse/README.md deleted file mode 100644 index 28d57de..0000000 --- a/mods/ToneAPI.pulse/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Pulse - -Pulse is a clientside mod for [TF|2 + Northstar](https://github.com/R2Northstar/Northstar) letting you view killstats collected by [the Tone API](https://toneapi.github.io/ToneAPI_webclient/) using the otherwise non-functional `Stats` tab. - -## Currently, features include: -- mostly functional `Overview` tab, -- functional `Time` tab, -- Pilot weapon data displayed in `Pilot Weapons` tab, -- Titan kills displayed in `Titans` tab, -- functional `Maps` tab, -- real-time updates. - -Want to know what we have planned for future updates? See [here.](https://github.com/ToneAPI/pulse/projects?query=is%3Aopen) - -Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/issues/new) - -
-Features, more in-depth: - -### `Overview` -- Most Kills - shows the weapon with most accumulated kills. -- Nemesis Weapon - shows the weapon that has killed you the most. -- Most Effective - shows weapon with the highest K/D ratio. -- Kill/Death Ratio - shows the overall K/D ratio of player compared to global K/D. -- Kills as Pilot - shows general kill data for player as Pilot, visualised in the table below: - - | Name | Description | - |--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| - | Pilots |Shows **ALL KILLS** accumulated by player as Pilot. Differentiating Pilot and Titan kills will come in a later Tone API update.| - | Titans |Non-functional, see line above.| - | AI kills |Non-functional, Tone API does not collect AI kill data.| - | Pilot melee kills |Shows only melee kills accumulated by player as Pilot.| - | Pilot executions |Shows only executions accumulated by player as Pilot.| - -- Kills as Titan - shows general kill data for player as Titan, visualised in the table below: - - | Name | Description | - |--------------------|------------------------------------------------------| - | Pilots |Shows **ALL KILLS** accumulated by player as Titan. Differentiating Pilot and Titan kills will come in a later Tone API update.| - | Titans |Non-functional, see line above.| - | Titan executions |Shows only executions accumulated by player as Titan.| - | Pilots meleed |Shows only melee kills accumulated by player as Titan.| - | Pilot roadkills |Shows only roadkills accumulated by player as Titan.| - -- Upper statbox values have been zeroed out, these don't yet work and are set to 0 to avoid confusion. - -### `Time` - -- Kills by Class shows kills by Pilot and Titan on a piechart. -- Kills by Titan shows kills by all Titan classes on a piechart. -- Kills by Gamemode shows kills on each gamemode played on a piechart. - -### `Pilot Weapons` - -- shows total accumulated kills per weapon under Total Kills. -- shows deaths with given weapon equipped under Deaths with Weapon. - -### `Titans` - -- shows total accumulated kills per Titan under Total Kills. - -### `Maps` - -- Player Map Stats - shows general data for player on chosen map, visualised in the table below: - - | Name | Description | - |-----------------------|------------------------------------------------------- | - | Kills on Map |Shows all kills accumulated by player on chosen map.| - | Deaths on Map |Shows all deaths accumulated by player on chosen map.| - | Total Shot Distance |Shows total distance of kills accumulated by player on chosen map.| - | Maximum Shot Distance |Shows highest distance kill by player on chosen map.| - -- Kills by Gamemode - piechart showing all kills (in percent) on chosen map by gamemode. -
- -## DISCLAIMER - -The Tone API is NOT used by every server, view a list of supported servers [here.](https://tone.sleepycat.date/v2/client/servers) - -Pulse is very much a W.I.P as of right now, features may be missing/nonfunctional. From bd6c98a59a524fd02ef7a9a557bed33ad0d7054c Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:27:22 +0200 Subject: [PATCH 47/71] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index af245a1..d8a03f6 100644 --- a/README.md +++ b/README.md @@ -89,4 +89,10 @@ The Tone API is NOT used by every server, view a list of supported servers [here - new parser, allowing for better expandability and faster data processing (and much simpler implementation, unlike the hellspawn that was the previous `getFromToneAPI` function), - new request function, more compact and simple than previous iterations, - other functions that simplify the code and make it easier to read / develop + - Localisation, currently available in: + - English, + - French, + - German, + - Italian, + - Polish. (Northstar isn't translated into Polish, but the game supports it.) From e81bd9c49d8f73ca07281f6654c790fc42958b3d Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:27:44 +0200 Subject: [PATCH 48/71] Clean up formatting of shown text #30 --- .../mod/resource/pulse_english.txt | Bin 1006 -> 1014 bytes .../mod/resource/pulse_french.txt | Bin 1050 -> 1058 bytes .../mod/resource/pulse_german.txt | Bin 1064 -> 1072 bytes .../mod/resource/pulse_italian.txt | Bin 1092 -> 1100 bytes .../mod/resource/pulse_polish.txt | Bin 1064 -> 1072 bytes .../vscripts/ui/menu_stats_overview.nut | 4 ++-- 6 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_english.txt b/mods/ToneAPI.pulse/mod/resource/pulse_english.txt index dcfcf51d5dfdfa1a52dee9e3e4bceb6e5a935bae..7869b0d6dadb1ef620f9609d299442210a27e58f 100644 GIT binary patch delta 20 bcmaFI{*8SD4Y$mKM4gy delta 16 Xcmeyy{*HYE594GpX1>izj8~WdG5!S> diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_french.txt b/mods/ToneAPI.pulse/mod/resource/pulse_french.txt index 9831cc3365799325f392277bfe2d09dc999f01e8..2f854cefe8b4b96740f0503aea625bbc67438602 100644 GIT binary patch delta 20 bcmbQmv4~>>4lAf*;N^e84MW|HnTG-G6MiI`UCL* delta 12 TcmdnMv4Ud*2jgY|Mg?X789xIF diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt b/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt index dfa318d037b2f35019022adac6e6ed0e2490bf05..bf7734ce1d9f4e9d7eb3f56e2dec32cd457ff242 100644 GIT binary patch delta 20 bcmX@YafV|92P3;GLotIPgTiKZMq6e8H(CTm delta 12 TcmX@ZafD+72jgY|MjK`T8{Y$6 diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt b/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt index 7dd952ec4d33aa963dc3aacc1764be39dca01d5c..b13878f549fd0a98749360ce002e9290039f3bd1 100644 GIT binary patch delta 20 acmZ3%u>lAf*;N^e84MW|HnTG-G6MiI`UCL* delta 16 XcmdnMv4Ud*2jgT5W}(eWjC{-hDOUsO diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut index 23fe3a2..2884033 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -218,7 +218,7 @@ function UpdateViewStatsOverviewMenu() Hud_Show( weaponImageElem ) Hud_SetText( weaponNameElem, nemesisWeapon.printName ) Hud_Show( weaponNameElem ) - Hud_SetText( weaponDescElem, nemesisWeapon.val + " " + Localize("#NEMESIS_WEAPON_VALUE")) + Hud_SetText( weaponDescElem, Localize("#NEMESIS_WEAPON_VALUE"), nemesisWeapon.val) Hud_Show( weaponDescElem ) Hud_Hide( noDataElem ) } @@ -243,7 +243,7 @@ function UpdateViewStatsOverviewMenu() Hud_Show( weaponImageElem ) Hud_SetText( weaponNameElem, highestKPMData.printName ) Hud_Show( weaponNameElem ) - Hud_SetText( weaponDescElem, highestKPMData.val + " K/D") + Hud_SetText( weaponDescElem, "%s1 K/D", highestKPMData.val) Hud_Show( weaponDescElem ) Hud_Hide( noDataElem ) } From aa979e6bb4919b6f3faf908036877bf822f444dd Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:38:32 +0200 Subject: [PATCH 49/71] Lock Stats tab until data has been gathered #27 --- .../mod/scripts/vscripts/pulse-common-func.gnut | 3 +++ .../mod/scripts/vscripts/ui/menu_lobby.nut | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 4c12684..c9428ef 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -3,6 +3,7 @@ globalize_all_functions global string pulsePrefix +global bool pulseSuccessBool = true table withMapName = {} void function pulsePrefixSet() //Sets our prefix { @@ -28,10 +29,12 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } else { pulseData[tablepath] <- DecodedJSON } + pulseSuccessBool = false } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) { pulsePrintt("Something went wrong while getting data.") + pulseSuccessBool = true } foreach (key, value in parameterTable) { diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut index cd743ed..3a2be2f 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut @@ -540,13 +540,21 @@ void function Lobby_RefreshButtons() } } +void function GetStats() +{ + Hud_SetLocked(file.statsButton, pulseSuccessBool) + waitthread pulseGetData() + wait 0.5 //temporary + Hud_SetLocked(file.statsButton, pulseSuccessBool) +} + void function OnLobbyMenu_Open() { Assert( IsConnected() ) // code will start loading DLC info from first party unless already done InitDLCStore() - waitthread pulseGetData() + thread GetStats() thread UpdateCachedNewItems() if ( file.putPlayerInMatchmakingAfterDelay ) From 8501955cea2173378c3c6c44fbcd9f82afda1ba9 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 13 Jun 2023 20:06:51 +0200 Subject: [PATCH 50/71] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d8a03f6..a26d789 100644 --- a/README.md +++ b/README.md @@ -95,4 +95,5 @@ The Tone API is NOT used by every server, view a list of supported servers [here - German, - Italian, - Polish. (Northstar isn't translated into Polish, but the game supports it.) + - Locking the Stats tab, avoiding situations where you could click too fast and see no stats. Also prevents the game from showing stats when the API is unreachable. From 1d6b09537f34d14c22a1b9ff541ce90dd6f2c707 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 15 Jun 2023 19:02:54 +0200 Subject: [PATCH 51/71] Add status code checking to request function "Borrowed" from the servermod --- .../scripts/vscripts/pulse-common-func.gnut | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index c9428ef..a740c3c 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -18,18 +18,23 @@ void function pulsePrintt(string content) //Prints whatever we want printed with bool function pulseRequestData(string givenURL, table parameterTable, string tablepath) //Gets data from API (see ToneURL within mod.json) and puts it into one table for processing. { table > requestTable - void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (parameterTable, requestTable, tablepath) + void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (givenURL, parameterTable, requestTable, tablepath) { - table DecodedJSON = DecodeJSON(response.body) - if ("map" in parameterTable) - { - string mapName = expect string(parameterTable["map"]) - withMapName[mapName] <- DecodedJSON - pulseData[tablepath] <- withMapName + if(response.statusCode == 200 || response.statusCode == 201){ + table DecodedJSON = DecodeJSON(response.body) + if ("map" in parameterTable) + { + string mapName = expect string(parameterTable["map"]) + withMapName[mapName] <- DecodedJSON + pulseData[tablepath] <- withMapName + } else { + pulseData[tablepath] <- DecodedJSON + } + pulseSuccessBool = false } else { - pulseData[tablepath] <- DecodedJSON + pulseSuccessBool = true + pulsePrintt(format("%s %s is unreachable.", response.statusCode, givenURL)) } - pulseSuccessBool = false } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) { From 81b1b4f928c1b3436f1cd27b25e56872c75b052f Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Thu, 15 Jun 2023 19:22:06 +0200 Subject: [PATCH 52/71] Cleanup in menu_stats_overview.nut --- .../vscripts/ui/menu_stats_overview.nut | 46 ++++++------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut index 2884033..89b3dd0 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -32,7 +32,7 @@ void function InitViewStatsOverviewMenu() AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) } -void function GetTitanKills( string titanName ) +void function GetTitanKills() { file.allTitans = GetVisibleItemsOfType( eItemTypes.TITAN ) var dataTable = GetDataTable( $"datatable/titan_properties.rpak" ) @@ -50,9 +50,12 @@ void function GetTitanKills( string titanName ) file.titanStatLoadout[ titan.ref ].append( GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "melee" ) ) ) } - foreach ( weaponRef in file.titanStatLoadout[ titanName ]) + foreach ( titan in file.allTitans) { - titanKillData[weaponRef] <- pulseParse("weaponsLocal", weaponRef, "kills") + foreach ( weaponRef in file.titanStatLoadout[ titan.ref ]) + { + titanKillData[weaponRef] <- pulseParse("weaponsLocal", weaponRef, "kills") + } } } @@ -68,15 +71,7 @@ void function GetAllPilotWeapons() void function OnStatsOverview_Open() { UI_SetPresentationType( ePresentationType.NO_MODELS ) - - GetTitanKills("ion") - GetTitanKills("scorch") - GetTitanKills("northstar") - GetTitanKills("ronin") - GetTitanKills("tone") - GetTitanKills("legion") - GetTitanKills("vanguard") - + GetTitanKills() UpdateViewStatsOverviewMenu() } @@ -301,48 +296,35 @@ function UpdateViewStatsOverviewMenu() // Lifetime table playerweaponData = expect table(pulseData["weaponsLocal"]) table globalweaponData = expect table(pulseData["weaponsGlobal"]) + + var totalPilotKills = 0 - - foreach (var key, var value in playerweaponData) { - table values = expect table(value) - totalPilotKills += values["kills"] - } - - var totalGlobalKills = 0 - foreach (var key, var value in globalweaponData) { - table values = expect table(value) - totalGlobalKills += values["kills"] - } - var totalPilotDeaths = 0 foreach (var key, var value in playerweaponData) { table values = expect table(value) + totalPilotKills += values["kills"] totalPilotDeaths += values["deaths"] } + var totalGlobalKills = 0 var totalGlobalDeaths = 0 foreach (var key, var value in globalweaponData) { table values = expect table(value) + totalGlobalKills += values["kills"] totalGlobalDeaths += values["deaths"] } + var killsAsTitan = 0 var killsAsPilot = 0 foreach (var key, var value in playerweaponData) { if (key in titanKillData) { - continue + killsAsTitan += titanKillData[string(key)] } else { killsAsPilot += pulseParse("weaponsLocal", string(key), "kills") } } - var killsAsTitan = 0 - foreach (var key, var value in playerweaponData) { - if (key in titanKillData) { - killsAsTitan += titanKillData[string(key)] - } - } - float kval = float(totalPilotKills) float dval = float(totalPilotDeaths) float kdval = float(int((kval / dval)*100))/100 From d4efc94e7d94ce71e248e08c65997196d12c9667 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:42:18 +0200 Subject: [PATCH 53/71] Add missing comma --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index a740c3c..22105d9 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -33,7 +33,7 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab pulseSuccessBool = false } else { pulseSuccessBool = true - pulsePrintt(format("%s %s is unreachable.", response.statusCode, givenURL)) + pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) } } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) From e1d5801d9a62a51f1e7481be5baf256a3dfa9481 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 16:30:02 +0200 Subject: [PATCH 54/71] Add melee_pilot_kunai into the melee kill stat --- .../mod/scripts/vscripts/ui/menu_stats_overview.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut index 89b3dd0..8cc6f46 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_overview.nut @@ -389,7 +389,7 @@ function UpdateViewStatsOverviewMenu() Hud_SetText( GetElem( file.menu, "KillsAsPilotValue0" ), string( killsAsPilot ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue1" ), string( GetPlayerStatInt( player, "kills_stats", "titanKillsAsPilot" ) ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue2" ), string( GetPlayerStatInt( player, "kills_stats", "totalNPC" ) ) ) - Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( pulseParse("weaponsLocal", "pilot_emptyhanded", "kills") ) ) + Hud_SetText( GetElem( file.menu, "KillsAsPilotValue3" ), string( pulseParse("weaponsLocal", "pilot_emptyhanded", "kills") + pulseParse("weaponsLocal", "melee_pilot_kunai", "kills") ) ) Hud_SetText( GetElem( file.menu, "KillsAsPilotValue4" ), string( pulseParse("weaponsLocal", "human_execution", "kills") ) ) // Hud_SetText( GetElem( file.menu, "KillsAsPilotValue5" ), string( GetPlayerStatInt( player, "kills_stats", "titanFallKill" ) ) ) From ff06daefae76e2059d43fd5a3aed97804cf2f2bd Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:15:47 +0200 Subject: [PATCH 55/71] Use NsIsSuccessHttpCode() for status code checking --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 22105d9..8fc4afe 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -20,7 +20,7 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab table > requestTable void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (givenURL, parameterTable, requestTable, tablepath) { - if(response.statusCode == 200 || response.statusCode == 201){ + if (NSIsSuccessHttpCode(response.statusCode)){ table DecodedJSON = DecodeJSON(response.body) if ("map" in parameterTable) { From a8bbd9ea39e23e50152237fdb3b434114d74b519 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:16:17 +0200 Subject: [PATCH 56/71] Fix typo in english localisation --- .../mod/resource/pulse_english.txt | Bin 1014 -> 1034 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_english.txt b/mods/ToneAPI.pulse/mod/resource/pulse_english.txt index 7869b0d6dadb1ef620f9609d299442210a27e58f..041ccd6528a8787ae223c4f77f67b00fe7f7c146 100644 GIT binary patch delta 21 dcmeyy-o>$D1{13SLkNTa#O>;vH!!&|0su~V2E70P delta 21 dcmeC;_{P3r1{0&w#6t1O8<@E^pJTFN1OQZ=2POaj From c1cd3a6fc7fd20af60a8bed91a93ea29329aae1b Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:17:52 +0200 Subject: [PATCH 57/71] Format code --- .../mod/scripts/vscripts/pulse-common-func.gnut | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 8fc4afe..3d666b8 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -20,7 +20,8 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab table > requestTable void functionref (HttpRequestResponse) onSuccess = void function(HttpRequestResponse response) : (givenURL, parameterTable, requestTable, tablepath) { - if (NSIsSuccessHttpCode(response.statusCode)){ + if (NSIsSuccessHttpCode(response.statusCode)) + { table DecodedJSON = DecodeJSON(response.body) if ("map" in parameterTable) { @@ -56,7 +57,7 @@ int function pulseParse(...) //Returns data from our pulseData table. if (i < expect int(vargc) - 1) { if (expect string (vargv[i]) in parser) { parser = expect table(parser[expect string(vargv[i])]) - } else {break} + } else break } else { result = expect int(parser[expect string(vargv[i])]) } From ba0c4d11c775cc449ff4097a09f2554abb664d37 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:20:55 +0200 Subject: [PATCH 58/71] Change request failure message --- .../ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 3d666b8..976c813 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -37,9 +37,9 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) } } - void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) + void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (givenURL) { - pulsePrintt("Something went wrong while getting data.") + pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) pulseSuccessBool = true } foreach (key, value in parameterTable) From df4ee8fb0c3f8fed2e0c365294dfb7f3f7a59991 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:21:49 +0200 Subject: [PATCH 59/71] Rename pulseSuccessBool to pulseFailure --- .../mod/scripts/vscripts/pulse-common-func.gnut | 8 ++++---- mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 976c813..f2c9000 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -3,7 +3,7 @@ globalize_all_functions global string pulsePrefix -global bool pulseSuccessBool = true +global bool pulseFailure = true table withMapName = {} void function pulsePrefixSet() //Sets our prefix { @@ -31,16 +31,16 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } else { pulseData[tablepath] <- DecodedJSON } - pulseSuccessBool = false + pulseFailure = false } else { - pulseSuccessBool = true + pulseFailure = true pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) } } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (givenURL) { pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) - pulseSuccessBool = true + pulseFailure = true } foreach (key, value in parameterTable) { diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut index 3a2be2f..530042a 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut @@ -542,10 +542,10 @@ void function Lobby_RefreshButtons() void function GetStats() { - Hud_SetLocked(file.statsButton, pulseSuccessBool) + Hud_SetLocked(file.statsButton, pulseFailure) waitthread pulseGetData() wait 0.5 //temporary - Hud_SetLocked(file.statsButton, pulseSuccessBool) + Hud_SetLocked(file.statsButton, pulseFailure) } void function OnLobbyMenu_Open() From c538dd44f37893fc85bf9bf2c704b080e9b06a66 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 20 Jun 2023 20:25:31 +0200 Subject: [PATCH 60/71] Hotfixes --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index f2c9000..eb09ab0 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -39,7 +39,7 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (givenURL) { - pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) + pulsePrintt(format("Something went wrong, %s is unreachable", givenURL)) pulseFailure = true } foreach (key, value in parameterTable) From 1c5ab1514bf0dd2fb9bf9cb3d124921c4bd4006b Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:36:41 +0200 Subject: [PATCH 61/71] Average kill distance calculation, better Hammer conversion --- .../mod/resource/pulse_english.txt | Bin 1034 -> 1118 bytes .../scripts/vscripts/pulse-common-func.gnut | 5 +++++ .../scripts/vscripts/ui/menu_stats_maps.nut | 8 ++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_english.txt b/mods/ToneAPI.pulse/mod/resource/pulse_english.txt index 041ccd6528a8787ae223c4f77f67b00fe7f7c146..0d3d7124758600d7d92d9ef76905b341c16362aa 100644 GIT binary patch delta 50 zcmeC;xW}>K8}sCO%rcUW48aU83`z_NK 0 && int((1.905 * value ))/100 > 0 ? string(int((1.905 * value ) )/100) + "m" : "0"; } \ No newline at end of file diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut index e43ddca..0e5f3d1 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_stats_maps.nut @@ -159,13 +159,13 @@ void function UpdateStatsForMap( string mapName ) SetStatsLabelValue( file.menu, "KillsValue1", pulseParse("maps", mapName.slice(3), "deaths") ) SetStatsLabelValue( file.menu, "KillsLabel2", Localize("#MAPS_TSD") ) - SetStatsLabelValue( file.menu, "KillsValue2", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "total_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue2", HammerToMeterString(float(pulseParse("maps", mapName.slice(3), "total_distance")))) SetStatsLabelValue( file.menu, "KillsLabel3", Localize("#MAPS_MSD") ) - SetStatsLabelValue( file.menu, "KillsValue3", string(int((1.905 * float(pulseParse("maps", mapName.slice(3), "max_distance") ) ) )/100) + "m" ) + SetStatsLabelValue( file.menu, "KillsValue3", HammerToMeterString(float(pulseParse("maps", mapName.slice(3), "max_distance")))) - SetStatsLabelValue( file.menu, "KillsLabel4", "--" ) - SetStatsLabelValue( file.menu, "KillsValue4", "--" ) + SetStatsLabelValue( file.menu, "KillsLabel4", Localize("#MAPS_ASD") ) + SetStatsLabelValue( file.menu, "KillsValue4", HammerToMeterString(float(pulseParse("maps", mapName.slice(3), "max_distance")) / float(pulseParse("maps", mapName.slice(3), "kills")))) //var anchorElem = Hud_GetChild( file.menu, "WeaponStatsBackground" ) //printt( Hud_GetX( anchorElem ) ) From b8879c3560917e39652f24eb6dd661f1874610c0 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:37:50 +0200 Subject: [PATCH 62/71] Update viewstats_maps.menu --- mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu index c1b505a..10bfa63 100644 --- a/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu +++ b/mods/ToneAPI.pulse/mod/resource/ui/menus/viewstats_maps.menu @@ -532,7 +532,7 @@ resource/ui/menus/viewstats_pve.menu visible 1 font Default_23 labelText "--" - allcaps 1 + allcaps 0 textAlignment center fgcolor_override "255 255 255 255" //bgcolor_override "0 255 0 100" From f7e4588f803b77e6319e054a75ff8ed9fbe326a3 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:44:04 +0200 Subject: [PATCH 63/71] Update localisation --- .../mod/resource/pulse_french.txt | Bin 1058 -> 1146 bytes .../mod/resource/pulse_german.txt | Bin 1072 -> 1168 bytes .../mod/resource/pulse_italian.txt | Bin 1100 -> 1190 bytes .../mod/resource/pulse_polish.txt | Bin 1072 -> 1150 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_french.txt b/mods/ToneAPI.pulse/mod/resource/pulse_french.txt index 2f854cefe8b4b96740f0503aea625bbc67438602..351f13f1fbb623b15f10f8bf25ef0a9d1450d313 100644 GIT binary patch delta 40 wcmZ3)@rz>vAIszjW*J7u$>*8nIsF+T8C)6s82l#BW|rruW#DDtVyI;R0N(BiIsgCw delta 28 bcmeyxv4~>>ABzYt0~dn=6xK3;c(n`wPSyk~ diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_german.txt b/mods/ToneAPI.pulse/mod/resource/pulse_german.txt index d1940731ac14b7a48a2ef07414c48651d9c53865..9ce43c046c83e3a4a4dfffbaa49a792d3f1a6051 100644 GIT binary patch delta 60 zcmdnMF@bY~49nyL%reT348aU83`z_NKvGgG L@G@{Q)G`17a|a6j delta 28 bcmbQhxq)MY42uXa0~dn=6xK3;c(n`wMh64l diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt b/mods/ToneAPI.pulse/mod/resource/pulse_italian.txt index bf7734ce1d9f4e9d7eb3f56e2dec32cd457ff242..e84956d8e19b622336502afdfb592174382d97a2 100644 GIT binary patch delta 79 zcmX@Zv5a$r1Dh+P;wfxHl)m>)wFkW^ssWpD+F VPL^ho6;J^3L9mvAmw^jN0sw674C4R* delta 11 ScmZ3+d4^+y1 diff --git a/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt b/mods/ToneAPI.pulse/mod/resource/pulse_polish.txt index b13878f549fd0a98749360ce002e9290039f3bd1..551af7bf9644730127363ce408ec2fe80ef6605b 100644 GIT binary patch delta 71 zcmdnM@sDG}3}!~X$qSjQC!P?RT)@nw>c|kx;KHE9pa8^Cj6n>pK%O6iCxatU#DyUe UC>z26(xAvu%fQRP#Zb!t0E6TX*Z=?k delta 42 qcmeyzv4La53}#M820w;ihRY1$lV>tli|{gVF(^P`Edz*G%K!lESqOyy From 11ae2bac909164457c7d8ece9225cd142c7195c8 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:30:26 +0200 Subject: [PATCH 64/71] Integrate with loeb #35 --- mods/ToneAPI.pulse/mod.json | 7 + .../scripts/vscripts/pulse-common-func.gnut | 4 - .../scripts/vscripts/pulse-loeb-component.nut | 18 + .../mod/scripts/vscripts/pulse.gnut | 29 +- .../mod/scripts/vscripts/ui/menu_lobby.nut | 1637 ----------------- 5 files changed, 48 insertions(+), 1647 deletions(-) create mode 100644 mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut delete mode 100644 mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut diff --git a/mods/ToneAPI.pulse/mod.json b/mods/ToneAPI.pulse/mod.json index 46a716b..5c96e32 100644 --- a/mods/ToneAPI.pulse/mod.json +++ b/mods/ToneAPI.pulse/mod.json @@ -24,6 +24,13 @@ "UICallback": { "After": "pulseInit" } + }, + { + "Path": "pulse-loeb-component.nut", + "RunOn": "UI", + "UICallback": { + "After": "pulseRegisterWithLoeb" + } } ], "Localisation": [ diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index d09953c..37461ac 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -3,7 +3,6 @@ globalize_all_functions global string pulsePrefix -global bool pulseFailure = true table withMapName = {} void function pulsePrefixSet() //Sets our prefix { @@ -31,16 +30,13 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } else { pulseData[tablepath] <- DecodedJSON } - pulseFailure = false } else { - pulseFailure = true pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) } } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (givenURL) { pulsePrintt(format("Something went wrong, %s is unreachable", givenURL)) - pulseFailure = true } foreach (key, value in parameterTable) { diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut new file mode 100644 index 0000000..1f4b592 --- /dev/null +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut @@ -0,0 +1,18 @@ +global function pulseRegisterWithLoeb +global function pulseLoebFunc + +void function pulseRegisterWithLoeb() +{ + loebLogMod(pulseLoebFunc()) +} + +void function pulseLoebFunc() +{ + print("func called") + GetStats() +} + +void function GetStats() +{ + loebSetLockedButton(Localize("#MENU_TITLE_STATS"), pulseGetData()) +} \ No newline at end of file diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut index a2efbe9..a9eb9c3 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut @@ -14,17 +14,34 @@ void function pulseInit() pulsePrintt("Initialized.") } -void function pulseGetData() +bool function pulseGetData() { + print("data getter called") string URL = GetConVarString("ToneURL") array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] array tablepath = ["weaponsLocal", "weaponsGlobal", "gamemodesAll", "gamemodesSeparated", "maps"] - pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0]) - pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1]) - pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2]) + if (!pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0])) + { + return true + } + if (!pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1])) + { + return true + } + if (!pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2])) + { + return true + } foreach (map in file.allMaps) { - pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3]) + if (!pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3])) + { + return true + } } - pulseRequestData(URL + URLpath[4], {["player"] = NSGetLocalPlayerUID()}, tablepath[4]) + if (!pulseRequestData(URL + URLpath[4], {["player"] = NSGetLocalPlayerUID()}, tablepath[4])) + { + return true + } + return false } \ No newline at end of file diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut deleted file mode 100644 index 530042a..0000000 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/ui/menu_lobby.nut +++ /dev/null @@ -1,1637 +0,0 @@ -untyped - - -global function MenuLobby_Init - -global function InitLobbyMenu -global function UICodeCallback_SetupPlayerListGenElements -global function UpdateAnnouncementDialog -global function EnableButton -global function DisableButton - -global function UICodeCallback_CommunityUpdated -global function UICodeCallback_FactionUpdated -global function Lobby_UpdateInboxButtons - -global function GetTimeToRestartMatchMaking - -global function RefreshCreditsAvailable - -global function InviteFriendsIfAllowed -global function SetPutPlayerInMatchmakingAfterDelay - -global function DLCStoreShouldBeMarkedAsNew - -global function SetNextAutoMatchmakingPlaylist -global function GetNextAutoMatchmakingPlaylist - -global function OnDpadCommsButton_Activate - -global function GetActiveSearchingPlaylist - -global function Lobby_SetFDModeBasedOnSearching -global function Lobby_IsFDMode -global function Lobby_SetAutoFDOpen -global function Lobby_SetFDMode -global function Lobby_ToggleFDMode -global function Lobby_CallsignButton3EventHandler -global function Lobby_RefreshButtons - -global function OnStoreButton_Activate -global function OnStoreBundlesButton_Activate -global function OnStoreNewReleasesButton_Activate - -const string MATCHMAKING_AUDIO_CONNECTING = "menu_campaignsummary_titanunlocked" - -struct -{ - struct { - string playlistName = "" - int mapIdx = -1 - int modeIdx = -1 - } preCacheInfo - - array searchIconElems - array searchTextElems - array matchStartCountdownElems - array matchStatusRuis - - array creditsAvailableElems - - var chatroomMenu - var chatroomMenu_chatroomWidget - - var findGameButton - var inviteRoomButton - var inviteFriendsButton - var inviteFriendsToNetworkButton - var toggleMenuModeButton - - var networksMoreButton - - int inboxHeaderIndex - var inboxButton - - int customizeHeaderIndex - var pilotButton - var titanButton - var boostsButton - var storeButton - var storeNewReleasesButton - var storeBundlesButton - var factionButton - var bannerButton - var patchButton - var statsButton - var networksHeader - var settingsHeader - var storeHeader - var browseNetworkButton - var faqButton - var dpadCommsButton - - var genUpButton - - array lobbyButtons - var playHeader - var customizeHeader - var callsignHeader - - float timeToRestartMatchMaking = 0 - - string nextAutoMatchmakingPlaylist - - var callsignCard - - bool putPlayerInMatchmakingAfterDelay = false - float matchmakingStartTime = 0.0 - int etaTime = 0 - int etaMaxMinutes = 15 - string lastMixtapeMatchmakingStatus - - ComboStruct &lobbyComboStruct - - bool isFDMode = false - bool shouldAutoOpenFDMenu = false -} file - -void function MenuLobby_Init() -{ - PrecacheHUDMaterial( $"ui/menu/lobby/player_hover" ) - PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_player" ) - PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_hover" ) - PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background" ) - PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background_happyhour" ) - - AddUICallback_OnLevelInit( OnLobbyLevelInit ) -} - - -bool function ChatroomIsVisibleAndFocused() -{ - return Hud_IsVisible( file.chatroomMenu ) && Hud_IsFocused( file.chatroomMenu_chatroomWidget ); -} - -bool function ChatroomIsVisibleAndNotFocused() -{ - return Hud_IsVisible( file.chatroomMenu ) && !Hud_IsFocused( file.chatroomMenu_chatroomWidget ); -} - -void function Lobby_UpdateInboxButtons() -{ - var menu = GetMenu( "LobbyMenu" ) - if ( GetUIPlayer() == null || !IsPersistenceAvailable() ) - return - - bool hasNewMail = (Inbox_HasUnreadMessages() && Inbox_GetTotalMessageCount() > 0) || PlayerRandomUnlock_GetTotal( GetUIPlayer() ) > 0 - if ( hasNewMail ) - { - int messageCount = Inbox_GetTotalMessageCount() - int lootCount = PlayerRandomUnlock_GetTotal( GetUIPlayer() ) - int totalCount = messageCount + lootCount - - string countString - if ( totalCount >= MAX_MAIL_COUNT ) - countString = MAX_MAIL_COUNT + "+" - else - countString = string( totalCount ) - - SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS_NEW_MSGS", countString ) ) - ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_INBOX_NEW_MSGS", countString ) ) - } - else - { - SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS" ) ) - ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_READ" ) ) - } - - ComboButton_SetNewMail( file.inboxButton, hasNewMail ) -} - -void function InitLobbyMenu() -{ - var menu = GetMenu( "LobbyMenu" ) - - InitOpenInvitesMenu() - - AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT", "", null, ChatroomIsVisibleAndNotFocused ) - AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) - AddMenuFooterOption( menu, BUTTON_BACK, "#BACK_BUTTON_POSTGAME_REPORT", "#POSTGAME_REPORT", OpenPostGameMenu, IsPostGameMenuValid ) - AddMenuFooterOption( menu, BUTTON_TRIGGER_RIGHT, "#R_TRIGGER_CHAT", "", null, IsVoiceChatPushToTalk ) - - InitChatroom( menu ) - - file.chatroomMenu = Hud_GetChild( menu, "ChatRoomPanel" ) - file.chatroomMenu_chatroomWidget = Hud_GetChild( file.chatroomMenu, "ChatRoom" ) - file.genUpButton = Hud_GetChild( menu, "GenUpButton" ) - - SetupComboButtonTest( menu ) - - AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnLobbyMenu_Open ) - AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnLobbyMenu_Close ) - AddMenuEventHandler( menu, eUIEvent.MENU_NAVIGATE_BACK, OnLobbyMenu_NavigateBack ) - - RegisterUIVarChangeCallback( "gameStartTime", GameStartTime_Changed ) - - RegisterUIVarChangeCallback( "showGameSummary", ShowGameSummary_Changed ) - - file.searchIconElems = GetElementsByClassnameForMenus( "SearchIconClass", uiGlobal.allMenus ) - file.searchTextElems = GetElementsByClassnameForMenus( "SearchTextClass", uiGlobal.allMenus ) - file.matchStartCountdownElems = GetElementsByClassnameForMenus( "MatchStartCountdownClass", uiGlobal.allMenus ) - file.matchStatusRuis = GetElementsByClassnameForMenus( "MatchmakingStatusRui", uiGlobal.allMenus ) - file.creditsAvailableElems = GetElementsByClassnameForMenus( "CreditsAvailableClass", uiGlobal.allMenus ) - - file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) - - AddEventHandlerToButton( menu, "GenUpButton", UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "Generation_Respawn" ) ) ) - - AddMenuVarChangeHandler( "focus", UpdateFooterOptions ) - AddMenuVarChangeHandler( "isFullyConnected", UpdateFooterOptions ) - AddMenuVarChangeHandler( "isPartyLeader", UpdateFooterOptions ) - AddMenuVarChangeHandler( "isPrivateMatch", UpdateFooterOptions ) - #if DURANGO_PROG - AddMenuVarChangeHandler( "DURANGO_canInviteFriends", UpdateFooterOptions ) - AddMenuVarChangeHandler( "DURANGO_isJoinable", UpdateFooterOptions ) - AddMenuVarChangeHandler( "DURANGO_isGameFullyInstalled", UpdateFooterOptions ) - #elseif PS4_PROG - AddMenuVarChangeHandler( "PS4_canInviteFriends", UpdateFooterOptions ) - #elseif PC_PROG - AddMenuVarChangeHandler( "ORIGIN_isEnabled", UpdateFooterOptions ) - AddMenuVarChangeHandler( "ORIGIN_isJoinable", UpdateFooterOptions ) - #endif - - RegisterSignal( "BypassWaitBeforeRestartingMatchmaking" ) - RegisterSignal( "PutPlayerInMatchmakingAfterDelay" ) - RegisterSignal( "CancelRestartingMatchmaking" ) - RegisterSignal( "LeaveParty" ) -} - -void function SetupComboButtonTest( var menu ) -{ - ComboStruct comboStruct = ComboButtons_Create( menu ) - file.lobbyComboStruct = comboStruct - - int headerIndex = 0 - int buttonIndex = 0 - file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" ) - - bool isModded = IsNorthstarServer() - - - // this will be the server browser - if ( isModded ) - { - file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" ) - file.lobbyButtons.append( file.findGameButton ) - Hud_SetLocked( file.findGameButton, true ) - Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser ) - } - else - { - file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) - file.lobbyButtons.append( file.findGameButton ) - Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) - } - - // this is used for launching private matches now - if ( isModded ) - { - file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) - Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) - } - else - { - file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) - Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) - } - - file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) - Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed ) - - if ( isModded ) - { - Hud_SetEnabled( file.inviteFriendsButton, false ) - Hud_SetVisible( file.inviteFriendsButton, false ) - } - - // file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" ) - // Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode ) - - headerIndex++ - buttonIndex = 0 - file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" ) - file.customizeHeaderIndex = headerIndex - var pilotButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PILOT" ) - file.pilotButton = pilotButton - file.lobbyButtons.append( pilotButton ) - Hud_AddEventHandler( pilotButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditPilotLoadoutsMenu" ) ) ) - var titanButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_TITAN" ) - file.titanButton = titanButton - Hud_AddEventHandler( titanButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditTitanLoadoutsMenu" ) ) ) - file.boostsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BOOSTS" ) - Hud_AddEventHandler( file.boostsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "BurnCardMenu" ) ) ) - - headerIndex++ - buttonIndex = 0 - file.callsignHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_CALLSIGN" ) - file.bannerButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BANNER" ) - file.lobbyButtons.append( file.bannerButton ) - Hud_AddEventHandler( file.bannerButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignCardSelectMenu" ) ) ) - file.patchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PATCH" ) - Hud_AddEventHandler( file.patchButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignIconSelectMenu" ) ) ) - file.factionButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FACTION" ) - Hud_AddEventHandler( file.factionButton, UIE_CLICK, Lobby_CallsignButton3EventHandler ) - file.statsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STATS" ) - Hud_AddEventHandler( file.statsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStatsMenu" ) ) ) - - file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) - - headerIndex++ - buttonIndex = 0 - file.networksHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_NETWORKS" ) - file.inboxHeaderIndex = headerIndex - var networksInbox = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INBOX" ) - file.inboxButton = networksInbox - file.lobbyButtons.append( networksInbox ) - Hud_AddEventHandler( networksInbox, UIE_CLICK, OnInboxButton_Activate ) - var switchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_SWITCHCOMMUNITY" ) - Hud_AddEventHandler( switchButton, UIE_CLICK, OnSwitchButton_Activate ) - var browseButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_BROWSE_NETWORKS" ) - file.lobbyButtons.append( browseButton ) - Hud_AddEventHandler( browseButton, UIE_CLICK, OnBrowseNetworksButton_Activate ) - file.browseNetworkButton = browseButton - #if NETWORK_INVITE - file.inviteFriendsToNetworkButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#INVITE_FRIENDS" ) - file.lobbyButtons.append( file.inviteFriendsToNetworkButton ) - Hud_AddEventHandler( file.inviteFriendsToNetworkButton, UIE_CLICK, OnInviteFriendsToNetworkButton_Activate ) - #endif - - headerIndex++ - buttonIndex = 0 - file.storeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_STORE" ) - SetComboButtonHeaderTint( GetMenu( "LobbyMenu" ), headerIndex, true ) - file.storeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BROWSE" ) - Hud_AddEventHandler( file.storeButton, UIE_CLICK, OnStoreButton_Activate ) - file.storeNewReleasesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_NEW_RELEASES" ) - Hud_AddEventHandler( file.storeNewReleasesButton, UIE_CLICK, OnStoreNewReleasesButton_Activate ) - file.storeBundlesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BUNDLES" ) - Hud_AddEventHandler( file.storeBundlesButton, UIE_CLICK, OnStoreBundlesButton_Activate ) - - headerIndex++ - buttonIndex = 0 - file.settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) - var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_CONTROLS" ) - Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) - file.lobbyButtons.append( controlsButton ) - #if CONSOLE_PROG - var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) - Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) - #elseif PC_PROG - var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) - Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) - var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) - Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) - #endif - file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) - Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) - - comboStruct.navUpButtonDisabled = true - comboStruct.navDownButton = file.genUpButton - - ComboButtons_Finalize( comboStruct ) -} - -bool function MatchResultsExist() -{ - return true // TODO -} - -void function StartPrivateMatch( var button ) -{ - if ( Hud_IsLocked( button ) ) - return - - ClientCommand( "StartPrivateMatchSearch" ) -} - -void function DoRoomInviteIfAllowed( var button ) -{ - if ( Hud_IsLocked( button ) ) - return - - if ( !DoesCurrentCommunitySupportInvites() ) - { - OnBrowseNetworksButton_Activate( button ) - return - } - - entity player = GetUIPlayer() - - if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) - { - DisplayMatchmakingPenaltyDialog( player ) - return - } - - SendOpenInvite( true ) - OpenSelectedPlaylistMenu() -} - -void function DisplayMatchmakingPenaltyDialog( entity player ) -{ - int minutesRemaining = int( ceil( Player_GetRemainingMatchmakingDelay( player ) / 60) ) - if ( minutesRemaining <= 1 ) - ServerCallback_GenericDialog( 30, 31, true ) - else if ( minutesRemaining == 2 ) - ServerCallback_GenericDialog( 30, 32, true ) - else if ( minutesRemaining == 3 ) - ServerCallback_GenericDialog( 30, 33, true ) - else if ( minutesRemaining == 4 ) - ServerCallback_GenericDialog( 30, 34, true ) - else if ( minutesRemaining == 5 ) - ServerCallback_GenericDialog( 30, 35, true ) - else - ServerCallback_GenericDialog( 30, 36, true ) -} - -void function CreatePartyAndInviteFriends() -{ - if ( CanInvite() ) - { - while ( !PartyHasMembers() && !AmIPartyLeader() ) - { - ClientCommand( "createparty" ) - WaitFrameOrUntilLevelLoaded() - } - InviteFriends( file.inviteFriendsButton ) - } - else - { - printt( "Not inviting friends - CanInvite() returned false" ); - } -} - -void function ToggleLobbyMode( var button ) -{ - Lobby_ToggleFDMode() -} - -void function Lobby_ToggleFDMode() -{ - Hud_SetFocused( file.findGameButton ) - ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) - file.isFDMode = !file.isFDMode - Lobby_RefreshButtons() -} - -void function Lobby_CallsignButton3EventHandler( var button ) -{ - if ( Lobby_IsFDMode() ) - { - AdvanceMenu( GetMenu( "ViewStatsMenu" ) ) - } - else - { - AdvanceMenu( GetMenu( "FactionChoiceMenu" ) ) - } -} - -void function InviteFriendsIfAllowed( var button ) -{ - if ( Hud_IsLocked( button ) ) - return - - entity player = GetUIPlayer() - if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) - { - DisplayMatchmakingPenaltyDialog( player ) - return - } - - #if PC_PROG - if ( !Origin_IsOverlayAvailable() ) - { - PopUpOriginOverlayDisabledDialog() - return - } - #endif - - thread CreatePartyAndInviteFriends() -} - -bool function CanInvite() -{ - if ( Player_NextAvailableMatchmakingTime( GetUIPlayer() ) > 0 ) - return false - -#if DURANGO_PROG - return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "DURANGO_canInviteFriends" ) && GetMenuVarBool( "DURANGO_isJoinable" ) && GetMenuVarBool( "DURANGO_isGameFullyInstalled" ) ) - #elseif PS4_PROG - return GetMenuVarBool( "PS4_canInviteFriends" ) - #elseif PC_PROG - return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "ORIGIN_isEnabled" ) && GetMenuVarBool( "ORIGIN_isJoinable" ) && Origin_IsOverlayAvailable() ) - #endif -} - -void function Lobby_RefreshButtons() -{ - bool fdMode = Lobby_IsFDMode() - var menu = GetMenu( "LobbyMenu" ) - - if ( GetTopNonDialogMenu() == GetMenu( "LobbyMenu" ) ) - { - if ( fdMode ) - UI_SetPresentationType( ePresentationType.FD_MAIN ) - else - UI_SetPresentationType( ePresentationType.DEFAULT ) - } - - string buttonString = fdMode ? "#MENU_LOBBY_SWITCH_DEFAULT" : "#MENU_LOBBY_SWITCH_FD" - // ComboButton_SetText( file.toggleMenuModeButton, buttonString ) - - buttonString = fdMode ? "" : "#MENU_TITLE_BOOSTS" - Hud_SetEnabled( file.boostsButton, !fdMode ) - ComboButton_SetText( file.boostsButton, buttonString ) - - buttonString = fdMode ? "#MENU_TITLE_STATS" : "#MENU_TITLE_FACTION" - ComboButton_SetText( file.factionButton, buttonString ) - - buttonString = fdMode ? "" : "#MENU_TITLE_STATS" - Hud_SetEnabled( file.statsButton, !fdMode ) - ComboButton_SetText( file.statsButton, buttonString ) - - buttonString = fdMode ? "#MENU_HEADER_PLAY_FD" : "#MENU_HEADER_PLAY" - SetComboButtonHeaderTitle( menu, 0, buttonString ) - - if ( fdMode ) - Hud_Hide( Hud_GetChild( menu, "ImgTopBar" ) ) - else - Hud_Show( Hud_GetChild( menu, "ImgTopBar" ) ) - - ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) - - if ( fdMode ) - { - Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "" ) - } - else - { - Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "#MULTIPLAYER" ) - } -} - -void function GetStats() -{ - Hud_SetLocked(file.statsButton, pulseFailure) - waitthread pulseGetData() - wait 0.5 //temporary - Hud_SetLocked(file.statsButton, pulseFailure) -} - -void function OnLobbyMenu_Open() -{ - Assert( IsConnected() ) - - // code will start loading DLC info from first party unless already done - InitDLCStore() - thread GetStats() - - thread UpdateCachedNewItems() - if ( file.putPlayerInMatchmakingAfterDelay ) - { - entity player = GetUIPlayer() - if (IsValid( player )) - { - string playlistToSearch = expect string( player.GetPersistentVar( "lastPlaylist" ) ) - string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() - if ( nextAutoPlaylist.len() > 0 ) - playlistToSearch = nextAutoPlaylist - - Lobby_SetFDModeBasedOnSearching( playlistToSearch ) - } - AdvanceMenu( GetMenu( "SearchMenu" ) ) - thread PutPlayerInMatchmakingAfterDelay() - file.putPlayerInMatchmakingAfterDelay = false - } - else if ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) ) - Lobby_SetFDMode( false ) - - thread UpdateLobbyUI() - thread LobbyMenuUpdate( GetMenu( "LobbyMenu" ) ) - - Hud_Show( file.chatroomMenu ) - - Lobby_RefreshButtons() - - if ( IsFullyConnected() ) - { - entity player = GetUIPlayer() - if ( !IsValid( player ) ) - return - - while ( IsPersistenceAvailable() && (player.GetPersistentVarAsInt( "initializedVersion" ) < PERSISTENCE_INIT_VERSION) ) - { - WaitFrame() - } - if ( !IsPersistenceAvailable() ) - return - - // Clear hidden boosts - array boosts = GetAllItemsOfType( eItemTypes.BURN_METER_REWARD ) - foreach ( boost in boosts ) - { - if ( boost.hidden ) - { - ClearNewStatus( null, boost.ref ) - } - } - - UpdateCallsignElement( file.callsignCard ) - RefreshCreditsAvailable() - - bool emotesAreEnabled = EmotesEnabled() - // "Customize" - { - bool anyNewPilotItems = HasAnyNewPilotItems( player ) - bool anyNewTitanItems = HasAnyNewTitanItems( player ) - bool anyNewBoosts = HasAnyNewBoosts( player ) - bool anyNewCommsIcons = emotesAreEnabled ? HasAnyNewDpadCommsIcons( player ) : false - bool anyNewCustomizeHeader = (anyNewPilotItems || anyNewTitanItems || anyNewBoosts || anyNewCommsIcons) - - RuiSetBool( Hud_GetRui( file.customizeHeader ), "isNew", anyNewCustomizeHeader ) - ComboButton_SetNew( file.pilotButton, anyNewPilotItems ) - ComboButton_SetNew( file.titanButton, anyNewTitanItems ) - ComboButton_SetNew( file.boostsButton, anyNewBoosts ) - } - - // "Store" - { - bool storeIsNew = DLCStoreShouldBeMarkedAsNew() - RuiSetBool( Hud_GetRui( file.storeHeader ), "isNew", storeIsNew ) - ComboButton_SetNew( file.storeButton, storeIsNew ) - } - - // "Callsign" - { - bool anyNewBanners = HasAnyNewCallsignBanners( player ) - bool anyNewPatches = HasAnyNewCallsignPatches( player ) - bool anyNewFactions = HasAnyNewFactions( player ) && Lobby_IsFDMode() - bool anyNewCallsignHeader = (anyNewBanners || anyNewPatches || anyNewFactions) - - RuiSetBool( Hud_GetRui( file.callsignHeader ), "isNew", anyNewCallsignHeader ) - ComboButton_SetNew( file.bannerButton, anyNewBanners ) - ComboButton_SetNew( file.patchButton, anyNewPatches ) - ComboButton_SetNew( file.factionButton, anyNewFactions ) - } - - bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() - RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) - ComboButton_SetNew( file.faqButton, faqIsNew ) - - TryUnlockSRSCallsign() - - Lobby_UpdateInboxButtons() - - if ( file.shouldAutoOpenFDMenu ) - { - file.shouldAutoOpenFDMenu = false - AdvanceMenu( GetMenu( GetPlaylistMenuName() ) ) - AdvanceMenu( GetMenu( "FDMenu" ) ) - } - } -} - -bool function DLCStoreShouldBeMarkedAsNew() -{ - if ( !IsFullyConnected() ) - return false - - if ( !IsPersistenceAvailable() ) - return false - - bool hasSeenStore = expect bool( GetPersistentVar( "hasSeenStore" ) ) - bool result = (!hasSeenStore) - return result -} - -void function LobbyMenuUpdate( var menu ) -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - - while ( GetTopNonDialogMenu() == menu ) - { - bool inPendingOpenInvite = InPendingOpenInvite() - Hud_SetLocked( file.findGameButton, !IsPartyLeader() || inPendingOpenInvite ) - Hud_SetLocked( file.inviteRoomButton, IsOpenInviteVisible() || GetPartySize() > 1 || inPendingOpenInvite ) - Hud_SetLocked( file.inviteFriendsButton, inPendingOpenInvite ) - - bool canGenUp = false - if ( GetUIPlayer() ) - canGenUp = GetPersistentVarAsInt( "xp" ) == GetMaxPlayerXP() && GetGen() < MAX_GEN - - Hud_SetVisible( file.genUpButton, canGenUp ) - Hud_SetEnabled( file.genUpButton, canGenUp ) - - WaitFrame() - } -} - -void function SetNextAutoMatchmakingPlaylist( string playlistName ) -{ - file.nextAutoMatchmakingPlaylist = playlistName -} - -string function GetNextAutoMatchmakingPlaylist() -{ - return file.nextAutoMatchmakingPlaylist -} - -void function PutPlayerInMatchmakingAfterDelay() -{ - Signal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) - EndSignal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) - EndSignal( uiGlobal.signalDummy, "CancelRestartingMatchmaking" ) - EndSignal( uiGlobal.signalDummy, "LeaveParty" ) - EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - - if ( AreWeMatchmaking() ) //Party member, party leader is already searching - return - - entity player = GetUIPlayer() - if ( !player ) - return - - string lastPlaylist = expect string( player.GetPersistentVar( "lastPlaylist" ) ) - - //Bump player out of match making if they were playing coliseum and are out of tickets. - if ( ("coliseum" == lastPlaylist) && Player_GetColiseumTicketCount( GetLocalClientPlayer() ) <= 0 ) - { - SetNextAutoMatchmakingPlaylist( "" ) - return - } - - // Need to know if you were a party member before the countdown starts in case you leave - bool wasAPartyMemberThatIsNotLeader = AmIPartyMember() - waitthread WaitBeforeRestartingMatchmaking() - // Only the leader should proceed to start matchmaking - if ( wasAPartyMemberThatIsNotLeader ) - return - - if ( !Console_HasPermissionToPlayMultiplayer() ) - { - ClientCommand( "disconnect" ) - return - } - - string playlistToSearch = lastPlaylist - string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() - if ( nextAutoPlaylist.len() > 0 ) - playlistToSearch = nextAutoPlaylist - - StartMatchmakingPlaylists( playlistToSearch ) -} - -void function WaitBeforeRestartingMatchmaking() -{ - Signal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) - EndSignal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) - - float timeToWait - - bool isPartyMemberThatIsNotLeader = AmIPartyMember() - SetPutPlayerInMatchmakingAfterDelay( !isPartyMemberThatIsNotLeader ) - - if ( isPartyMemberThatIsNotLeader ) - timeToWait = 99999 //HACK, JFS - else - timeToWait = GetCurrentPlaylistVarFloat( "wait_before_restarting_matchmaking_time", 30.0 ) - - float timeToEnd = Time() + timeToWait - - UpdateTimeToRestartMatchmaking( timeToEnd ) - - OnThreadEnd( - function() : ( ) - { - UpdateTimeToRestartMatchmaking( 0.0 ) - UpdateFooterOptions() - } - ) - - if ( isPartyMemberThatIsNotLeader ) - { - while( Time() < timeToEnd ) //Hack hack, JFS. No appropriate signals for StartMatchmaking() being called. Replace when code gives us notifications about it - { - if ( isPartyMemberThatIsNotLeader != ( AmIPartyMember() ) ) //Party Status changed. Party leader probably left? - break - - if ( AreWeMatchmaking() ) //Need to break out if Party Leader brings us into matchmaking - break - - WaitFrame() - } - - } - else - { - wait timeToWait - } -} - -void function OnLobbyMenu_Close() -{ - Signal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) -} - -void function OnLobbyMenu_NavigateBack() -{ - if ( ChatroomIsVisibleAndFocused() ) - { - foreach ( button in file.lobbyButtons ) - { - if ( Hud_IsVisible( button ) && Hud_IsEnabled( button ) && !Hud_IsLocked( button ) ) - { - Hud_SetFocused( button ) - return - } - } - } - - if ( InPendingOpenInvite() ) - LeaveOpenInvite() - else - LeaveDialog() -} - -function GameStartTime_Changed() -{ - UpdateGameStartTimeCounter() -} - -function ShowGameSummary_Changed() -{ - if ( level.ui.showGameSummary ) - uiGlobal.EOGOpenInLobby = true -} - -function UpdateGameStartTimeCounter() -{ - if ( level.ui.gameStartTime == null ) - return - - MatchmakingSetSearchText( "#STARTING_IN_LOBBY" ) - MatchmakingSetCountdownTimer( expect float( level.ui.gameStartTime + 0.0 ), true ) - - HideMatchmakingStatusIcons() -} - -bool function MatchmakingStatusShouldShowAsActiveSearch( string matchmakingStatus ) -{ - if ( matchmakingStatus == "#MATCHMAKING_QUEUED" ) - return true - if ( matchmakingStatus == "#MATCHMAKING_ALLOCATING_SERVER" ) - return true - if ( matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" ) - return true - - return false -} - -string function GetActiveSearchingPlaylist() -{ - if ( !IsConnected() ) - return "" - if ( !AreWeMatchmaking() ) - return "" - - string matchmakingStatus = GetMyMatchmakingStatus() - if ( !MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) - return "" - - string param1 = GetMyMatchmakingStatusParam( 1 ) - return param1 -} - -float function CalcMatchmakingWaitTime() -{ - float result = ((file.matchmakingStartTime > 0.01) ? (Time() - file.matchmakingStartTime) : 0.0) - return result -} - -float function GetMixtapeWaitTimeForPlaylist( string playlistName ) -{ - float maxWaitTime = float( GetPlaylistVarOrUseValue( playlistName, "mixtape_timeout", "0" ) ) - return maxWaitTime -} - -void function UpdateRestartMatchmakingStatus( float time ) -{ - if ( AmIPartyMember() ) - { - MatchmakingSetSearchText( "#MATCHMAKING_WAIT_ON_PARTY_LEADER_RESTARTING_MATCHMAKING" ) - } - else - { - string statusText = "#MATCHMAKING_WAIT_BEFORE_RESTARTING_MATCHMAKING" - string matchmakeNowText = "" - if ( uiGlobal.activeMenu == GetMenu( "SearchMenu" ) ) - matchmakeNowText = Localize( "#MATCHMAKING_WAIT_MATCHMAKE_NOW" ) - MatchmakingSetSearchText( statusText, matchmakeNowText ) - MatchmakingSetCountdownTimer( time, false ) - } -} - -void function UpdateMatchmakingStatus() -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - - OnThreadEnd( - function() : () - { - printt( "Hiding all matchmaking elems due to UpdateMatchmakingStatus thread ending" ) - - HideMatchmakingStatusIcons() - - MatchmakingSetSearchText( "" ) - MatchmakingSetCountdownTimer( 0.0, true ) - - MatchmakingSetSearchVisible( false ) - MatchmakingSetCountdownVisible( false ) - } - ) - - MatchmakingSetSearchVisible( true ) - MatchmakingSetCountdownVisible( true ) - - var lobbyMenu = GetMenu( "LobbyMenu" ) - var searchMenu = GetMenu( "SearchMenu" ) - var postGameMenu = GetMenu( "PostGameMenu" ) - - string lastActiveSearchingPlaylist - file.matchmakingStartTime = 0.0 - file.etaTime = 0 - file.etaMaxMinutes = int( GetCurrentPlaylistVarOrUseValue( "etaMaxMinutes", file.etaMaxMinutes ) ) - file.lastMixtapeMatchmakingStatus = "" - - while ( true ) - { - int lobbyType = GetLobbyTypeScript() - string matchmakingStatus = GetMyMatchmakingStatus() - bool isConnectingToMatch = matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" - - { - string activeSearchingPlaylist = GetActiveSearchingPlaylist() - if ( lastActiveSearchingPlaylist != activeSearchingPlaylist ) - { - if ( activeSearchingPlaylist.len() > 0 ) - { - lastActiveSearchingPlaylist = activeSearchingPlaylist - file.matchmakingStartTime = Time() - } - else - { - lastActiveSearchingPlaylist = "" - file.matchmakingStartTime = 0.0 - } - } - - if ( isConnectingToMatch && (matchmakingStatus != file.lastMixtapeMatchmakingStatus) ) - { - EmitUISound( MATCHMAKING_AUDIO_CONNECTING ) - - int mixtape_version = GetMixtapeMatchmakingVersion() - if ( IsMixtapeVersionNew() ) - LogMixtapeHasNew( mixtape_version ) - } - - file.lastMixtapeMatchmakingStatus = matchmakingStatus - } - - if ( level.ui.gameStartTime != null || lobbyType == eLobbyType.PRIVATE_MATCH ) - { - if ( level.ui.gameStartTimerComplete ) - { - MatchmakingSetSearchText( matchmakingStatus, GetMyMatchmakingStatusParam( 1 ), GetMyMatchmakingStatusParam( 2 ), GetMyMatchmakingStatusParam( 3 ), GetMyMatchmakingStatusParam( 4 ) ) - } - - if ( uiGlobal.activeMenu == searchMenu ) - CloseActiveMenu() - } - else if ( GetTimeToRestartMatchMaking() > 0 ) - { - UpdateRestartMatchmakingStatus( GetTimeToRestartMatchMaking() ) - } - else if ( level.ui.gameStartTime == null ) - { - MatchmakingSetCountdownTimer( 0.0, true ) - MatchmakingSetSearchText( "" ) - HideMatchmakingStatusIcons() - - if ( !IsConnected() || !AreWeMatchmaking() ) - { - if ( uiGlobal.activeMenu == searchMenu ) - CloseActiveMenu() - } - else - { - ShowMatchmakingStatusIcons() - - if ( GetActiveMenu() == lobbyMenu && !IsMenuInMenuStack( searchMenu ) ) - { - CloseAllDialogs() - AdvanceMenu( searchMenu ) - } - - var statusEl = Hud_GetChild( searchMenu, "MatchmakingStatusBig" ) - if ( matchmakingStatus == "#MATCH_NOTHING" ) - { - Hud_Hide( statusEl ) - } - else if ( MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) - { - string playlistName = GetMyMatchmakingStatusParam( 1 ) - int etaSeconds = int( GetMyMatchmakingStatusParam( 2 ) ) - int mapIdx = int( GetMyMatchmakingStatusParam( 3 ) ) - int modeIdx = int( GetMyMatchmakingStatusParam( 4 ) ) - string playlistList = GetMyMatchmakingStatusParam( 5 ) - - { - string statusText = Localize( "#MATCHMAKING_PLAYLISTS" ) - RuiSetString( Hud_GetRui( statusEl ), "statusText", statusText ) - for ( int idx = 1; idx <= 5; ++idx ) - RuiSetString( Hud_GetRui( statusEl ), ("bulletPointText" + idx), "" ) - - const int MAX_SHOWN_PLAYLISTS = 9 - array< string > searchingPlaylists = split( playlistList, "," ) - int searchingCount = minint( searchingPlaylists.len(), MAX_SHOWN_PLAYLISTS ) - RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", searchingCount ) - for( int idx = 0; idx < searchingCount; ++idx ) - { - asset playlistThumbnail = GetPlaylistThumbnailImage( searchingPlaylists[idx] ) - RuiSetImage( Hud_GetRui( statusEl ), format( "playlistIcon%d", idx ), playlistThumbnail ) - } - } - - Hud_Show( statusEl ) - - if ( mapIdx > -1 && modeIdx > -1 ) - { - if ( file.preCacheInfo.playlistName != playlistName || file.preCacheInfo.mapIdx != mapIdx || file.preCacheInfo.modeIdx != modeIdx ) - { - file.preCacheInfo.playlistName = playlistName - file.preCacheInfo.mapIdx = mapIdx - file.preCacheInfo.modeIdx = modeIdx - } - } - - string etaStr = "" - if ( !etaSeconds && !isConnectingToMatch ) - { - matchmakingStatus = "#MATCHMAKING_SEARCHING_FOR_MATCH" - } - else - { - int now = int( Time() ) - int etaTime = now + etaSeconds - if ( !file.etaTime || etaTime < file.etaTime ) - file.etaTime = etaTime - - int etaSeconds = file.etaTime - now - if ( etaSeconds <= 0 ) - file.etaTime = etaTime - - etaSeconds = file.etaTime - now - if ( etaSeconds <= 90 ) - { - etaStr = Localize( "#MATCHMAKING_ETA_SECONDS", etaSeconds ) - } - else - { - int etaMinutes = int( ceil( etaSeconds / 60.0 ) ) - if ( etaMinutes < file.etaMaxMinutes ) - etaStr = Localize( "#MATCHMAKING_ETA_MINUTES", etaMinutes ) - else - etaStr = Localize( "#MATCHMAKING_ETA_UNKNOWN", etaMinutes ) - } - } - - MatchmakingSetSearchText( matchmakingStatus, etaStr ) - } - else - { - Hud_Show( statusEl ) - RuiSetString( Hud_GetRui( statusEl ), "statusText", "" ) - RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", 0 ) - } - } - } - - WaitFrameOrUntilLevelLoaded() - } -} - -void function UpdateAnnouncementDialog() -{ - while ( IsLobby() && IsFullyConnected() ) - { - // Only safe on these menus. Not safe if these variables are true because they indicate the search menu or postgame menu are going to be opened. - if ( ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) || uiGlobal.activeMenu == GetMenu( "PrivateLobbyMenu" ) ) && !file.putPlayerInMatchmakingAfterDelay && !uiGlobal.EOGOpenInLobby ) - { - entity player = GetUIPlayer() - - // Only initialize here, CloseAnnouncementDialog() handles setting it when closing - if ( uiGlobal.announcementVersionSeen == -1 ) - uiGlobal.announcementVersionSeen = player.GetPersistentVarAsInt( "announcementVersionSeen" ) - - int announcementVersion = GetConVarInt( "announcementVersion" ) - if ( announcementVersion > uiGlobal.announcementVersionSeen ) - { - OpenAnnouncementDialog() - } - else if ( uiGlobal.activeMenu != "AnnouncementDialog" && ShouldShowEmotesAnnouncement( player ) ) - { - OpenCommsIntroDialog() - } - } - - WaitFrame() - } -} - -bool function CurrentMenuIsPVEMenu() -{ - var topMenu = GetTopNonDialogMenu() - if ( topMenu == null ) - return false - - return (uiGlobal.menuData[topMenu].isPVEMenu) -} - -void function RefreshCreditsAvailable( int creditsOverride = -1 ) -{ - entity player = GetUIPlayer() - if ( !IsValid( player ) ) - return - if ( !IsPersistenceAvailable() ) - return - - int credits = creditsOverride >= 0 ? creditsOverride : GetAvailableCredits( GetLocalClientPlayer() ) - string pveTitle = "" - int pveCredits = 0 - bool isPVE = CurrentMenuIsPVEMenu() - if ( isPVE ) - { - TitanLoadoutDef loadout = GetCachedTitanLoadout( uiGlobal.editingLoadoutIndex ) - pveCredits = GetAvailableFDUnlockPoints( player, loadout.titanClass ) - pveTitle = GetTitanLoadoutName( loadout ) - } - - foreach ( elem in file.creditsAvailableElems ) - { - SetUIPlayerCreditsInfo( elem, credits, GetLocalClientPlayer().GetXP(), GetGen(), GetLevel(), GetNextLevel( GetLocalClientPlayer() ), isPVE, pveCredits, pveTitle ) - } -} - -void function SetUIPlayerCreditsInfo( var infoElement, int credits, int xp, int gen, int level, int nextLevel, bool isPVE, int pveCredits, string pveTitle ) -{ - var rui = Hud_GetRui( infoElement ) - RuiSetInt( rui, "credits", credits ) - RuiSetString( rui, "nameText", GetPlayerName() ) - - RuiSetBool( rui, "isPVE", isPVE ) - if ( isPVE ) - { - RuiSetInt( rui, "pveCredits", pveCredits ) - RuiSetString( rui, "pveTitle", pveTitle ) - } - - if ( xp == GetMaxPlayerXP() && gen < MAX_GEN ) - { - RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) - RuiSetString( rui, "nextLevelText", Localize( "#REGEN_AVAILABLE" ) ) - RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) - RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) - } - else if ( xp == GetMaxPlayerXP() && gen == MAX_GEN ) - { - RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) - RuiSetString( rui, "nextLevelText", Localize( "#MAX_GEN" ) ) - RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) - RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) - } - else - { - RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) - RuiSetString( rui, "nextLevelText", PlayerXPDisplayGenAndLevel( gen, nextLevel ) ) - RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level ) ) - RuiSetInt( rui, "filledLevelPips", GetXPFilledPipsForXP( xp ) ) - } - - CallsignIcon callsignIcon = PlayerCallsignIcon_GetActive( GetLocalClientPlayer() ) - - RuiSetImage( rui, "callsignIcon", callsignIcon.image ) -} - -void function OpenServerBrowser( var button ) -{ - if ( Hud_IsLocked( button ) ) - return - - // nothing here yet lol - // look at OpenSelectedPlaylistMenu for advancing to server browser menu probably - AdvanceMenu( GetMenu( "ServerBrowserMenu" ) ) -} - -void function BigPlayButton1_Activate( var button ) -{ - if ( Hud_IsLocked( button ) ) - return - - SendOpenInvite( false ) - OpenSelectedPlaylistMenu() -} - -function EnableButton( button ) -{ - Hud_SetEnabled( button, true ) - Hud_Show( button ) -} - -function DisableButton( button ) -{ - Hud_SetEnabled( button, false ) - Hud_Hide( button ) -} - -void function OpenSelectedPlaylistMenu() -{ - if ( Lobby_IsFDMode() ) - { - AdvanceMenu( GetMenu( "FDMenu" ) ) - } - else - { - string playlistMenuName = GetPlaylistMenuName() - AdvanceMenu( GetMenu( playlistMenuName ) ) - } -} - -function UpdateLobbyUI() -{ - if ( uiGlobal.updatingLobbyUI ) - return - uiGlobal.updatingLobbyUI = true - - thread UpdateLobbyType() - thread UpdateMatchmakingStatus() - thread UpdateChatroomThread() - //thread UpdateInviteJoinButton() - thread UpdateInviteFriendsToNetworkButton() - thread UpdatePlayerInfo() - - if ( uiGlobal.menuToOpenFromPromoButton != null ) - { - // Special case because this menu needs a few properties set before opening - - if ( IsStoreMenu( uiGlobal.menuToOpenFromPromoButton ) ) - { - string menuName = expect string( uiGlobal.menuToOpenFromPromoButton._name ) - - void functionref() preOpenfunc = null - if ( uiGlobal.menuToOpenFromPromoButton == GetMenu( "StoreMenu_WeaponSkins" ) ) // Hardcoded special case for now - preOpenfunc = DefaultToDLC11WeaponWarpaintBundle - - OpenStoreMenu( [ menuName ], preOpenfunc ) - } - else - { - AdvanceMenu( uiGlobal.menuToOpenFromPromoButton ) - } - - uiGlobal.menuToOpenFromPromoButton = null - } - else if ( uiGlobal.EOGOpenInLobby ) - { - EOGOpen() - } - - WaitSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - uiGlobal.updatingLobbyUI = false -} - -void function UpdateInviteJoinButton() -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - var menu = GetMenu( "LobbyMenu" ) - - while ( true ) - { - if ( DoesCurrentCommunitySupportInvites() ) - ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_INVITE_ROOM" ) ) - else - ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_JOIN_NETWORK" ) ) - - WaitFrame() - } -} - -void function UpdateInviteFriendsToNetworkButton() -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - var menu = GetMenu( "LobbyMenu" ) - - while ( true ) - { - bool areInvitesToNetworkNotAllowed = !DoesCurrentCommunitySupportChat() - if ( areInvitesToNetworkNotAllowed || ( IsCurrentCommunityInviteOnly() && !AreWeAdminInCurrentCommunity() ) ) - DisableButton( file.inviteFriendsToNetworkButton ) - else - EnableButton( file.inviteFriendsToNetworkButton ) - - WaitFrame() - } -} - -function UpdateLobbyType() -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - - var menu = GetMenu( "LobbyMenu" ) - int lobbyType - local lastType - local partySize - local lastPartySize - local debugArray = [ "SOLO", "PARTY_LEADER", "PARTY_MEMBER", "MATCH", "PRIVATE_MATCH" ] // Must match enum - - WaitFrameOrUntilLevelLoaded() - - while ( true ) - { - lobbyType = GetLobbyTypeScript() - partySize = GetPartySize() - - if ( IsConnected() && ((lobbyType != lastType) || (partySize != lastPartySize)) ) - { - if ( lastType == null ) - printt( "Lobby lobbyType changing from:", lastType, "to:", debugArray[lobbyType] ) - else - printt( "Lobby lobbyType changing from:", debugArray[lastType], "to:", debugArray[lobbyType] ) - - local animation = null - - switch ( lobbyType ) - { - case eLobbyType.SOLO: - animation = "SoloLobby" - break - - case eLobbyType.PARTY_LEADER: - animation = "PartyLeaderLobby" - break - - case eLobbyType.PARTY_MEMBER: - animation = "PartyMemberLobby" - break - - case eLobbyType.MATCH: - animation = "MatchLobby" - break - - case eLobbyType.PRIVATE_MATCH: - animation = "PrivateMatchLobby" - break - } - - if ( animation != null ) - { - menu.RunAnimationScript( animation ) - } - - // Force the animation scripts (which have zero duration) to complete before anything can cancel them. - ForceUpdateHUDAnimations() - - lastType = lobbyType - lastPartySize = partySize - } - - WaitFrameOrUntilLevelLoaded() - } -} - -void function UICodeCallback_CommunityUpdated() -{ - Community_CommunityUpdated() - UpdateChatroomUI() -} - -void function UICodeCallback_FactionUpdated() -{ - printt( "Faction changed! to " + GetCurrentFaction() ); -} - -void function UICodeCallback_SetupPlayerListGenElements( table params, int gen, int rank, bool isPlayingRanked, int pilotClassIndex ) -{ - params.image = "" - params.label = "" - params.imageOverlay = "" -} - -float function GetTimeToRestartMatchMaking() -{ - return file.timeToRestartMatchMaking -} - -void function UpdateTimeToRestartMatchmaking( float time )//JFS: This uses UI time instead of server time, which leads to awkwardness in MatchmakingSetCountdownTimer() and the rui involved -{ - file.timeToRestartMatchMaking = time - - if ( time > 0 ) - { - UpdateRestartMatchmakingStatus( time ) - ShowMatchmakingStatusIcons() - } - else - { - MatchmakingSetSearchText( "" ) - MatchmakingSetCountdownTimer( 0.0, true ) - HideMatchmakingStatusIcons() - } -} - -void function HideMatchmakingStatusIcons() -{ - foreach ( element in file.searchIconElems ) - Hud_Hide( element ) - - foreach ( element in file.matchStatusRuis ) - RuiSetBool( Hud_GetRui( element ), "iconVisible", false ) -} - -void function ShowMatchmakingStatusIcons() -{ - //foreach ( element in file.searchIconElems ) - // Hud_Show( element ) - - foreach ( element in file.matchStatusRuis ) - RuiSetBool( Hud_GetRui( element ), "iconVisible", true ) -} - -void function MatchmakingSetSearchVisible( bool state ) -{ - foreach ( el in file.searchTextElems ) - { - //if ( state ) - // Hud_Show( el ) - //else - Hud_Hide( el ) - } - - foreach ( element in file.matchStatusRuis ) - RuiSetBool( Hud_GetRui( element ), "statusVisible", state ) -} - -void function MatchmakingSetSearchText( string searchText, var param1 = "", var param2 = "", var param3 = "", var param4 = "" ) -{ - foreach ( el in file.searchTextElems ) - { - Hud_SetText( el, searchText, param1, param2, param3, param4 ) - } - - foreach ( element in file.matchStatusRuis ) - { - RuiSetBool( Hud_GetRui( element ), "statusHasText", searchText != "" ) - - RuiSetString( Hud_GetRui( element ), "statusText", Localize( searchText, param1, param2, param3, param4 ) ) - } -} - - -void function MatchmakingSetCountdownVisible( bool state ) -{ - foreach ( el in file.matchStartCountdownElems ) - { - //if ( state ) - // Hud_Show( el ) - //else - Hud_Hide( el ) - } - - foreach ( element in file.matchStatusRuis ) - RuiSetBool( Hud_GetRui( element ), "timerVisible", state ) -} - -void function MatchmakingSetCountdownTimer( float time, bool useServerTime = true ) //JFS: useServerTime bool is awkward, comes from level.ui.gameStartTime using server time and UpdateTimeToRestartMatchmaking() uses UI time. -{ - foreach ( element in file.matchStatusRuis ) - { - RuiSetBool( Hud_GetRui( element ), "timerHasText", time != 0.0 ) - RuiSetGameTime( Hud_GetRui( element ), "startTime", Time() ) - RuiSetBool( Hud_GetRui( element ), "useServerTime", useServerTime ) - RuiSetGameTime( Hud_GetRui( element ), "timerEndTime", time ) - } -} - -void function OnLobbyLevelInit() -{ - UpdateCallsignElement( file.callsignCard ) - RefreshCreditsAvailable() -} - -function UpdatePlayerInfo() -{ - EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) - - var menu = GetMenu( "LobbyMenu" ) - - WaitFrameOrUntilLevelLoaded() - - while ( true ) - { - RefreshCreditsAvailable() - WaitFrame() - } -} - -void function TryUnlockSRSCallsign() -{ - if ( Script_IsRunningTrialVersion() ) - return - - int numCallsignsToUnlock = 0 - - if ( GetTotalLionsCollected() >= GetTotalLionsInGame() ) - numCallsignsToUnlock = 3 - else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_2_COUNT ) - numCallsignsToUnlock = 2 - else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_1_COUNT ) - numCallsignsToUnlock = 1 - else - numCallsignsToUnlock = 0 - - if ( numCallsignsToUnlock > 0 ) - ClientCommand( "UnlockSRSCallsign " + numCallsignsToUnlock ) -} - -void function SetPutPlayerInMatchmakingAfterDelay( bool value ) -{ - file.putPlayerInMatchmakingAfterDelay = value -} - -void function OnStoreButton_Activate( var button ) -{ - LaunchGamePurchaseOrDLCStore() -} - -void function OnStoreNewReleasesButton_Activate( var button ) -{ - //LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_NewReleases" ] ) - LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_WeaponSkins" ] ) -} - -void function OnStoreBundlesButton_Activate( var button ) -{ - LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_Sales" ] ) -} - -void function OnDpadCommsButton_Activate( var button ) -{ - AdvanceMenu( GetMenu( "EditDpadCommsMenu" ) ) -} - -void function OpenCommsIntroDialog() -{ - DialogData dialogData - dialogData.menu = GetMenu( "AnnouncementDialog" ) - dialogData.header = "#DPAD_COMMS_ANNOUNCEMENT_HEADER" - dialogData.ruiMessage.message = "#DPAD_COMMS_ANNOUNCEMENT" - dialogData.image = $"ui/menu/common/dialog_announcement_1" - - AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B1" , OpenDpadCommsMenu ) - AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B2" ) - - AddDialogPCBackButton( dialogData ) - AddDialogFooter( dialogData, "#A_BUTTON_ACCEPT" ) - AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) - - OpenDialog( dialogData ) - - ClientCommand( "SetCommsIntroSeen" ) -} - -void function OpenDpadCommsMenu() -{ - OnDpadCommsButton_Activate( null ) -} - -bool function ShouldShowEmotesAnnouncement( entity player ) -{ - if ( !EmotesEnabled() ) - return false - - if ( player.GetPersistentVarAsInt( "numTimesUsedComms" ) > 2 ) - return false - - if ( player.GetPersistentVar( "hasBeenIntroducedToComms" ) ) - return false - - #if !DEV - if ( PlayerGetRawLevel( player ) <= 2 ) - return false - #endif - - return true -} - -void function Lobby_SetFDMode( bool mode ) -{ - file.isFDMode = mode -} - -//Function returns whether lobby is currently in "Frontier Defense" lobby mode. -bool function Lobby_IsFDMode() -{ - return file.isFDMode -} - -void function Lobby_SetAutoFDOpen( bool autoFD ) -{ - Lobby_SetFDMode( autoFD ) - file.shouldAutoOpenFDMenu = autoFD -} - -void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) -{ - array< string > searchingPlaylists = split( playlistToSearch, "," ) - - bool isFDMode = false - int searchingCount = searchingPlaylists.len() - for( int idx = 0; idx < searchingCount; ++idx ) - { - isFDMode = isFDMode || IsFDMode( searchingPlaylists[idx] ) - if ( isFDMode ) - break - } - - Lobby_SetFDMode( isFDMode ) -} \ No newline at end of file From 48c415c9bae4e32aded56a43252a1f76ea3e586d Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:41:31 +0200 Subject: [PATCH 65/71] Dependency info --- README.md | 8 +++++--- manifest.json | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a26d789..8c7bfb8 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/is | AI kills |Non-functional, Tone API does not collect AI kill data.| | Pilot melee kills |Shows only melee kills accumulated by player as Pilot.| | Pilot executions |Shows only executions accumulated by player as Pilot.| - + - Kills as Titan - shows general kill data for player as Titan, visualised in the table below: | Name | Description | @@ -73,16 +73,18 @@ Found a bug? Make an issue on GitHub [here.](https://github.com/ToneAPI/pulse/is - Kills by Gamemode - piechart showing all kills (in percent) on chosen map by gamemode. -## DISCLAIMER +## DISCLAIMERS The Tone API is NOT used by every server, view a list of supported servers [here.](https://tone.sleepycat.date/v2/client/servers) **pulse** is very much a W.I.P as of right now, features may be missing/nonfunctional. +As of v2.1.0, **pulse** requires [loeb](https://github.com/okvdai/loeb) + ## CHANGELOG
pulse v2.0.0 "Demeter" - + - Switched to Thunderstore template on the GitHub site for easier development. - General code rewrite - lots of improvements for easier development. Rewrite includes: - common code file, for better code readability and ease of development, diff --git a/manifest.json b/manifest.json index 83c562f..d01615b 100644 --- a/manifest.json +++ b/manifest.json @@ -3,5 +3,5 @@ "description": "Adds stats (collected by the Tone API) back to the Stats tab.", "version_number": "2.0.0", "website_url": "https://github.com/ToneAPI/pulse", - "dependencies": [] + "dependencies": ["Okudai-loeb-1.0.0"] } From 5a5591d7b4058dcddaf73f8db68b4f9b4edca483 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:58:52 +0200 Subject: [PATCH 66/71] Update pulse-loeb-component.nut --- .../mod/scripts/vscripts/pulse-loeb-component.nut | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut index 1f4b592..052b98c 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut @@ -1,18 +1,7 @@ global function pulseRegisterWithLoeb -global function pulseLoebFunc void function pulseRegisterWithLoeb() { - loebLogMod(pulseLoebFunc()) -} - -void function pulseLoebFunc() -{ - print("func called") - GetStats() -} - -void function GetStats() -{ - loebSetLockedButton(Localize("#MENU_TITLE_STATS"), pulseGetData()) + bool success = pulseGetData() + loebSetLockedButton(Localize("#MENU_TITLE_STATS"), success) } \ No newline at end of file From d56b2878a235c1351e6c8eb5b98e909ed63d5f4f Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 3 Sep 2023 14:16:16 +0200 Subject: [PATCH 67/71] Update ToneURL convar --- mods/ToneAPI.pulse/mod.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mods/ToneAPI.pulse/mod.json b/mods/ToneAPI.pulse/mod.json index 5c96e32..8d52e9d 100644 --- a/mods/ToneAPI.pulse/mod.json +++ b/mods/ToneAPI.pulse/mod.json @@ -6,11 +6,7 @@ "ConVars": [ { "Name": "ToneURL", - "DefaultValue": "https://tone.sleepycat.date/v2/client" - }, - { - "Name": "VersionURL", - "DefaultValue": "https://raw.githubusercontent.com/ToneAPI/pulse/main/version.json" + "DefaultValue": "https://toneapi.ovh/v2/client" } ], "Scripts": [ From 0f0d89c9c39b9a7bad88036ea8a9a1289cae7afa Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 3 Sep 2023 15:15:33 +0200 Subject: [PATCH 68/71] Merge pulse-loeb-component.nut into pulse-common-func.gnut --- mods/ToneAPI.pulse/mod.json | 7 ----- .../scripts/vscripts/pulse-common-func.gnut | 7 +++++ .../scripts/vscripts/pulse-loeb-component.nut | 7 ----- .../mod/scripts/vscripts/pulse.gnut | 29 +++++-------------- 4 files changed, 14 insertions(+), 36 deletions(-) delete mode 100644 mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut diff --git a/mods/ToneAPI.pulse/mod.json b/mods/ToneAPI.pulse/mod.json index 8d52e9d..f5936a2 100644 --- a/mods/ToneAPI.pulse/mod.json +++ b/mods/ToneAPI.pulse/mod.json @@ -20,13 +20,6 @@ "UICallback": { "After": "pulseInit" } - }, - { - "Path": "pulse-loeb-component.nut", - "RunOn": "UI", - "UICallback": { - "After": "pulseRegisterWithLoeb" - } } ], "Localisation": [ diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut index 37461ac..0c3d3af 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-common-func.gnut @@ -32,11 +32,13 @@ bool function pulseRequestData(string givenURL, table parameterTable, string tab } } else { pulsePrintt(format("%s, %s is unreachable.", response.statusCode, givenURL)) + pulseLockStats() } } void functionref (HttpRequestFailure) onFailure = void function(HttpRequestFailure failure) : (givenURL) { pulsePrintt(format("Something went wrong, %s is unreachable", givenURL)) + pulseLockStats() } foreach (key, value in parameterTable) { @@ -61,6 +63,11 @@ int function pulseParse(...) //Returns data from our pulseData table. return result } +void function pulseLockStats() +{ + loebSetLockedButton(Localize("#MENU_TITLE_STATS"), true) +} + string function HammerToMeterString(float value) { return value > 0 && int((1.905 * value ))/100 > 0 ? string(int((1.905 * value ) )/100) + "m" : "0"; diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut deleted file mode 100644 index 052b98c..0000000 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse-loeb-component.nut +++ /dev/null @@ -1,7 +0,0 @@ -global function pulseRegisterWithLoeb - -void function pulseRegisterWithLoeb() -{ - bool success = pulseGetData() - loebSetLockedButton(Localize("#MENU_TITLE_STATS"), success) -} \ No newline at end of file diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut index a9eb9c3..3d5c869 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut @@ -12,36 +12,21 @@ void function pulseInit() pulsePrefixSet() file.allMaps = GetPrivateMatchMaps() pulsePrintt("Initialized.") + pulseGetData() } -bool function pulseGetData() +void function pulseGetData() { print("data getter called") string URL = GetConVarString("ToneURL") array URLpath = ["/weapons", "/weapons", "/gamemodes", "/gamemodes", "/maps"] array tablepath = ["weaponsLocal", "weaponsGlobal", "gamemodesAll", "gamemodesSeparated", "maps"] - if (!pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0])) - { - return true - } - if (!pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1])) - { - return true - } - if (!pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2])) - { - return true - } + pulseRequestData(URL + URLpath[0], {["player"] = NSGetLocalPlayerUID()}, tablepath[0]) + pulseRequestData(URL + URLpath[1], {["player"] = "!" + NSGetLocalPlayerUID()}, tablepath[1]) + pulseRequestData(URL + URLpath[2], {["player"] = NSGetLocalPlayerUID()}, tablepath[2]) foreach (map in file.allMaps) { - if (!pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3])) - { - return true - } + pulseRequestData(URL + URLpath[3], {["player"] = NSGetLocalPlayerUID(), ["map"] = map.slice(3)}, tablepath[3]) } - if (!pulseRequestData(URL + URLpath[4], {["player"] = NSGetLocalPlayerUID()}, tablepath[4])) - { - return true - } - return false + pulseRequestData(URL + URLpath[4], {["player"] = NSGetLocalPlayerUID()}, tablepath[4]) } \ No newline at end of file From 7aa6c9476f25e425c778770b94af01d94ed3a779 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Sun, 3 Sep 2023 15:20:57 +0200 Subject: [PATCH 69/71] Fix stats loading only after reloading mods --- mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut index 3d5c869..5705721 100644 --- a/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut +++ b/mods/ToneAPI.pulse/mod/scripts/vscripts/pulse.gnut @@ -12,7 +12,7 @@ void function pulseInit() pulsePrefixSet() file.allMaps = GetPrivateMatchMaps() pulsePrintt("Initialized.") - pulseGetData() + AddUICallback_OnLevelInit( pulseGetData ) } void function pulseGetData() From f959f7dd91aaa2993d7508bbd63c0f3da63a7970 Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:37:41 +0200 Subject: [PATCH 70/71] Prepare for release v2.1.0 --- README.md | 8 ++++++++ manifest.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c7bfb8..79feb37 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,11 @@ As of v2.1.0, **pulse** requires [loeb](https://github.com/okvdai/loeb) - Polish. (Northstar isn't translated into Polish, but the game supports it.) - Locking the Stats tab, avoiding situations where you could click too fast and see no stats. Also prevents the game from showing stats when the API is unreachable.
+ +
+ pulse v2.1.0 + + - Changed endpoint + - Lots of bug fixes + - Uses new experimental loeb library +
diff --git a/manifest.json b/manifest.json index d01615b..4522522 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Pulse", "description": "Adds stats (collected by the Tone API) back to the Stats tab.", - "version_number": "2.0.0", + "version_number": "2.1.0", "website_url": "https://github.com/ToneAPI/pulse", "dependencies": ["Okudai-loeb-1.0.0"] } From 02ba70198f74838a89d3f187075b3b3597de356a Mon Sep 17 00:00:00 2001 From: okvdai <108829133+okvdai@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:04:54 +0200 Subject: [PATCH 71/71] Update version numbers --- manifest.json | 4 ++-- mods/ToneAPI.pulse/mod.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 4522522..7471b25 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Pulse", "description": "Adds stats (collected by the Tone API) back to the Stats tab.", - "version_number": "2.1.0", + "version_number": "2.1.1", "website_url": "https://github.com/ToneAPI/pulse", - "dependencies": ["Okudai-loeb-1.0.0"] + "dependencies": ["Okudai-loeb-1.0.1"] } diff --git a/mods/ToneAPI.pulse/mod.json b/mods/ToneAPI.pulse/mod.json index f5936a2..2c652a0 100644 --- a/mods/ToneAPI.pulse/mod.json +++ b/mods/ToneAPI.pulse/mod.json @@ -1,7 +1,7 @@ { "Name": "ToneAPI.pulse", "Description": "Displays Tone API kill data in the Stats tab.", - "Version": "2.0.0", + "Version": "2.1.1", "LoadPriority": 1, "ConVars": [ {