using Cielonos.MainGame.Characters; using Cielonos.MainGame.FunctionalAnimation; using SLSUtilities.General; using UnityEngine; namespace Cielonos.MainGame.Inventory.Collections { /// /// Aleph 级支援装备:持续重掷 Luck、Curse、最终伤害倍率和敌方强力动作抗性。 /// public class ChaosPact : SupportEquipmentBase { /// /// 混沌契约每次重掷属性和伤害倍率的间隔。 /// private const float RefreshInterval = 0.1f; private const float MinimumDamageMultiplier = 0f; private const float MaximumDamageMultiplier = 2f; private const string ResistanceResolverKey = nameof(ChaosPact); private float _refreshTimer; private bool _isResistanceResolverRegistered; public override bool CanUnequip => false; public override void Initialize() { base.Initialize(); if (activeAttributeData != null) { activeAttributeSm = new AttributeSubmodule(this, activeAttributeData); } } public override void OnEquipped() { base.OnEquipped(); RegisterResistanceResolver(); _refreshTimer = 0f; RefreshChaosState(); } public override void OnUnequipped() { UnregisterResistanceResolver(); RemoveChaosModifiers(); base.OnUnequipped(); } protected override void Update() { if (!player.inventorySc.equipmentSm.currentSupportEquipments.Contains(this)) return; base.Update(); _refreshTimer += player.selfTimeSm.DeltaTime; if (_refreshTimer < RefreshInterval) return; _refreshTimer %= RefreshInterval; RefreshChaosState(); } private void RefreshChaosState() { if (activeAttributeSm == null) return; // 当前版本将 Luck 和 Curse 作为契约的运行时数值来源;未来可替换为正式的属性覆盖层。 activeAttributeSm.charAttrNumericChange[CharacterAttribute.Luck] = Randomizer.Roll01() * 100f; activeAttributeSm.charAttrNumericChange[CharacterAttribute.Curse] = Randomizer.Roll01() * 100f; player.attributeSm.RefreshAttribute(CharacterAttribute.Luck); player.attributeSm.RefreshAttribute(CharacterAttribute.Curse); float luck = player.attributeSm[CharacterAttribute.Luck]; float curse = player.attributeSm[CharacterAttribute.Curse]; activeAttributeSm.chaAttrPercentageChangeOfMultiplication[CharacterAttribute.FinalDamageDealtMultiplier] = MapGoodnessToDealtDamageMultiplier(Randomizer.RollLuckCurse01(luck, curse)); activeAttributeSm.chaAttrPercentageChangeOfMultiplication[CharacterAttribute.FinalDamageReceivedMultiplier] = MapGoodnessToReceivedDamageMultiplier(Randomizer.RollLuckCurse01(luck, curse)); player.attributeSm.RefreshAttribute(CharacterAttribute.FinalDamageDealtMultiplier); player.attributeSm.RefreshAttribute(CharacterAttribute.FinalDamageReceivedMultiplier); } /// /// 强力动作开始时按随机结果映射抗性等级。 /// 随机值越高,敌人越容易被较低等级的攻击打断。 /// private Breakthrough.Type ResolveBreakthroughableType(Automata enemy, Breakthrough.Type originalType) { if (originalType is not (Breakthrough.Type.Heavy or Breakthrough.Type.Disruption or Breakthrough.Type.Forced)) { return originalType; } float goodness = Randomizer.RollLuckCurse01(player.attributeSm[CharacterAttribute.Luck], player.attributeSm[CharacterAttribute.Curse]); if (goodness >= 2f / 3f) return Breakthrough.Type.Heavy; if (goodness >= 1f / 3f) return Breakthrough.Type.Disruption; return Breakthrough.Type.Forced; } /// /// 对玩家而言,较高的随机好坏值应提升造成伤害。 /// private static float MapGoodnessToDealtDamageMultiplier(float goodness) { return Mathf.Lerp(MinimumDamageMultiplier, MaximumDamageMultiplier, goodness); } /// /// 对玩家而言,较高的随机好坏值应降低受到伤害。 /// private static float MapGoodnessToReceivedDamageMultiplier(float goodness) { return Mathf.Lerp(MaximumDamageMultiplier, MinimumDamageMultiplier, goodness); } private void RegisterResistanceResolver() { if (_isResistanceResolverRegistered) return; SetBreakthroughResistance.onResolveBreakthroughableType.InsertByPriority( ResistanceResolverKey, new PrioritizedFunc(ResolveBreakthroughableType)); _isResistanceResolverRegistered = true; } private void UnregisterResistanceResolver() { if (!_isResistanceResolverRegistered) return; SetBreakthroughResistance.onResolveBreakthroughableType.Remove(ResistanceResolverKey); _isResistanceResolverRegistered = false; } private void RemoveChaosModifiers() { if (activeAttributeSm == null) return; // 强制卸下或 run 清理时必须还原运行时写入的四项属性。 activeAttributeSm.charAttrNumericChange.Remove(CharacterAttribute.Luck); activeAttributeSm.charAttrNumericChange.Remove(CharacterAttribute.Curse); activeAttributeSm.chaAttrPercentageChangeOfMultiplication.Remove(CharacterAttribute.FinalDamageDealtMultiplier); activeAttributeSm.chaAttrPercentageChangeOfMultiplication.Remove(CharacterAttribute.FinalDamageReceivedMultiplier); player.attributeSm.RefreshAttribute(CharacterAttribute.Luck); player.attributeSm.RefreshAttribute(CharacterAttribute.Curse); player.attributeSm.RefreshAttribute(CharacterAttribute.FinalDamageDealtMultiplier); player.attributeSm.RefreshAttribute(CharacterAttribute.FinalDamageReceivedMultiplier); } } }