Formulator / utils /analyzer.py
ango
5.16 commit
1cc60af
import pandas as pd
from base.attribute import Attribute
from base.skill import Skill, DotDamage, NpcDamage, PetDamage
from utils.parser import School, Parser, CALCULATE_COLUMNS
DAMAGE_COLUMNS = ["damage", "critical_damage", "critical_strike", "expected_damage"]
def filter_status(status, school: School):
buffs = []
for buff_id, buff_level, buff_stack in status:
buff = school.buffs[buff_id]
if buff.activate:
buffs.append(buff)
return buffs
def add_buffs(current_buffs, snapshot_buffs, target_buffs, attribute: Attribute, skill: Skill):
if not snapshot_buffs:
for buff in current_buffs:
buff.add_all(attribute, skill)
elif isinstance(skill, DotDamage):
for buff in snapshot_buffs:
buff.add_dot(attribute, skill, True)
for buff in current_buffs:
buff.add_dot(attribute, skill, False)
elif isinstance(skill, NpcDamage):
for buff in snapshot_buffs:
buff.add_all(attribute, skill)
elif isinstance(skill, PetDamage):
for buff in snapshot_buffs:
buff.add_all(attribute, skill)
for buff in target_buffs:
buff.add_all(attribute, skill)
def sub_buffs(current_buffs, snapshot_buffs, target_buffs, attribute: Attribute, skill: Skill):
if not snapshot_buffs:
for buff in current_buffs:
buff.sub_all(attribute, skill)
elif isinstance(skill, DotDamage):
for buff in snapshot_buffs:
buff.sub_dot(attribute, skill, True)
for buff in current_buffs:
buff.sub_dot(attribute, skill, False)
elif isinstance(skill, NpcDamage):
for buff in snapshot_buffs:
buff.sub_all(attribute, skill)
elif isinstance(skill, PetDamage):
for buff in snapshot_buffs:
buff.sub_all(attribute, skill)
for buff in target_buffs:
buff.sub_all(attribute, skill)
def analyze_records(parser: Parser, duration: int, attribute: Attribute):
records: pd.DataFrame = parser.current_records
school = parser.current_school
condition = (records.player_id == parser.current_player) & (records.time < duration)
if parser.current_target:
condition = condition & (records.target_id == parser.current_target)
records = records[condition].copy()
damage_columns = [(0 for _ in DAMAGE_COLUMNS)] * len(records)
grad_attrs = list(attribute.grad_attrs)
gradient_columns = [(0 for _ in grad_attrs)] * len(records)
for row, indices in records.groupby(CALCULATE_COLUMNS).indices.items():
skill_id, skill_level, skill_stack, current_status, target_status, snapshot_index = row
skill: Skill = school.skills[skill_id]
skill.skill_level, skill.skill_stack = skill_level, skill_stack
current_buffs = filter_status(current_status, school)
target_buffs = filter_status(target_status, school)
if snapshot_index < 0:
snapshot_buffs = tuple()
else:
snapshot_buffs = filter_status(records.loc[snapshot_index].current_status, school)
add_buffs(current_buffs, snapshot_buffs, target_buffs, attribute, skill)
damage_tuple = skill(attribute)
gradient_tuple = analyze_gradients(skill, attribute)
for index in indices:
damage_columns[index] = damage_tuple
gradient_columns[index] = gradient_tuple
sub_buffs(current_buffs, snapshot_buffs, target_buffs, attribute, skill)
records[DAMAGE_COLUMNS] = damage_columns
records[grad_attrs] = gradient_columns
return records
def analyze_gradients(skill, attribute):
results = []
for attr, value in attribute.grad_attrs.items():
origin_value = getattr(attribute, attr)
setattr(attribute, attr, origin_value + value)
_, _, _, expected_damage = skill(attribute)
results.append(expected_damage)
setattr(attribute, attr, origin_value)
return results