using System; using Cielonos.MainGame.Chaaracters; using Sirenix.OdinInspector; using SLSFramework.WwiseAssistance; using SLSUtilities.FunctionalAnimation; using UniRx; using UnityEngine; using UnityEngine.AI; using UnityEngine.Serialization; namespace Cielonos.MainGame.Characters { public enum Fraction { Player = 0, AlliedMinion = 1, Enemy = 10, Neutral = 20 } public partial class CharacterBase : SerializedMonoBehaviour { public Fraction fraction; public Transform flexibleCenterPoint; public Transform footPoint; [TitleGroup("Data & Presets")] public AttributeData attributeData; public BaseAnimationGroup baseAnimationGroup; [TitleGroup("Submodules")] public SelfTimeSubmodule selfTimeSm; public AttributeSubmodule attributeSm; public AdditionalForceSubmodule additionalForceSm; public CompositeDisposable disposables; [TitleGroup("Subcontrollers")] public CollisionSubcontrollerBase collisionSc; public MovementSubcontrollerBase movementSc; [Required] public AnimationSubcontrollerBase animationSc; [Required] public RenderSubcontrollerBase renderSc; public BodyPartsSubcontroller bodyPartsSc; public AudioSubcontroller audioSc; public ReactionSubcontroller reactionSc; public FeedbackSubcontroller feedbackSc; protected virtual void Awake() { InitializeSubmodules(); InitializeSubcontrollers(); } #if UNITY_EDITOR private void Reset() { InitializeSubmodules(); } #endif protected virtual void Start() { if (fraction == Fraction.Enemy) { BattleManager.EnemySm.activeEnemiesList.Add(this); } } public virtual void Die() { Destroy(gameObject);//TODO: 后续改为死亡动画+回收 } } public partial class CharacterBase { protected virtual void InitializeSubmodules() { selfTimeSm ??= new SelfTimeSubmodule(this); attributeSm ??= new AttributeSubmodule(this); additionalForceSm ??= new AdditionalForceSubmodule(this); disposables ??= new CompositeDisposable(); } protected virtual void InitializeSubcontrollers() { renderSc?.Initialize(); movementSc?.Initialize(); animationSc?.Initialize(); collisionSc?.Initialize(); bodyPartsSc?.Initialize(); audioSc?.Initialize(); reactionSc?.Initialize(); feedbackSc?.Initialize(); } } public partial class CharacterBase { public float DealAttack(AttackValue attackValue, out bool isDead) { float finalDamage = 0; /*if (statusModule.IsInvincible) { isDead = false; GeneralUtilities.InstantiateInfo(flexibleCenterPoint.position, "无敌"); return finalDamage; }*/ finalDamage = GetDamageValueAfterResistance(attackValue); if (attributeSm.HasAttribute("Shield") && attributeSm["Shield"] > 0) { float blockedDamage = Mathf.Min(finalDamage, attributeSm["Shield"]); //GeneralUtilities.InstantiateBlockedDamageNumber(flexibleCenterPoint.position, blockedDamage); if(finalDamage > attributeSm["Shield"]) { finalDamage -= attributeSm["Shield"]; attributeSm["Shield"] = 0; } else { attributeSm["Shield"] -= finalDamage; finalDamage = 0; } } attributeSm["Health"] -= finalDamage; if (attributeSm["Health"] <= 0) { isDead = true; attributeSm["Health"] = 0; Die(); } else { isDead = false; } return finalDamage; } public float GetDamageValueAfterResistance(AttackValue attackValue) { /*float reductionRate = attributeModule.currentAttributes.TryGetValue("DamageReduction", out float rate) ? rate : 0; return attackValue.attackType switch { AttackType.Energy => attackValue.damage * GetDamageReduction(attributeModule.GetCurrentAttribute("EnergyAttackResistance"), reductionRate), AttackType.Kinetics => attackValue.damage * GetDamageReduction(attributeModule.GetCurrentAttribute("KineticAttackResistance"), reductionRate), AttackType.Explosion => attackValue.damage * GetDamageReduction(attributeModule.GetCurrentAttribute("ExplosionAttackResistance"), reductionRate), AttackType.Magic => attackValue.damage * GetDamageReduction(attributeModule.GetCurrentAttribute("MagicAttackResistance"), reductionRate), AttackType.Elemental => attackValue.damage * GetDamageReduction(attributeModule.GetCurrentAttribute("ElementalAttackResistance"), reductionRate), AttackType.Pure => attackValue.damage * GetDamageReduction(0, reductionRate), _ => throw new ArgumentOutOfRangeException() };*/ return attackValue.damage; } } public partial class CharacterBase { public virtual bool GetHit(BreakthroughType breakthroughType, DisruptionType disruptionType = DisruptionType.NormalExternal, Vector3 direction = default) { renderSc.GetHitBlink(); if (animationSc.SetGetHitDisruption(disruptionType, breakthroughType)) { animationSc.PlayGetHitMediumAnimation(direction); return true; } return false; } } }