151 lines
6.3 KiB
C#
151 lines
6.3 KiB
C#
using Cielonos.MainGame.Characters;
|
|
using Cielonos.MainGame.FunctionalAnimation;
|
|
using SLSUtilities.General;
|
|
using UnityEngine;
|
|
|
|
namespace Cielonos.MainGame.Inventory.Collections
|
|
{
|
|
/// <summary>
|
|
/// Aleph 级支援装备:持续重掷 Luck、Curse、最终伤害倍率和敌方强力动作抗性。
|
|
/// </summary>
|
|
public class ChaosPact : SupportEquipmentBase
|
|
{
|
|
/// <summary>
|
|
/// 混沌契约每次重掷属性和伤害倍率的间隔。
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强力动作开始时按随机结果映射抗性等级。
|
|
/// 随机值越高,敌人越容易被较低等级的攻击打断。
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 对玩家而言,较高的随机好坏值应提升造成伤害。
|
|
/// </summary>
|
|
private static float MapGoodnessToDealtDamageMultiplier(float goodness)
|
|
{
|
|
return Mathf.Lerp(MinimumDamageMultiplier, MaximumDamageMultiplier, goodness);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 对玩家而言,较高的随机好坏值应降低受到伤害。
|
|
/// </summary>
|
|
private static float MapGoodnessToReceivedDamageMultiplier(float goodness)
|
|
{
|
|
return Mathf.Lerp(MaximumDamageMultiplier, MinimumDamageMultiplier, goodness);
|
|
}
|
|
|
|
private void RegisterResistanceResolver()
|
|
{
|
|
if (_isResistanceResolverRegistered) return;
|
|
|
|
SetBreakthroughResistance.onResolveBreakthroughableType.InsertByPriority(
|
|
ResistanceResolverKey,
|
|
new PrioritizedFunc<Automata, Breakthrough.Type, Breakthrough.Type>(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);
|
|
}
|
|
}
|
|
}
|