class_name DefenseResolver extends RefCounted static func resolve_effective_defense(context: Dictionary, attack_tags: Array[StringName] = []) -> Dictionary: var defense_state := StringName(str(context.get("defense_state", &"Vulnerable"))) # 背刺破格挡只作用于姿态本身的 Parrying,先降级再合并 effect 修饰符: # 否则霸体(SuperArmor,优先级低于 Parrying)会先被格挡态吞掉、 # 再随背刺降级一起丢失,违反霸体「无击退、不打断」的承诺。 if defense_state == &"Parrying" and not bool(context.get("attack_from_front", true)): defense_state = &"Vulnerable" var modifiers := _defense_modifiers(context, attack_tags) for modifier: Resource in modifiers: var modified_state := StringName(str(modifier.get("defense_state"))) if not modified_state.is_empty(): defense_state = _stronger_defense_state(defense_state, modified_state) var damage_mult := _damage_mult_for_state(defense_state, context) var interrupts := defense_state != &"Invincible" and defense_state != &"SuperArmor" and defense_state != &"Parrying" for modifier: Resource in modifiers: damage_mult *= float(modifier.get("damage_mult")) interrupts = interrupts and bool(modifier.get("interrupts")) return { "defense_state": defense_state, "damage_mult": damage_mult, "interrupts": interrupts, } static func _damage_mult_for_state(defense_state: StringName, context: Dictionary = {}) -> float: match defense_state: &"Invincible": return 0.0 &"Parrying": return _parry_damage_mult(context) &"SuperArmor": return 1.0 _: return 1.0 static func _parry_damage_mult(context: Dictionary) -> float: match StringName(str(context.get("block_judgement", &"perfect"))): &"good": return 0.2 &"bad": return 0.4 &"miss": return 1.0 return 0.0 static func _defense_modifiers(context: Dictionary, attack_tags: Array[StringName]) -> Array[Resource]: var modifiers: Array[Resource] = [] if context.has("defense_modifiers"): modifiers = _resource_array(context["defense_modifiers"]) else: var container = context.get("effect_container", null) if container != null and container.has_method("defense_modifiers"): modifiers = _resource_array(container.call("defense_modifiers")) var matched: Array[Resource] = [] for modifier: Resource in modifiers: if _modifier_matches_attack_tags(modifier, attack_tags): matched.append(modifier) return matched static func _resource_array(value: Variant) -> Array[Resource]: var result: Array[Resource] = [] if value is Array: for item: Variant in value: if item is Resource: result.append(item) return result static func _modifier_matches_attack_tags(modifier: Resource, attack_tags: Array[StringName]) -> bool: var required_tags := _string_name_array(modifier.get("required_attack_tags")) return required_tags.is_empty() or _has_any(attack_tags, required_tags) static func _string_name_array(value: Variant) -> Array[StringName]: var result: Array[StringName] = [] if value is Array: for item: Variant in value: result.append(StringName(str(item))) return result static func _has_any(values: Array[StringName], candidates: Array[StringName]) -> bool: for value: StringName in values: if candidates.has(value): return true return false static func _stronger_defense_state(current_state: StringName, candidate_state: StringName) -> StringName: return candidate_state if _defense_priority(candidate_state) > _defense_priority(current_state) else current_state static func _defense_priority(defense_state: StringName) -> int: match defense_state: &"Invincible": return 4 &"Parrying": return 3 &"SuperArmor": return 2 &"Vulnerable": return 1 _: return 0