Formulator / gr /scripts /combat.py
ango
5.15 commit
d26e0de
raw
history blame
6.72 kB
from typing import Dict
from gr.components.combat import CombatComponent
from assets.constant import ATTR_TYPE_TRANSLATE
# from gr.scripts.bonuses import Bonuses
# from gr.scripts.consumables import Consumables
from gr.scripts.top import Parser
from gr.scripts.equipments import Equipments
from gr.scripts.recipes import Recipes
from gr.scripts.talents import Talents
from utils.analyzer import analyze_details, Detail
import gradio as gr
FULL_SPACE = "\u3000"
def attribute_content(display_attrs, attribute):
content = []
for attr, name in display_attrs.items():
value = getattr(attribute, attr)
if isinstance(value, int):
content.append(name.ljust(10, FULL_SPACE) + str(value))
else:
content.append(name.ljust(10, FULL_SPACE) + f"{round(value * 100, 2)}%")
return "\n".join(content)
def summary_content(summary: Dict[str, Detail], total_damage):
content = []
for skill in sorted(summary, key=lambda x: summary[x].expected_damage, reverse=True):
detail = summary[skill]
critical = round(detail.critical_count, 2)
critical_rate = round(detail.critical_count / detail.count * 100, 2)
hit = round(detail.count - critical, 2)
hit_rate = round(100 - critical_rate, 2)
damage = round(detail.expected_damage, 2)
damage_rate = round(damage / total_damage * 100, 2)
content.append(
[f"{skill}/{detail.count}",
f"{hit}/{hit_rate}%", f"{critical}/{critical_rate}%", f"{damage}/{damage_rate}%"]
)
return content
def gradient_content(gradients, total_damage):
return "\n".join(
ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + f"{round(v / total_damage * 100, 2)}%"
for k, v in gradients.items()
)
def detail_content(detail: Detail):
damage_detail = "\n".join([
"命中伤害".ljust(10) + f"{round(detail.damage)}",
"会心伤害".ljust(10) + f"{round(detail.critical_damage)}",
"期望伤害".ljust(10) + f"{round(detail.expected_damage)}",
"期望会心".ljust(10) + f"{round(detail.critical_strike * 100, 2)}%",
"实际会心".ljust(10) + f"{round(detail.actual_critical_strike * 100, 2)}%",
"统计数量".ljust(10) + f"{detail.count}"
])
damage_gradient = gradient_content(detail.gradients, detail.expected_damage)
return damage_detail, damage_gradient
def combat_script(
parser: Parser,
talents: Talents, recipes: Recipes, equipments: Equipments,
# consumables: Consumables, bonuses: Bonuses
combat_component: CombatComponent,
):
def formulate(target_level, duration, skill, status):
combat_update = {}
record = parser.current_records
school = parser.current_school
attribute = school.attribute()
attribute.target_level = target_level
for attr, value in equipments.attrs.items():
setattr(attribute, attr, getattr(attribute, attr) + value)
combat_update[combat_component.init_attribute] = gr.update(
value=attribute_content(school.display_attrs, attribute)
)
# for attr, value in consumables.attrs.items():
# setattr(attribute, attr, getattr(attribute, attr) + value)
equipment_gains = [school.gains[gain] for gain in equipments.gains]
talent_gains = [school.talent_gains[school.talent_encoder[talent]] for talent in talents.gains]
recipe_gains = [
school.recipe_gains[skill][recipe]
for i, skill in enumerate(school.recipe_gains)
for recipe in recipes.gains[i]
]
gains = equipment_gains + talent_gains + recipe_gains # + bonuses.gains
for gain in gains:
gain.add(attribute, school.skills, school.buffs)
combat_update[combat_component.final_attribute] = gr.update(
value=attribute_content(school.display_attrs, attribute)
)
total, summary, details = analyze_details(record, duration, attribute, school)
for gain in gains:
gain.sub(attribute, school.skills, school.buffs)
combat_update[combat_component.dps] = gr.update(value=round(total.expected_damage / duration))
combat_update[combat_component.gradient] = gradient_content(total.gradients, total.expected_damage)
combat_update[combat_component.details] = details
combat_update[combat_component.skill_select] = gr.update(choices=list(details))
if skill_detail := details.get(skill, {}):
combat_update[combat_component.status_select] = gr.update(choices=[""] + list(skill_detail))
if detail := skill_detail.get(status):
damage_detail, damage_gradient = detail_content(detail)
combat_update[combat_component.damage_detail] = gr.update(value=damage_detail)
combat_update[combat_component.damage_gradient] = gr.update(value=damage_gradient)
else:
combat_update[combat_component.damage_detail] = gr.update(value="")
combat_update[combat_component.damage_gradient] = gr.update(value="")
combat_update[combat_component.summary] = summary_content(summary, total.expected_damage)
return combat_update
combat_component.formulate.click(
formulate,
[combat_component.target_level, combat_component.combat_duration,
combat_component.skill_select, combat_component.status_select],
[combat_component.init_attribute, combat_component.final_attribute,
combat_component.dps, combat_component.gradient, combat_component.summary,
combat_component.details, combat_component.skill_select, combat_component.status_select,
combat_component.damage_detail, combat_component.damage_gradient
]
)
def skill_changed(skill, details):
if skill not in details:
return None
return gr.update(choices=[""] + list(details[skill]))
combat_component.skill_select.change(
skill_changed, [combat_component.skill_select, combat_component.details], combat_component.status_select
)
def status_changed(skill, status, details):
if skill not in details:
return None, None
if status not in details[skill]:
return None, None
damage_detail, damage_gradient = detail_content(details[skill][status])
return gr.update(value=damage_detail), gr.update(value=damage_gradient)
combat_component.status_select.change(
status_changed, [combat_component.skill_select, combat_component.status_select, combat_component.details],
[combat_component.damage_detail, combat_component.damage_gradient]
)