diff --git a/README.md b/README.md index 2672fd8..065bdec 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,34 @@ Currently supported stats are: - all damage - damage dealt to target (in wvw: equivalent to damage dealt to players) - damage dealt to everything else (in wvw: siege, npcs, ...) +- all condition damage +- condition damage dealt to target (in wvw: equivalent to damage dealt to players) +- condition damage dealt to everything else (in wvw: siege, npcs, ...) +- all power damage +- power damage dealt to target (in wvw: equivalent to damage dealt to players) +- power damage dealt to everything else (in wvw: siege, npcs, ...) - spike damage (maximum damage dealt within 1s) - killing hits - downing hits -- down contribution (damage on downs) +- damage against downed players - boon rips +- interrupts - cleanses -- stability output (generation squad) -- protection output (generation squad) -- aegis output (generation squad) -- resistance output (generation squad) -- resolution output (generation squad) -- quickness output (generation squad) -- might output (generation squad) -- fury output (generation squad) -- alacrity output (generation squad) -- superspeed output (generation squad) -- swiftness output (generation squad) -- vigor output (generation squad) +- dodges +- blocks +- stability (output to squad, uptime) +- protection (output to squad, uptime) +- aegis (output to squad, uptime) +- resistance (output to squad, uptime) +- resolution (output to squad, uptime) +- quickness (output to squad, uptime) +- might (output to squad, uptime) +- fury (output to squad, uptime) +- alacrity (output to squad, uptime) +- superspeed (output to squad, uptime) +- swiftness (output to squad, uptime) +- vigor (output to squad, uptime) +- stealth (output to squad, uptime) - all healing output - healing dealt to target (in wvw: equivalent to healing on players) - healing dealt to everything else (in wvw: npcs, pets, ...) @@ -33,6 +43,9 @@ Currently supported stats are: - total damage taken - damage absorbed by barrier - hp lost (= total damage taken - damage absorbed by barrier) +- condition damage taken +- power damage taken +- downstates - deaths Healing and barrier output can only be analyzed when contained in the logs, i.e., the [healing addon for arcdps](https://github.com/Krappa322/arcdps_healing_stats/releases) is installed. They will only be analyzed for players who also have the addon installed, since data may be incomplete for others. diff --git a/io_helper.py b/io_helper.py index ea394a5..ac52311 100644 --- a/io_helper.py +++ b/io_helper.py @@ -84,7 +84,7 @@ def write_stats_xls(players, top_players, stat, xls_output_filename, config): # sort in descending order, unless it's a stat where low values are good and total or avg are sorted sort_ascending = [False for x in config.sort_xls_by[stat]] - if stat == 'deaths' or stat == 'stripped' or stat == 'dist' or 'dmg_taken' in stat: + if stat == 'deaths' or stat == 'downstate' or stat == 'stripped' or stat == 'dist' or 'dmg_taken' in stat: for i, val in enumerate(config.sort_xls_by[stat]): if val == "avg" or val == "total": sort_ascending[i] = True @@ -92,7 +92,7 @@ def write_stats_xls(players, top_players, stat, xls_output_filename, config): for i, val in enumerate(config.sort_xls_by[stat]): if is_string_column(val): sort_ascending[i] = True - + df = create_panda_dataframe(players, top_players, stat, sorting_columns, sort_ascending, config) df.to_excel(writer, sheet_name = config.stat_names[stat], startrow = 3, index = False, header = False) @@ -106,7 +106,7 @@ def write_stats_xls(players, top_players, stat, xls_output_filename, config): column_names = [config.xls_column_names[c] for c in list(df) if c in config.xls_column_names] column_names.append("Times Top "+str(config.num_players_considered_top[stat])) - column_names.append("Percentage Top"+str(config.num_players_considered_top[stat])) + column_names.append("Percentage Top "+str(config.num_players_considered_top[stat])) # rename the columns for the xls if stat == 'spike_dmg': @@ -114,7 +114,7 @@ def write_stats_xls(players, top_players, stat, xls_output_filename, config): else: column_names.append("Total "+stat) - if stat == 'deaths' or stat == 'kills' or stat == 'downs': + if stat == 'deaths' or stat == 'kills' or stat == 'downstate' or stat == 'downs': column_names.append("Average "+stat+" per min "+config.duration_for_averages[stat]) elif stat == 'spike_dmg': column_names.append("Average "+stat+" over all fights") @@ -122,6 +122,8 @@ def write_stats_xls(players, top_players, stat, xls_output_filename, config): column_names.append("Average "+stat+" in %") elif stat not in config.self_buff_ids: column_names.append("Average "+stat+" per s "+config.duration_for_averages[stat]) + if stat in config.squad_buff_ids: + column_names.append(stat+" Uptime in %") for i in range(len(column_names)): header_cell = sheet.cell(row=3, column=(i+1)) header_cell.value = column_names[i] @@ -233,7 +235,10 @@ def create_panda_dataframe_overview(fights, overall_squad_stats, overall_raid_st num_enemies.append(overall_raid_stats['mean_enemies']) kills.append(overall_raid_stats['total_kills']) for stat in config.stats_to_compute: - stats[stat].append(overall_squad_stats['total'][stat]) + if stat in config.squad_buff_abbrev.values(): + stats[stat].append(overall_squad_stats['avg'][stat]) + else: + stats[stat].append(overall_squad_stats['total'][stat]) data = {"": first_col, "#": fight_num, @@ -271,10 +276,17 @@ def create_panda_dataframe(players, top_players, stat, sorting_columns, sort_asc duration_present = (players[top_players[i]].duration_present[config.duration_for_averages[stat]] for i in range(len(top_players))) consistency_stats = (players[top_players[i]].consistency_stats[stat] for i in range(len(top_players))) portion_top_stats = (players[top_players[i]].portion_top_stats[stat]*100 for i in range(len(top_players))) - total_stats = (players[top_players[i]].total_stats[stat] for i in range(len(top_players))) + total_stats = list() + if stat in config.squad_buff_abbrev.values(): + total_stats = (players[top_players[i]].total_stats[stat]['gen'] for i in range(len(top_players))) + else: + total_stats = (players[top_players[i]].total_stats[stat] for i in range(len(top_players))) average_stats = list() if stat not in config.self_buff_ids: average_stats = (players[top_players[i]].average_stats[stat] for i in range(len(top_players))) + uptime_stats = list() + if stat in config.squad_buff_abbrev.values(): + uptime_stats = (players[top_players[i]].total_stats[stat]['uptime'] for i in range(len(top_players))) data = {"account": accounts, "name": names, "profession": professions, @@ -285,11 +297,11 @@ def create_panda_dataframe(players, top_players, stat, sorting_columns, sort_asc "total": total_stats} if stat not in config.self_buff_ids: data["avg"] = average_stats + if stat in config.squad_buff_abbrev.values(): + data["uptime"] = uptime_stats df = pd.DataFrame(data) print(stat) - #if stat == 'interrupts': - # print(df) df.sort_values(sorting_columns, ascending=sort_ascending, inplace=True) return df diff --git a/json_helper.py b/json_helper.py index 4860a13..c84ac9d 100644 --- a/json_helper.py +++ b/json_helper.py @@ -270,6 +270,32 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, return -1 return int(player_json['defenses'][0]['deadCount']) + ################# + ### downstate ### + ################# + if stat == 'downstate': + if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'downCount' not in player_json['defenses'][0]: + config.errors.append("Could not find defenses or an entry for downCount in json.") + return -1 + return int(player_json['defenses'][0]['downCount']) + + ################# + ### dodges ### + ################# + if stat == 'dodges': + if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'dodgeCount' not in player_json['defenses'][0]: + config.errors.append("Could not find defenses or an entry for dodgeCount in json.") + return -1 + return int(player_json['defenses'][0]['dodgeCount']) + + ############## + ### blocks ### + ############## + if stat == 'blocks': + if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'blockedCount' not in player_json['defenses'][0]: + config.errors.append("Could not find defenses or an entry for blockedCount in json.") + return -1 + return int(player_json['defenses'][0]['blockedCount']) ################ ### distance ### @@ -300,7 +326,7 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, # includes dmg absorbed by barrier if stat == 'dmg_taken_total': if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'damageTaken' not in player_json['defenses'][0]: - config.errors.append("Could not find defenses or an entry for damageTaken in json to determine dmg_taken(_total).") + config.errors.append("Could not find defenses or an entry for damageTaken in json to determine dmg_taken_total.") return -1 return int(player_json['defenses'][0]['damageTaken']) @@ -317,6 +343,20 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, return -1 return total_dmg_taken - dmg_absorbed + # includes dmg absorbed by barrier + if stat == 'condi_dmg_taken_total': + if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'conditionDamageTaken' not in player_json['defenses'][0]: + config.errors.append("Could not find defenses or an entry for conditionDamageTaken in json to determine condi_dmg_taken_total.") + return -1 + return int(player_json['defenses'][0]['conditionDamageTaken']) + + # includes dmg absorbed by barrier + if stat == 'power_dmg_taken_total': + if 'defenses' not in player_json or len(player_json['defenses']) != 1 or 'powerDamageTaken' not in player_json['defenses'][0]: + config.errors.append("Could not find defenses or an entry for powerDamageTaken in json to determine power_dmg_taken_total.") + return -1 + return int(player_json['defenses'][0]['powerDamageTaken']) + ################# ### Dmg Dealt ### ################# @@ -339,6 +379,44 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, return -1 return total_dmg - players_dmg + if stat == 'condi_dmg_total': + if 'dpsAll' not in player_json or len(player_json['dpsAll']) != 1 or 'condiDamage' not in player_json['dpsAll'][0]: + config.errors.append("Could not find dpsAll or an entry for condiDamage in json to determine condi_dmg.") + return -1 + return int(player_json['dpsAll'][0]['condiDamage']) + + if stat == 'condi_dmg_players': + if 'targetConditionDamage1S' not in player_json: + config.errors.append("Could not find targetConditionDamage1S in json to determine condi_dmg_players.") + return -1 + return sum(target[0][-1] for target in player_json['targetConditionDamage1S']) + + if stat == 'condi_dmg_other': + total_condi_dmg = get_stat_from_player_json(player_json, 'condi_dmg_total', fight, player_duration_present, config) + players_condi_dmg = get_stat_from_player_json(player_json, 'condi_dmg_players', fight, player_duration_present, config) + if total_condi_dmg < 0 or players_condi_dmg < 0: + return -1 + return total_condi_dmg - players_condi_dmg + + if stat == 'power_dmg_total': + if 'dpsAll' not in player_json or len(player_json['dpsAll']) != 1 or 'powerDamage' not in player_json['dpsAll'][0]: + config.errors.append("Could not find dpsAll or an entry for powerDamage in json to determine power_dmg.") + return -1 + return int(player_json['dpsAll'][0]['powerDamage']) + + if stat == 'power_dmg_players': + if 'targetPowerDamage1S' not in player_json: + config.errors.append("Could not find targetPowerDamage1S in json to determine power_dmg_players.") + return -1 + return sum(target[0][-1] for target in player_json['targetPowerDamage1S']) + + if stat == 'power_dmg_other': + total_power_dmg = get_stat_from_player_json(player_json, 'power_dmg_total', fight, player_duration_present, config) + players_power_dmg = get_stat_from_player_json(player_json, 'power_dmg_players', fight, player_duration_present, config) + if total_power_dmg < 0 or players_power_dmg < 0: + return -1 + return total_power_dmg - players_power_dmg + if stat == 'spike_dmg': if 'targetDamage1S' not in player_json: config.errors.append("Could not find targetDamage1S in json to determine spike_dmg.") @@ -368,11 +446,11 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, return -1 return int(player_json['statsAll'][0]['downed']) - if stat == 'down_contrib': - if 'statsAll' not in player_json or len(player_json['statsAll']) == 0 or 'downContribution' not in player_json['statsAll'][0]: - config.errors.append("Could not find statsAll or downed in json to determine down contribution.") + if stat == 'dmg_against_downed': + if 'statsAll' not in player_json or len(player_json['statsAll']) == 0 or 'againstDownedDamage' not in player_json['statsAll'][0]: + config.errors.append("Could not find statsAll or againstDownedDamage in json to determine dmg against downed.") return -1 - return int(player_json['statsAll'][0]['downContribution']) + return int(player_json['statsAll'][0]['againstDownedDamage']) ################################## ### Incoming / Outgoing strips ### @@ -468,35 +546,17 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, config.errors.append("Could not find regen in json to determine hits_from_regen.") return -1 - ############# - ### Auras ### - ############# - - if 'aura' in stat and stat in config.squad_buff_ids: - if 'buffUptimes' not in player_json: - config.errors.append("Could not find buffUptimes in json to determine "+stat+".") - return -1 - for buff in player_json['buffUptimes']: - if 'id' not in buff: - continue - # find right buff - buffId = buff['id'] - if buffId == int(config.squad_buff_ids[stat]): - if 'buffData' not in buff or len(buff['buffData']) == 0 or 'uptime' not in buff['buffData'][0]: - config.errors.append("Could not find entry for buffData or uptime in json to determine "+stat+".") - return -1 - return float(buff['buffData'][0]['uptime']) - config.errors.append("Could not find the buff "+stat+" in the json. Treating as 0.") - return 0. ################### ### Squad Buffs ### ################### if stat in config.squad_buff_ids: - if 'squadBuffs' not in player_json: - config.errors.append("Could not find squadBuffs in json to determine "+stat+".") - return -1 + vals = {'gen': -1, 'uptime': -1} + squad_gen = -1 + if 'squadBuffs' not in player_json or 'buffUptimes' not in player_json: + config.errors.append("Could not find squadBuffs or buffUptimes in json to determine "+stat+".") + return vals # get buffs in squad generation -> need to loop over all buffs for buff in player_json['squadBuffs']: if 'id' not in buff: @@ -506,11 +566,34 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, if buffId == int(config.squad_buff_ids[stat]): if 'buffData' not in buff or len(buff['buffData']) == 0 or 'generation' not in buff['buffData'][0]: config.errors.append("Could not find entry for buffData or generation in json to determine "+stat+".") - return -1 - return float(buff['buffData'][0]['generation']) + return vals + squad_gen = float(buff['buffData'][0]['generation']) + break + # get buffs in uptime -> need to loop over all buffs + for buff in player_json['buffUptimes']: + #TODO fix + if 'id' not in buff: + continue + # find right buff + + buffId = buff['id'] + if buffId == int(config.squad_buff_ids[stat]): + if stat in config.buffs_stacking_intensity: + if 'buffData' not in buff or len(buff['buffData']) == 0 or 'presence' not in buff['buffData'][0]: + config.errors.append("Could not find entry for buffData or presence in json to determine "+stat+".") + return vals + vals = {'gen': squad_gen, 'uptime': float(buff['buffData'][0]['presence'])} + else: + if 'buffData' not in buff or len(buff['buffData']) == 0 or 'uptime' not in buff['buffData'][0]: + config.errors.append("Could not find entry for buffData or uptime in json to determine "+stat+".") + return vals + vals = {'gen': squad_gen, 'uptime': float(buff['buffData'][0]['uptime'])} + return vals config.errors.append("Could not find the buff "+stat+" in the json. Treating as 0.") - return 0. + vals['gen'] = 0. + vals['uptime'] = 0. + return vals ################## ### Self Buffs ### @@ -534,9 +617,12 @@ def get_stat_from_player_json(player_json, stat, fight, player_duration_present, config.errors.append("Could not find the buff "+stat+" in the json. Treating as 0.") return 0 + if stat in config.squad_buff_abbrev.values(): + vals = {'gen': -1, 'uptime': -1} + return vals if stat not in config.self_buff_abbrev.values() and stat not in config.squad_buff_abbrev.values(): - config.errors.append("Stat ", stat, " is currently not supported! Treating it as 0.") + config.errors.append("Stat "+stat+" is currently not supported! Treating it as 0.") return 0 diff --git a/parse_top_stats_tools.py b/parse_top_stats_tools.py index e3109fd..c5eee9a 100755 --- a/parse_top_stats_tools.py +++ b/parse_top_stats_tools.py @@ -52,8 +52,8 @@ def increase_top_x_reached(players, sortedList, config, stat, fight_number): players[sortedList[i][0]].consistency_stats[stat] += 1 valid_values += 1 last_val = sortedList[i][1] - # for incoming strips or dmg taken, anything >= 0 can be top - elif (stat == 'stripped' or 'dmg_taken' in stat) and sortedList[i][1] >= 0: + # for incoming strips, dmg taken, or downstate, anything >= 0 can be top + elif (stat == 'stripped' or 'dmg_taken' in stat or stat == 'downstate') and sortedList[i][1] >= 0: players[sortedList[i][0]].consistency_stats[stat] += 1 valid_values += 1 last_val = sortedList[i][1] @@ -72,13 +72,18 @@ def increase_top_x_reached(players, sortedList, config, stat, fight_number): # players = list of all Players # stat = stat that is considered # fight_num = number of the fight that is considered +# is_squad_buff = stat is a squad buff # Output: # list of (player index, stat value in fight fight_num), sorted by total stat value in fight fight_num -def sort_players_by_value_in_fight(players, stat, fight_num): +def sort_players_by_value_in_fight(players, stat, fight_num, is_squad_buff): # get list of (stat value, index) - decorated = [(player.stats_per_fight[fight_num][stat], i) for i, player in enumerate(players)] - if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped': - # for tag distance, dmg taken, deaths, and stripped, low numbers are good + decorated = [] + if is_squad_buff: + decorated = [(player.stats_per_fight[fight_num][stat]['gen'], i) for i, player in enumerate(players)] + else: + decorated = [(player.stats_per_fight[fight_num][stat], i) for i, player in enumerate(players)] + if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped' or stat == 'downstate': + # for tag distance, dmg taken, deaths, stripped, and downstate, low numbers are good decorated.sort() else: # for all other stats, high numbers are good @@ -93,12 +98,17 @@ def sort_players_by_value_in_fight(players, stat, fight_num): # Input: # players = list of all Players # stat = stat that is considered +# is_squad_buff = stat is a squad buff # Output: # list of (player index, total stat value), sorted by total stat value -def sort_players_by_total(players, stat): +def sort_players_by_total(players, stat, is_squad_buff): # get list of (total stat, index) - decorated = [(player.total_stats[stat], i) for i, player in enumerate(players)] - if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped': + decorated = [] + if is_squad_buff: + decorated = [(player.total_stats[stat]['gen'], i) for i, player in enumerate(players)] + else: + decorated = [(player.total_stats[stat], i) for i, player in enumerate(players)] + if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped' or stat == 'downstate': # for tag distance, dmg taken, deaths, and stripped, low numbers are good decorated.sort() else: @@ -114,11 +124,16 @@ def sort_players_by_total(players, stat): # Input: # players = list of all Players # stat = stat that is considered +# is_squad_buff = stat is a squad buff # Output: # list of (player index, consistency stat value), sorted by consistency stat value (how often was top x reached) -def sort_players_by_consistency(players, stat): +def sort_players_by_consistency(players, stat, is_squad_buff): # get list of (times top, total stat, index), sort first by times top (high value = good) and then by total - decorated = [(player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] + decorated = [] + if is_squad_buff: + decorated = [(player.consistency_stats[stat], player.total_stats[stat]['gen'], i) for i, player in enumerate(players)] + else: + decorated = [(player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] decorated.sort(reverse=True) # extract list of (index, times top) sorted_by_consistency = [(i, consistency) for consistency, total, i in decorated] @@ -130,11 +145,16 @@ def sort_players_by_consistency(players, stat): # Input: # players = list of all Players # stat = stat that is considered +# is_squad_buff = stat is a squad buff # Output: # list of (player index, percentage stat value), sorted by percentage stat value (how often was top x reached / number of fights attended) -def sort_players_by_percentage(players, stat): +def sort_players_by_percentage(players, stat, is_squad_buff): # get list of (percentage times top, times top, total stat, index), sort first by percentage times top (high value = good), then by times top, and then by total - decorated = [(player.portion_top_stats[stat], player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] + decorated = [] + if is_squad_buff: + decorated = [(player.portion_top_stats[stat], player.consistency_stats[stat], player.total_stats[stat]['gen'], i) for i, player in enumerate(players)] + else: + decorated = [(player.portion_top_stats[stat], player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] decorated.sort(reverse=True) # extract list of (index, percentage times top) sorted_by_percentage = [(i, percentage) for percentage, consistency, total, i in decorated] @@ -146,13 +166,18 @@ def sort_players_by_percentage(players, stat): # Input: # players = list of all Players # stat = stat that is considered +# is_squad_buff = stat is a squad buff # Output: # list of (player index, average stat value), sorted by average stat value ( total stat value / duration of fights attended) -def sort_players_by_average(players, stat): +def sort_players_by_average(players, stat, is_squad_buff): # get list of (average stat, times top, total stat, index), sort first by average stat, then by times top, and then by total - decorated = [(player.average_stats[stat], player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] - if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped': - # for dist, dmg taken, deaths, and stripped: low values good + decorated = [] + if is_squad_buff: + decorated = [(player.average_stats[stat], player.consistency_stats[stat], player.total_stats[stat]['gen'], i) for i, player in enumerate(players)] + else: + decorated = [(player.average_stats[stat], player.consistency_stats[stat], player.total_stats[stat], i) for i, player in enumerate(players)] + if stat == 'dist' or 'dmg_taken' in stat or stat == 'deaths' or stat == 'stripped' or stat == 'downstate': + # for dist, dmg taken, deaths, downstate, and stripped: low values good decorated.sort() else: # for all other stats: high values good @@ -191,19 +216,23 @@ def get_top_players(players, config, stat, total_or_consistent_or_average): # get correct portion of total value and get sorted list of (player index, total/consistency/average stat) if total_or_consistent_or_average == StatType.TOTAL: percentage = float(config.portion_of_top_for_total) - sorted_index = sort_players_by_total(players, stat) + sorted_index = sort_players_by_total(players, stat, (stat in config.squad_buff_abbrev.values())) elif total_or_consistent_or_average == StatType.CONSISTENT: percentage = float(config.portion_of_top_for_consistent) - sorted_index = sort_players_by_consistency(players, stat) + sorted_index = sort_players_by_consistency(players, stat, (stat in config.squad_buff_abbrev.values())) elif total_or_consistent_or_average == StatType.AVERAGE: percentage = 0. - sorted_index = sort_players_by_average(players, stat) + sorted_index = sort_players_by_average(players, stat, (stat in config.squad_buff_abbrev.values())) else: print("ERROR: Called get_top_players for stats that are not total or consistent or average") return # using total value for overall top player to compare with - top_value = players[sorted_index[0][0]].total_stats[stat] + top_value = 0 + if stat in config.squad_buff_abbrev.values(): + top_value = players[sorted_index[0][0]].total_stats[stat]['gen'] + else: + top_value = players[sorted_index[0][0]].total_stats[stat] top_players = list() i = 0 @@ -214,9 +243,14 @@ def get_top_players(players, config, stat, total_or_consistent_or_average): if i >= config.num_players_listed[stat] and new_value != last_value: break last_value = new_value + total_value = 0 + if stat in config.squad_buff_abbrev.values(): + total_value = players[sorted_index[i][0]].total_stats[stat]['gen'] + else: + total_value = players[sorted_index[i][0]].total_stats[stat] - # if stat isn't distance, dmg taken, deaths, or stripped, total value must be at least percentage % of top value - if stat == "dist" or "dmg_taken" in stat or stat == "deaths" or stat == 'stripped' or players[sorted_index[i][0]].total_stats[stat] >= top_value*percentage: + # if stat isn't distance, dmg taken, deaths, stripped, or downstate, total value must be at least percentage % of top value + if stat == "dist" or "dmg_taken" in stat or stat == "deaths" or stat == 'stripped' or stat == 'downstate' or stat in config.squad_buff_abbrev.values() or total_value >= top_value*percentage: # consider minimum attendance percentage for average stats if total_or_consistent_or_average != StatType.AVERAGE or (players[sorted_index[i][0]].attendance_percentage > config.min_attendance_percentage_for_average): top_players.append(sorted_index[i][0]) @@ -239,7 +273,7 @@ def get_top_players(players, config, stat, total_or_consistent_or_average): # Output: # list of player indices getting a percentage award, value with which the percentage stat was compared def get_top_percentage_players(players, config, stat, num_used_fights, top_consistent_players = list(), top_total_players = list()): - sorted_index = sort_players_by_percentage(players, stat) + sorted_index = sort_players_by_percentage(players, stat, (stat in config.squad_buff_abbrev.values())) top_percentage = players[sorted_index[0][0]].portion_top_stats[stat] # get correct comparison value for top percentage and minimum attendance @@ -272,7 +306,6 @@ def get_top_percentage_players(players, config, stat, num_used_fights, top_consi # fights = light of Fights # config = the config being used to compute top stats def compute_total_values(players, fights, config): - #print("computing totals") for player in players: for fight_number in range(len(fights)): fight = fights[fight_number] @@ -289,27 +322,36 @@ def compute_total_values(players, fights, config): for stat in config.stats_to_compute: duration_type = config.duration_for_averages[stat] # add stats of this fight and player to total stats of this fight and player, if value is valid ( >=0 ) - if player_stats['present_in_fight'] and player_stats[stat] >= 0: + if player_stats['present_in_fight'] and (player_stats['duration_present'][duration_type] > 0) and ((stat not in config.squad_buff_abbrev.values() and player_stats[stat] >= 0) or stat in config.squad_buff_abbrev.values()): # buff are generation squad values, using total over time if stat in config.buffs_stacking_duration: - # value from json is generated boon time on all squad players / fight duration / (players-1)" in percent, we want generated boon time on all squad players - fight.total_stats[stat] += round(player_stats[stat] / 100. * player_stats['duration_present'][duration_type] * (fight.allies-1), 2) - player.total_stats[stat] += round(player_stats[stat] / 100. * player_stats['duration_present'][duration_type] * (fight.allies-1), 2) - if stat in config.buffs_not_stacking: - # value from json is boon uptime / fight duration" in percent, we want overall boon uptime - fight.total_stats[stat] += round(player_stats[stat] / 100. * player_stats['duration_present'][duration_type], 2) - player.total_stats[stat] += round(player_stats[stat] / 100. * player_stats['duration_present'][duration_type], 2) + if player_stats[stat]['gen'] >= 0: + # value from json is generated boon time on all squad players / fight duration / (players-1)" in percent, we want generated boon time on all squad players + fight.total_stats[stat] += player_stats[stat]['gen'] / 100. * player_stats['duration_present'][duration_type] * (fight.allies-1) + player.total_stats[stat]['gen'] += player_stats[stat]['gen'] / 100. * player_stats['duration_present'][duration_type] * (fight.allies-1) + if player_stats[stat]['uptime'] >= 0: + player.total_stats[stat]['uptime'] += player_stats[stat]['uptime'] / 100. * player_stats['duration_present'][duration_type] + elif stat in config.buffs_not_stacking: + if player_stats[stat]['gen'] >= 0: + # value from json is boon uptime / fight duration" in percent, we want overall boon uptime + fight.total_stats[stat] += player_stats[stat]['gen'] / 100. * player_stats['duration_present'][duration_type] + player.total_stats[stat]['gen'] += player_stats[stat]['gen'] / 100. * player_stats['duration_present'][duration_type] + if player_stats[stat]['uptime'] >= 0: + player.total_stats[stat]['uptime'] += player_stats[stat]['uptime'] / 100. * player_stats['duration_present'][duration_type] elif stat in config.buffs_stacking_intensity: - # value from json is generated boon time on all squad players / fight duration / (players-1)", we want generated boon time on all squad players - fight.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type] * (fight.allies-1), 2) - player.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type] * (fight.allies-1), 2) + if player_stats[stat]['gen'] >= 0: + # value from json is generated boon time on all squad players / fight duration / (players-1)", we want generated boon time on all squad players + fight.total_stats[stat] += player_stats[stat]['gen'] * player_stats['duration_present'][duration_type] * (fight.allies-1) + player.total_stats[stat]['gen'] += player_stats[stat]['gen'] * player_stats['duration_present'][duration_type] * (fight.allies-1) + if player_stats[stat]['uptime'] >= 0: + player.total_stats[stat]['uptime'] += player_stats[stat]['uptime'] / 100. * player_stats['duration_present'][duration_type] elif stat == 'dist': if player_stats[stat] >= 0: - fight.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type]) - player.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type]) + fight.total_stats[stat] += player_stats[stat] * player_stats['duration_present'][duration_type] + player.total_stats[stat] += player_stats[stat] * player_stats['duration_present'][duration_type] elif 'dmg_taken' in stat: - fight.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type]) - player.total_stats[stat] += round(player_stats[stat] * player_stats['duration_present'][duration_type]) + fight.total_stats[stat] += player_stats[stat] * player_stats['duration_present'][duration_type] + player.total_stats[stat] += player_stats[stat] * player_stats['duration_present'][duration_type] elif stat in config.self_buff_ids: # only count whether or not buff was present fight.total_stats[stat] += player_stats[stat] @@ -317,6 +359,12 @@ def compute_total_values(players, fights, config): elif stat == 'spike_dmg': fight.total_stats[stat] = max(fight.total_stats[stat], player_stats[stat]) player.total_stats[stat] = max(player.total_stats[stat], player_stats[stat]) + elif stat in config.squad_buff_abbrev.values(): + if player_stats[stat]['gen'] >= 0: + fight.total_stats[stat] += player.stats_per_fight[fight_number][stat]['gen'] + player.total_stats[stat]['gen'] += player.stats_per_fight[fight_number][stat]['gen'] + if player_stats[stat]['uptime'] >= 0: + player.total_stats[stat]['uptime'] += player.stats_per_fight[fight_number][stat]['uptime'] else: # all other stats fight.total_stats[stat] += player.stats_per_fight[fight_number][stat] @@ -358,10 +406,10 @@ def compute_avg_values(players, fights, config): # TODO double check fight avg stats if stat == 'spike_dmg': fight.avg_stats[stat] = sum(player.stats_per_fight[fight_number][stat] for player in players)/len(players) - elif stat in config.squad_buff_ids and stat in config.buffs_not_stacking: + elif stat in config.squad_buff_abbrev.values() and stat in config.buffs_not_stacking: # all not stacking buff averages are per time, and the % values are always relative to the total fight duration fight.avg_stats[stat] /= total_normalization_time_per_fight[fight_number]['total'] - elif stat in config.squad_buff_ids and stat not in config.buffs_not_stacking: + elif stat in config.squad_buff_abbrev.values() and stat not in config.buffs_not_stacking: # all buff averages are per time and allied player fight.avg_stats[stat] /= total_normalization_time_allies_per_fight[fight_number][config.duration_for_averages[stat]] else: @@ -375,14 +423,22 @@ def compute_avg_values(players, fights, config): for player in players: # compute percentage top stats and attendance percentage for each player used_fights = len([fight for fight in fights if fight.skipped == False]) - player.attendance_percentage = round(player.num_fights_present / used_fights * 100) + player.attendance_percentage = round(sum(fight.duration for i,fight in enumerate(fights) if player.stats_per_fight[i]['present_in_fight']) / sum(fight.duration for fight in fights if fight.skipped == False) * 100) # round total and portion top stats for stat in config.stats_to_compute: player.portion_top_stats[stat] = round(player.consistency_stats[stat]/player.num_fights_present, 4) - player.total_stats[stat] = round(player.total_stats[stat], 2) - if player.total_stats[stat] == 0: - player.average_stats[stat] = 0 - continue + if stat in config.squad_buff_abbrev.values(): + player.total_stats[stat]['gen'] = round(player.total_stats[stat]['gen'], 2) +# player.total_stats[stat]['uptime'] = round(player.total_stats[stat]['uptime'], 2) + player.total_stats[stat]['uptime'] = round(player.total_stats[stat]['uptime']/player.duration_present['total'] * 100, 2) + if player.total_stats[stat]['gen'] <= 0: + player.average_stats[stat] = player.total_stats[stat]['gen'] + continue + else: + player.total_stats[stat] = round(player.total_stats[stat], 2) + if player.total_stats[stat] == 0: + player.average_stats[stat] = 0 + continue # DON'T SWITCH DMG_TAKEN AND DMG OR HEAL_FROM_REGEN AND HEAL if stat == 'spike_dmg': @@ -404,17 +460,17 @@ def compute_avg_values(players, fights, config): player.average_stats[stat] = 0 else: player.average_stats[stat] = round(player.total_stats[stat]/player.total_stats['hits_from_regen'], 2) - elif stat == 'deaths' or stat == 'kills' or stat == 'downs': + elif stat == 'deaths' or stat == 'kills' or stat == 'downs' or stat == 'downstate': player.average_stats[stat] = round(player.total_stats[stat]/(player.duration_present[config.duration_for_averages[stat]] / 60), 2) elif stat in config.self_buff_ids: # self buffs are only mentioned as "present" or "not present" player.average_stats[stat] = round(player.total_stats[stat]/player.num_fights_present, 2) elif stat in config.buffs_stacking_duration: - player.average_stats[stat] = round(player.total_stats[stat]/player.normalization_time_allies[config.duration_for_averages[stat]] * 100, 2) + player.average_stats[stat] = round(player.total_stats[stat]['gen']/player.normalization_time_allies[config.duration_for_averages[stat]] * 100, 2) elif stat in config.buffs_stacking_intensity: - player.average_stats[stat] = round(player.total_stats[stat]/player.normalization_time_allies[config.duration_for_averages[stat]], 2) + player.average_stats[stat] = round(player.total_stats[stat]['gen']/player.normalization_time_allies[config.duration_for_averages[stat]], 2) elif stat in config.buffs_not_stacking: - player.average_stats[stat] = round(player.total_stats[stat]/player.duration_present['total'] * 100, 2) + player.average_stats[stat] = round(player.total_stats[stat]['gen']/player.duration_present['total'] * 100, 2) else: player.average_stats[stat] = round(player.total_stats[stat]/player.duration_present[config.duration_for_averages[stat]], 2) @@ -494,13 +550,10 @@ def get_stats_from_json_data(json_data, players, player_index, account_index, fi for stat in config.stats_to_compute: # TODO add total stats per fight and avg stats per fight; add option to decide whether "top" should be determined by total or avg ? player.stats_per_fight[fight_number][stat] = get_stat_from_player_json(player_data, stat, fight, player.stats_per_fight[fight_number]['duration_present'], config) - if 'heal' in stat and player.stats_per_fight[fight_number][stat] >= 0: found_healing = True elif stat == 'barrier' and player.stats_per_fight[fight_number][stat] >= 0: found_barrier = True - elif stat == 'dist': - player.stats_per_fight[fight_number][stat] = round(player.stats_per_fight[fight_number][stat]) elif 'dmg_taken' in stat: # TODO fix with using proper duration for avg; check the rest of the comp is right # if player wasn't present, dmg taken doesn't count @@ -530,7 +583,7 @@ def get_stats_from_json_data(json_data, players, player_index, account_index, fi # create lists sorted according to stats sortedStats = {key: list() for key in config.stats_to_compute} for stat in config.stats_to_compute: - sortedStats[stat] = sort_players_by_value_in_fight(players, stat, fight_number) + sortedStats[stat] = sort_players_by_value_in_fight(players, stat, fight_number, (stat in config.squad_buff_abbrev.values())) ####################### ### print debug log ### @@ -665,9 +718,9 @@ def get_overall_squad_stats(fights, config): overall_allies += fight.allies spike_dmg = spike_dmg / (overall_allies * len(used_fights)) overall_squad_stats['avg'][stat] = round(spike_dmg, 2) - if stat not in config.squad_buff_ids: + if stat not in config.squad_buff_abbrev.values(): overall_squad_stats['avg'][stat] = round(overall_squad_stats['total'][stat] / (sum([f.duration * f.allies for f in fights])), 2) - if stat in config.squad_buff_ids: + else: overall_squad_stats['avg'][stat] = overall_squad_stats['total'][stat] if stat in config.buffs_stacking_duration: overall_squad_stats['avg'][stat] *= 100 diff --git a/parser_configs/parser_config_detailed.py b/parser_configs/parser_config_detailed.py index 0a23780..f2516da 100644 --- a/parser_configs/parser_config_detailed.py +++ b/parser_configs/parser_config_detailed.py @@ -23,7 +23,9 @@ log_level = "info" stats_to_compute = ['dmg_total', 'dmg_players', 'dmg_other', - 'spike_dmg', 'kills', 'downs', 'down_contrib', + 'condi_dmg_total', 'condi_dmg_players', 'condi_dmg_other', + 'power_dmg_total', 'power_dmg_players', 'power_dmg_other', + 'spike_dmg', 'kills', 'downs', 'dmg_against_downed', 'strips', 'interrupts', 'might', 'fury', 'heal_total', 'heal_players', 'heal_other', 'barrier', 'cleanses', 'stab', 'prot', 'aegis', @@ -31,7 +33,9 @@ 'heal_from_regen', 'hits_from_regen', 'dist', 'quick', 'alac', 'swift', 'speed', 'dmg_taken_total', 'dmg_taken_hp_lost', - 'dmg_taken_absorbed', 'deaths', 'stripped', + 'dmg_taken_absorbed', 'condi_dmg_taken_total', 'power_dmg_taken_total', + 'deaths', 'downstate', 'stripped', + 'dodges', 'blocks', 'stealth', 'chaos_aura', 'fire_aura', 'dark_aura', 'frost_aura', 'light_aura', 'magnetic_aura', 'shocking_aura', 'big_boomer', 'explosive_temper', 'explosive_entrance', @@ -51,10 +55,16 @@ 'dmg_total': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], 'dmg_players': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], 'dmg_other': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], + 'condi_dmg_total': [], + 'condi_dmg_players': [], + 'condi_dmg_other': [], + 'power_dmg_total': [], + 'power_dmg_players': [], + 'power_dmg_other': [], 'spike_dmg': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], 'kills': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], 'downs': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], - 'down_contrib': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], + 'dmg_against_downed': ["Dragonhunter", "Willbender", "Herald", "Vindicator", "Berserker", "Holosmith", "Weaver", "Catalyst", "Virtuoso", "Reaper"], 'strips': ["Chronomancer", "Virtuoso", "Reaper", "Scourge"], 'interrupts': ["Firebrand", "Chronomancer"], 'cleanses': ["Vindicator", "Scrapper", "Druid", "Tempest"], @@ -81,8 +91,14 @@ 'dmg_taken_total': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], 'dmg_taken_hp_lost': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], 'dmg_taken_absorbed': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], + 'condi_dmg_taken_total': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], + 'power_dmg_taken_total': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], 'deaths': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], + 'downstate': [], 'stripped': ["Guardian", "Dragonhunter", "Firebrand", "Willbender", "Revenant", "Renegade", "Herald", "Vindicator", "Warrior", "Berserker", "Spellbreaker", "Bladesworn", "Engineer", "Scrapper", "Holosmith", "Mechanist", "Ranger", "Druid", "Soulbeast", "Untamed", "Thief", "Daredevil", "Deadeye", "Specter", "Elementalist", "Tempest", "Weaver", "Catalyst", "Mesmer", "Chronomancer", "Mirage", "Virtuoso", "Necromancer", "Reaper", "Scourge", "Harbinger"], + 'dodges': [], + 'blocks': [], + 'stealth': [], 'big_boomer': ["Engineer", "Scrapper", "Holosmith", "Mechanist"], 'explosive_temper': ["Engineer", "Scrapper", "Holosmith", "Mechanist"], 'explosive_entrance': ["Engineer", "Scrapper", "Holosmith", "Mechanist"], @@ -180,10 +196,16 @@ stat_names["dmg_total"] = "Total Damage" stat_names["dmg_players"] = "Player Damage" stat_names["dmg_other"] = "Other Damage" +stat_names["condi_dmg_total"] = "Total Condition Damage" +stat_names["condi_dmg_players"] = "Player Condition Damage" +stat_names["condi_dmg_other"] = "Other Condition Damage" +stat_names["power_dmg_total"] = "Total Power Damage" +stat_names["power_dmg_players"] = "Player Power Damage" +stat_names["power_dmg_other"] = "Other Power Damage" stat_names["spike_dmg"] = "Spike Damage" stat_names["kills"] = "Kills" stat_names["downs"] = "Downs" -stat_names["down_contrib"] = "Down Contribution" +stat_names["dmg_against_downed"] = "Damage against Downstates" stat_names["strips"] = "Boon Strips" stat_names["interrupts"] = "Interrupts" stat_names["stab"] = "Stability Output" @@ -207,8 +229,14 @@ stat_names["dmg_taken_total"] = "Total Damage Taken" stat_names["dmg_taken_hp_lost"] = "HP lost" stat_names["dmg_taken_absorbed"] = "Damage absorbed" +stat_names["condi_dmg_taken_total"] = "Total Condition Damage Taken" +stat_names["power_dmg_taken_total"] = "Total Power Damage Taken" stat_names["deaths"] = "Deaths" +stat_names["downstate"] = "Player Downstate" stat_names["stripped"] = "Incoming Strips" +stat_names["dodges"] = "Dodges" +stat_names["blocks"] = "Blocks" +stat_names["stealth"] = "Stealth Output" stat_names["big_boomer"] = "Big Boomer" stat_names["explosive_temper"] = "Explosive Temper" stat_names["explosive_entrance"] = "Explosive Entrance" @@ -229,10 +257,16 @@ stat_descriptions["dmg_total"] = "Total Damage dealt to everything" stat_descriptions["dmg_players"] = "Damage dealt to enemy players" stat_descriptions["dmg_other"] = "Damage dealt to siege, gates, npcs, pets,..." +stat_descriptions["condi_dmg_total"] = "Total Condition Damage dealt to everything" +stat_descriptions["condi_dmg_players"] = "Condition Damage dealt to players" +stat_descriptions["condi_dmg_other"] = "Condition Damage dealt to siege, gates, npcs, pets,..." +stat_descriptions["power_dmg_total"] = "Total Power Damage dealt to everything" +stat_descriptions["power_dmg_players"] = "Power Damage dealt to players" +stat_descriptions["power_dmg_other"] = "Power Damage dealt to siege, gates, npcs, pets,..." stat_descriptions["spike_dmg"] = "Spike Damage (Maximum damage dealt to players within 1s)" stat_descriptions["kills"] = "Number of killing hits" stat_descriptions["downs"] = "Number of downing hits" -stat_descriptions["down_contrib"] = "Damage done to downstates" +stat_descriptions["dmg_against_downed"] = "Damage done to downstates" stat_descriptions["strips"] = "Boon Strips" stat_descriptions["interrupts"] = "Number of hits that interrupted an enemy" stat_descriptions["stab"] = "Stability Output (Squad Generation, excluding self)" @@ -256,8 +290,14 @@ stat_descriptions["dmg_taken_total"] = "Total Damage Taken (includes damage absorbed by barrier)" stat_descriptions["dmg_taken_hp_lost"] = "HP lost" stat_descriptions["dmg_taken_absorbed"] = "Damage absorbed by barrier" +stat_descriptions["condi_dmg_taken_total"] = "Total Condition Damage Taken (includes damage absorbed by barrier)" +stat_descriptions["power_dmg_taken_total"] = "Total Power Damage Taken (includes damage absorbed by barrier)" stat_descriptions["deaths"] = "Deaths" +stat_descriptions["downstate"] = "Number of times a player went downstate" stat_descriptions["stripped"] = "Incoming Strips" +stat_descriptions["dodges"] = "Dodges" +stat_descriptions["blocks"] = "Number of Blocked Enemy Attacks" +stat_descriptions["stealth"] = "Stealth Output (Squad Generation, excluding self)" stat_descriptions["big_boomer"] = "Big Boomer" stat_descriptions["explosive_temper"] = "Explosive Temper" stat_descriptions["explosive_entrance"] = "Explosive Entrance" diff --git a/stat_classes.py b/stat_classes.py index ea34f99..60fde92 100644 --- a/stat_classes.py +++ b/stat_classes.py @@ -42,7 +42,10 @@ def initialize(self, config): self.duration_present = {'total': 0, 'active': 0, 'in_combat': 0, 'not_running_back': 0} self.normalization_time_allies = {'total': 0, 'active': 0, 'in_combat': 0, 'not_running_back': 0} self.total_stats = {key: 0 for key in config.stats_to_compute} - self.average_stats = {key: 0 for key in config.stats_to_compute} + for stat in config.squad_buff_abbrev.values(): + self.total_stats[stat] = {'gen': 0, 'uptime': 0} + + self.average_stats = {key: 0 for key in config.stats_to_compute} self.consistency_stats = {key: 0 for key in config.stats_to_compute} self.portion_top_stats = {key: 0 for key in config.stats_to_compute} @@ -162,9 +165,6 @@ def fill_config(config_input, log): config.relevant_classes = config_input.relevant_classes_for_stat config.stats_to_compute = config_input.stats_to_compute - config.empty_stats = {stat: -1 for stat in config.stats_to_compute} - config.empty_stats['duration_present'] = {'total': 0, 'active': 0, 'in_combat': 0, 'not_running_back': 0} - config.empty_stats['present_in_fight'] = False config.squad_buff_abbrev["Stability"] = 'stab' config.squad_buff_abbrev["Protection"] = 'prot' @@ -179,6 +179,7 @@ def fill_config(config_input, log): config.squad_buff_abbrev["Swiftness"] = 'swift' config.squad_buff_abbrev["Vigor"] = 'vigor' config.squad_buff_abbrev["Superspeed"] = 'speed' + config.squad_buff_abbrev["Stealth"] = 'stealth' config.squad_buff_abbrev["Chaos Aura"] = 'chaos_aura' config.squad_buff_abbrev["Fire Aura"] = 'fire_aura' config.squad_buff_abbrev["Frost Aura"] = 'frost_aura' @@ -191,6 +192,12 @@ def fill_config(config_input, log): config.self_buff_abbrev["Big Boomer"] = 'big_boomer' config.self_buff_abbrev["Med Kit"] = 'med_kit' + config.empty_stats = {stat: -1 for stat in config.stats_to_compute} + for stat in config.squad_buff_abbrev.values(): + config.empty_stats[stat] = {'gen': -1, 'uptime': -1} + config.empty_stats['duration_present'] = {'total': 0, 'active': 0, 'in_combat': 0, 'not_running_back': 0} + config.empty_stats['present_in_fight'] = False + config.xls_column_names = config_input.xls_column_names if config_input.log_level == "debug" or config_input.log_level == "warning" or config_input.log_level == "info":