From 0052be32cd910bc456fdc7c8a8eb4217f28b91b9 Mon Sep 17 00:00:00 2001 From: seria Date: Mon, 27 May 2024 16:25:28 +0900 Subject: [PATCH] feat: Add a bunch of util functions --- ambr/__init__.py | 1 + ambr/constants.py | 28 +++++++++++ ambr/utils.py | 116 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 ambr/constants.py diff --git a/ambr/__init__.py b/ambr/__init__.py index 14b4121..8ef195c 100644 --- a/ambr/__init__.py +++ b/ambr/__init__.py @@ -1,3 +1,4 @@ +from . import constants, utils from .client import * from .exceptions import * from .models import * diff --git a/ambr/constants.py b/ambr/constants.py new file mode 100644 index 0000000..672052d --- /dev/null +++ b/ambr/constants.py @@ -0,0 +1,28 @@ +__all__ = ("AUDIO_LANGUAGES", "PERCENTAGE_FIGHT_PROPS") + +PERCENTAGE_FIGHT_PROPS = { + "FIGHT_PROP_HP_PERCENT", + "FIGHT_PROP_ATTACK_PERCENT", + "FIGHT_PROP_DEFENSE_PERCENT", + "FIGHT_PROP_SPEED_PERCENT", + "FIGHT_PROP_CRITICAL", + "FIGHT_PROP_CRITICAL_HURT", + "FIGHT_PROP_CHARGE_EFFICIENCY", + "FIGHT_PROP_ADD_HURT", + "FIGHT_PROP_HEAL_ADD", + "FIGHT_PROP_HEALED_ADD", + "FIGHT_PROP_FIRE_ADD_HURT", + "FIGHT_PROP_WATER_ADD_HURT", + "FIGHT_PROP_GRASS_ADD_HURT", + "FIGHT_PROP_ELEC_ADD_HURT", + "FIGHT_PROP_ICE_ADD_HURT", + "FIGHT_PROP_WIND_ADD_HURT", + "FIGHT_PROP_PHYSICAL_ADD_HURT", + "FIGHT_PROP_ROCK_ADD_HURT", + "FIGHT_PROP_SKILL_CD_MINUS_RATIO", + "FIGHT_PROP_ATTACK_PERCENT_A", + "FIGHT_PROP_DEFENSE_PERCENT_A", + "FIGHT_PROP_HP_PERCENT_A", +} + +AUDIO_LANGUAGES = ("EN", "CHS", "JP", "KR") diff --git a/ambr/utils.py b/ambr/utils.py index e0afff1..4db7c4d 100644 --- a/ambr/utils.py +++ b/ambr/utils.py @@ -1,5 +1,25 @@ +from __future__ import annotations + import re -from typing import Any +from collections import defaultdict +from typing import TYPE_CHECKING, Any + +from .constants import PERCENTAGE_FIGHT_PROPS + +if TYPE_CHECKING: + import ambr + +__all__ = ( + "calculate_upgrade_stat_values", + "format_layout", + "format_num", + "format_stat_values", + "get_params", + "get_skill_attributes", + "remove_html_tags", + "replace_placeholders", + "replace_pronouns", +) def remove_html_tags(text: str) -> str: @@ -31,3 +51,97 @@ def replace_pronouns(text: str) -> str: text = text.replace("#", "") return text + + +def calculate_upgrade_stat_values( + upgrade_data: ambr.CharacterUpgrade | ambr.WeaponUpgrade, + curve_data: dict[str, dict[str, dict[str, float]]], + level: int, + ascended: bool, +) -> dict[str, float]: + result: defaultdict[str, float] = defaultdict(float) + + for stat in upgrade_data.base_stats: + if stat.prop_type is None: + continue + result[stat.prop_type] = ( + stat.init_value * curve_data[str(level)]["curveInfos"][stat.growth_type] + ) + + for promote in reversed(upgrade_data.promotes): + if promote.add_stats is None: + continue + if (level == promote.unlock_max_level and ascended) or level > promote.unlock_max_level: + for stat in promote.add_stats: + if stat.value != 0: + result[stat.id] += stat.value + if stat.id in { + "FIGHT_PROP_CRITICAL_HURT", + "FIGHT_PROP_CRITICAL", + }: + result[stat.id] += 0.5 + break + + return result + + +def format_stat_values(stat_values: dict[str, float]) -> dict[str, str]: + result: dict[str, str] = {} + for fight_prop, value in stat_values.items(): + if fight_prop in PERCENTAGE_FIGHT_PROPS: + result[fight_prop] = f"{round(value * 100, 1)}%" + else: + result[fight_prop] = str(round(value)) + return result + + +def format_num(digits: int, calculation: int | float) -> str: + return f"{calculation:.{digits}f}" + + +def format_layout(text: str) -> str: + if "LAYOUT" in text: + brackets = re.findall(r"{LAYOUT.*?}", text) + word_to_replace = re.findall(r"{LAYOUT.*?#(.*?)}", brackets[0])[0] + text = text.replace("".join(brackets), word_to_replace) + return text + + +def get_params(text: str, param_list: list[int | float]) -> list[str]: + params: list[str] = re.findall(r"{[^}]*}", text) + + for item in params: + if "param" not in item: + continue + + param_text = re.findall(r"{param(\d+):([^}]*)}", item)[0] + param, value = param_text + + if value in {"F1P", "F2P"}: + result = format_num(int(value[1]), param_list[int(param) - 1] * 100) + text = re.sub(re.escape(item), f"{result}%", text) + elif value in {"F1", "F2"}: + result = format_num(int(value[1]), param_list[int(param) - 1]) + text = re.sub(re.escape(item), result, text) + elif value == "P": + result = format_num(0, param_list[int(param) - 1] * 100) + text = re.sub(re.escape(item), f"{result}%", text) + elif value == "I": + result = int(param_list[int(param) - 1]) + text = re.sub(re.escape(item), str(round(result)), text) + + text = format_layout(text) + text = text.replace("{NON_BREAK_SPACE}", "") + text = text.replace("#", "") + return text.split("|") + + +def get_skill_attributes(descriptions: list[str], params: list[int | float]) -> str: + result = "" + for desc in descriptions: + try: + k, v = get_params(desc, params) + except ValueError: + continue + result += f"{k}: {v}\n" + return result