Spaces:
Runtime error
Runtime error
File size: 6,183 Bytes
b76daae 2452398 6ab7697 c255694 5825182 2452398 b76daae 5825182 2452398 b76daae 2452398 c255694 17a347d 5825182 b76daae 5825182 17a347d 5825182 17a347d 6e6388e 5825182 17a347d 5825182 17a347d c255694 17a347d 2452398 17a347d 5825182 17a347d 5825182 6e6388e 5825182 6e6388e 5825182 6e6388e c255694 17a347d 2452398 17a347d b76daae 3ed500d b76daae 2452398 b76daae 6ab7697 2452398 5825182 b76daae 55f0dce b76daae 17a347d b76daae 3ed500d b76daae 5825182 17a347d b76daae 17a347d b76daae 6e6388e 60d173b 6e6388e 6d09f00 6e6388e 6d09f00 b76daae 60d173b b76daae 2452398 b76daae 2452398 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
from dataclasses import dataclass
from collections import defaultdict
from typing import Dict
from base.attribute import Attribute
from base.constant import FRAME_PER_SECOND
from base.skill import Skill, DotDamage, PetDamage
from utils.parser import School
@dataclass
class Detail:
damage: int = 0
critical_damage: int = 0
expected_damage: float = 0.
critical_strike: float = 0.
gradients: Dict[str, float] = None
critical_count: int = 0
count: int = 0
def __post_init__(self):
self.gradients = defaultdict(float)
@property
def actual_critical_strike(self):
if self.count:
return self.critical_count / self.count
return 0
def filter_status(status, school: School, skill_id):
buffs = []
for buff_id, buff_level, buff_stack in status:
buff = school.buffs[buff_id]
if not buff.activate:
continue
buff.buff_level, buff.buff_stack = buff_level, buff_stack
if buff.gain_attributes:
buffs.append(buff)
elif skill_id in buff.gain_skills:
buffs.append(buff)
return tuple(sorted(buffs, key=lambda x: x.buff_id))
def add_buffs(current_buffs, snapshot_buffs, target_buffs, attribute: Attribute, skill: Skill):
final_buffs = []
if not snapshot_buffs:
for buff in current_buffs:
buff.add_all(attribute, skill)
final_buffs.append(buff)
elif isinstance(skill, DotDamage):
for buff in snapshot_buffs:
if buff.add_dot(attribute, skill, True):
final_buffs.append(buff)
for buff in current_buffs:
if buff.add_dot(attribute, skill, False):
final_buffs.append(buff)
elif isinstance(skill, PetDamage):
for buff in snapshot_buffs:
buff.add_all(attribute, skill)
final_buffs.append(buff)
for buff in target_buffs:
buff.add_all(attribute, skill)
return final_buffs + list(target_buffs)
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, PetDamage):
for buff in snapshot_buffs:
buff.sub_all(attribute, skill)
for buff in target_buffs:
buff.sub_all(attribute, skill)
def concat_buffs(buffs):
buffs = ",".join(buff.display_name for buff in buffs)
if not buffs:
buffs = "~"
return buffs
def analyze_details(record, duration: int, attribute: Attribute, school: School):
total = Detail()
details = {}
summary = {}
duration *= FRAME_PER_SECOND
for skill, status in record.items():
skill_id, skill_level, skill_stack = skill
skill: Skill = school.skills[skill_id]
if not skill.activate:
continue
skill.skill_level, skill.skill_stack = skill_level, skill_stack
skill_name = skill.skill_name
skill_detail = details[skill.display_name] = {}
if not (skill_summary := summary.get(skill_name)):
skill_summary = summary[skill_name] = Detail()
skill_total = skill_detail[""] = Detail()
for (current_status, snapshot_status, target_status), timeline in status.items():
if not (timeline := [t for t in timeline if t[0] < duration]):
continue
critical_timeline = [t for t in timeline if t[1]]
current_buffs = filter_status(current_status, school, skill_id)
snapshot_buffs = filter_status(snapshot_status, school, skill_id)
target_buffs = filter_status(target_status, school, skill_id)
buffs = add_buffs(current_buffs, snapshot_buffs, target_buffs, attribute, skill)
buffs = concat_buffs(buffs)
detail = skill_detail[buffs] = Detail(*skill(attribute))
detail.gradients = analyze_gradients(skill, attribute)
sub_buffs(current_buffs, snapshot_buffs, target_buffs, attribute, skill)
detail.critical_count += len(critical_timeline)
detail.count += len(timeline)
skill_total.critical_count += len(critical_timeline)
skill_total.count += len(timeline)
skill_total.damage += detail.damage * len(timeline)
skill_total.critical_damage += detail.critical_damage * len(timeline)
skill_total.expected_damage += detail.expected_damage * len(timeline)
skill_total.critical_strike += detail.critical_strike * len(timeline)
for attr, residual_damage in detail.gradients.items():
skill_total.gradients[attr] += residual_damage * len(timeline)
if skill_total.count:
total.expected_damage += skill_total.expected_damage
skill_summary.expected_damage += skill_total.expected_damage
skill_summary.critical_count += skill_total.critical_strike
skill_summary.count += skill_total.count
skill_total.damage /= skill_total.count
skill_total.critical_damage /= skill_total.count
skill_total.expected_damage /= skill_total.count
skill_total.critical_strike /= skill_total.count
for attr, residual_damage in skill_total.gradients.items():
total.gradients[attr] += residual_damage
skill_total.gradients[attr] /= skill_total.count
else:
details.pop(skill.display_name)
summary = {skill: detail for skill, detail in summary.items() if detail.count}
return total, summary, details
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)
_, _, results[attr], _ = skill(attribute)
setattr(attribute, attr, origin_value)
return results
|