From d5d7b208f35449665647ac622b90e33574691091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E7=93=9C=C2=B0?= Date: Thu, 4 Jun 2026 19:47:42 +0800 Subject: [PATCH] refactor: extract character effect helpers --- backend/core/basic/character/calc_equip.py | 16 ++++----- backend/core/basic/character/effect_apply.py | 17 ++++++++++ backend/tests/unit/test_effect_apply.py | 35 ++++++++++++++++++++ 3 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 backend/core/basic/character/effect_apply.py create mode 100644 backend/tests/unit/test_effect_apply.py diff --git a/backend/core/basic/character/calc_equip.py b/backend/core/basic/character/calc_equip.py index 8f4faaba..98b2a38c 100644 --- a/backend/core/basic/character/calc_equip.py +++ b/backend/core/basic/character/calc_equip.py @@ -7,6 +7,7 @@ from ..formula import 增幅计算, 强化技攻, 武器强化计算, 精通计 from ..roleinfo import CharacterEmblemInfo, CharacterEquipInfo, CharacterOathInfo, get_key_by_value from .base import CharacterBase from .config_view import CalcConfigView +from .effect_apply import apply_uppercase_attrs @cache @@ -163,8 +164,7 @@ class CalcEquipMixin(CharacterBase): # 如果存在誓约和套装是同一个套装 # 则直接不执行原套装效果,执行誓约套装增强的效果 oathEffect = oath_suit_by_suit_id.get(suit.suitId, None) - filtered_dict = {k: v for k, v in suit.__dict__.items() if k[0].isupper()} - self.SetStatus(**filtered_dict) + apply_uppercase_attrs(self, suit) if func is not None and oathEffect is None: # print(f'套装 {suit.name} 生效') func(self) @@ -185,13 +185,11 @@ class CalcEquipMixin(CharacterBase): skills = [x for x in oathSuit.skills if x.suitId == oathSuit.suitId] skill = next((x for x in oathSuit.skills if str(x.skillId) == str(self.charOathSkillId)), None) # 誓约套装效果生效 - filtered_dict = {k: v for k, v in oathSuit.__dict__.items() if k[0].isupper()} - self.SetStatus(**filtered_dict) + apply_uppercase_attrs(self, oathSuit) if skill is not None: oathSkillEffect.append(skill) # 誓约技能效果生效 - filtered_dict = {k: v for k, v in skill.__dict__.items() if k[0].isupper()} - self.SetStatus(**filtered_dict) + apply_uppercase_attrs(self, skill) self.oathSkillInfo.append(skill) self.oathSuitInfo.append(oathSuit) if oathSuit.suitId == max_point_oath_suit: @@ -236,8 +234,7 @@ class CalcEquipMixin(CharacterBase): fun = effects.execture(f'equ_{equ.id}') if fun is None: continue - filtered_dict = {k: v for k, v in equ.__dict__.items() if k[0].isupper()} - self.SetStatus(**filtered_dict) + apply_uppercase_attrs(self, equ) fun(self) fun = effects.execture(f'enchant_{enchat}') if fun is not None: @@ -287,8 +284,7 @@ class CalcEquipMixin(CharacterBase): fun = effects.execture(f'oath_{oath.id}') if fun is None: continue - filtered_dict = {k: v for k, v in oath.__dict__.items() if k[0].isupper()} - self.SetStatus(**filtered_dict) + apply_uppercase_attrs(self, oath) fun(self) pass diff --git a/backend/core/basic/character/effect_apply.py b/backend/core/basic/character/effect_apply.py new file mode 100644 index 00000000..5eabdbbd --- /dev/null +++ b/backend/core/basic/character/effect_apply.py @@ -0,0 +1,17 @@ +from typing import Any + + +def uppercase_attrs(source: Any) -> dict[str, Any]: + return {key: value for key, value in source.__dict__.items() if key and key[0].isupper()} + + +def apply_uppercase_attrs(character: Any, source: Any) -> None: + character.SetStatus(**uppercase_attrs(source)) + + +def execute_effect(effects: Any, key: str, *args: Any) -> bool: + fun = effects.execture(key) + if fun is None: + return False + fun(*args) + return True diff --git a/backend/tests/unit/test_effect_apply.py b/backend/tests/unit/test_effect_apply.py new file mode 100644 index 00000000..bb100113 --- /dev/null +++ b/backend/tests/unit/test_effect_apply.py @@ -0,0 +1,35 @@ +from core.basic.character.effect_apply import execute_effect, uppercase_attrs + + +class Source: + STR = 10 + + def __init__(self): + self.INT = 20 + self.name = 'ignored' + + +class Effects: + def execture(self, key): + if key != 'known': + return None + + def effect(target): + target.append(key) + + return effect + + +def test_uppercase_attrs_returns_only_uppercase_instance_keys(): + assert uppercase_attrs(Source()) == {'INT': 20} + + +def test_execute_effect_returns_false_for_missing_effect(): + assert execute_effect(Effects(), 'missing', []) is False + + +def test_execute_effect_calls_existing_effect(): + target = [] + + assert execute_effect(Effects(), 'known', target) is True + assert target == ['known']