using System; using System.Collections.Generic; using Cielonos.MainGame.Characters; using DamageNumbersPro; using Sirenix.OdinInspector; using SLSUtilities.FunctionalAnimation; using SLSUtilities.General; using UnityEngine; using Random = UnityEngine.Random; namespace Cielonos.MainGame.Characters.Inventory { [Serializable] [HideReferenceObjectPicker] public partial class AttackUnit : ICloneable { [ReadOnly] public AttackData parentData; [ReadOnly] [Tooltip("和AttackData中的key对应,且用于运行时识别这个攻击单元")] public string unitName; [Title("Attack Parameters")] [Tooltip("如果为true,则这个攻击单元不会造成伤害,也不会触发暴击等相关机制,通常用于仅触发特殊效果")] public bool isInvalidAttack; [HideIf("isInvalidAttack")] public Attack.AttackType attackType = Attack.AttackType.Kinetics; [HideIf("isInvalidAttack")] public float startDamage; [HideIf("isInvalidAttack")] public float damageDeviation; [Tooltip("是否在多段攻击时独立计算伤害和暴击")] [HideIf("isInvalidAttack")] public bool isIndependentPerHit = true; [HideIf("isInvalidAttack")] public float criticalChance; [HideIf("isInvalidAttack")] public float criticalMultiplier = 1; [Title("Hit Effects")] public BreakthroughType breakthroughType = BreakthroughType.Weak; public DisruptionType disruptionType = DisruptionType.NormalExternal; [Title("Tags")] public List tags = new List(); [Title("Hit VFX")] public bool useVFXDataHit; [HideIf("useVFXDataHit")] public GameObject hitVFX; [ShowIf("useVFXDataHit")] public string vfxUnitName; [Title("Extra Modules")] [ListDrawerSettings(ShowFoldout = true)] [SerializeReference] public List submodules = new List(); public bool TryGetSubModule(out T submodule) where T : Submodule { submodule = submodules.Find(m => m is T) as T; return submodule != null; } public T GetSubmodule() where T : Submodule { return submodules.Find(m => m is T) as T; } public AttackValue GetAttackValue(CharacterBase attacker) { bool isCritical = Random.value < GetFinalCriticalChance(); float finalDamage = isCritical ? GetFinalCriticalDamage() : GetFinalRegularDamage(); return new AttackValue(attacker, isCritical, finalDamage, attackType, disruptionType, breakthroughType, tags); } public GameObject GetHitVFX() { return hitVFX != null ? hitVFX : parentData.defaultHitVFX; } public float GetFinalRegularDamage() { return startDamage + Random.Range(-damageDeviation, damageDeviation); // * GameManager.Player.attributeModule.currentAttributes["AttackPowerCoefficient"]; } public float GetFinalCriticalDamage() { return (startDamage + Random.Range(-damageDeviation, damageDeviation)) * GetFinalCriticalMultiplier();// * GameManager.Player.attributeModule.currentAttributes["AttackPowerCoefficient"] * GetFinalCriticalMultiplier(); } public float GetFinalCriticalChance() { return criticalChance;//+ GameManager.Player.attributeModule.currentAttributes["CriticalChance"]; } public float GetFinalCriticalMultiplier() { return criticalMultiplier;// + GameManager.Player.attributeModule.currentAttributes["CriticalMultiplier"] + 1; } public AttackUnit Clone() { return (AttackUnit) this.MemberwiseClone(); } } public partial class AttackUnit { [Serializable] public abstract class Submodule : SubmoduleBase { public Submodule(AttackUnit owner) : base(owner) { } } [Serializable] public class ParameterSubmodule : Submodule { public Dictionary floatParameters = new Dictionary(); public Dictionary intParameters = new Dictionary(); public Dictionary stringParameters = new Dictionary(); public ParameterSubmodule() : base(null) { } public ParameterSubmodule(AttackUnit owner) : base(owner) { } public T GetParameter(string key) { if (typeof(T) == typeof(float)) { return floatParameters.TryGetValue(key, out float floatParameter) ? (T)(object)floatParameter : (T)(object)0f; } if (typeof(T) == typeof(int)) { return intParameters.TryGetValue(key, out int intParameter) ? (T)(object)intParameter : (T)(object)0; } if (typeof(T) == typeof(string)) { return stringParameters.TryGetValue(key, out string stringParameter) ? (T)(object)stringParameter : (T)(object)string.Empty; } throw new InvalidOperationException($"Unsupported parameter type: {typeof(T)}"); } } [Serializable] public class DamageNumberSubmodule : Submodule { public DamageNumber regularPrefab; public DamageNumber criticalPrefab; public Dictionary customPrefabs = new Dictionary(); public DamageNumberSubmodule() : base(null) { } public DamageNumberSubmodule(AttackUnit owner) : base(owner) { } } } }