using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Cielonos.MainGame.Characters.Inventory; using DG.Tweening; using Opsive.BehaviorDesigner.Runtime; using Sirenix.OdinInspector; using SLSUtilities.FunctionalAnimation; using SLSUtilities.General; using UniRx; using UnityEngine; using UnityEngine.AI; using Ease = DG.Tweening.Ease; namespace Cielonos.MainGame.Characters { public partial class Automata : CharacterBase { public Player player => MainGameManager.Player; [TitleGroup("Data & Presets")] public FuncAnimDataCollection fullBodyFuncAnims; public FuncAnimDataCollection upperBodyFuncAnims; public AttackData attackData; [HideInInspector] private List registeredFunctionNames = new List(); [TitleGroup("Submodules")] public ActionRecordSubmodule actionRecordSm; [TitleGroup("Subcontrollers")] public BehaviorSubcontroller behaviorSc; private float getHitTimer; protected override void Start() { base.Start(); RegisterFuncAnims(); RegisterFunctionsToAnimSc(); } protected override void InitializeSubmodules() { base.InitializeSubmodules(); actionRecordSm = new ActionRecordSubmodule(this); } protected override void Update() { base.Update(); UpdateGetHit(); } } public partial class Automata { public override bool GetHit(BreakthroughType breakthroughType, out float recoveryTime, DisruptionType disruptionType = DisruptionType.NormalExternal, Vector3 direction = default, string funcAnimName = "") { if (string.IsNullOrEmpty(funcAnimName)) { funcAnimName = GetHitFuncAnimName(breakthroughType, direction); } if (base.GetHit(breakthroughType, out recoveryTime, disruptionType, direction, funcAnimName)) { if (getHitTimer <= 0) { if (behaviorSc.navMeshAgent.enabled) { behaviorSc.navMeshAgent.isStopped = true; } getHitTimer = recoveryTime; } else { getHitTimer = Mathf.Max(getHitTimer, recoveryTime); } return true; } return false; } protected virtual void UpdateGetHit() { getHitTimer -= selfTimeSm.DeltaTime; if (getHitTimer <= 0) { if (behaviorSc.navMeshAgent.enabled) { behaviorSc.navMeshAgent.isStopped = false; } //statusSm.RemoveStatus(StatusType.Stun); } } } public partial class Automata { public override void Die() { eventSm.onDeath.Invoke(); BattleManager.EnemySm.RemoveEnemy(this); float deathProcessTime = 0f; var deathFuncAnim = fullBodyFuncAnims.animDataList.Find(data => data.animInfo.animationName == "Death"); if (deathFuncAnim != null) { animationSc.fullBodyFuncAnimSm.Play("Death"); behaviorSc.mainBehaviorTree.StopBehavior(); behaviorSc.navMeshAgent.enabled = false; collisionSc.DisableAllColliders(); deathProcessTime = deathFuncAnim.animationClip.length; } statusSm.isDead = true; if (deathProcessTime > 0) { Observable.Timer(TimeSpan.FromSeconds(deathProcessTime)).Subscribe(_ => { Sequence fade = DOTween.Sequence(); foreach (Material mat in renderSc.baseRenderMaterials) { fade.Join(mat.DOFloat(1, "_FadeAmount", 1f).SetEase(Ease.InQuint)); //fade.Join(mat.DOColor(Color.clear, "_FadeBurnColor", 1f).SetEase(Ease.Linear)); } fade.OnComplete(() => base.Die()); fade.Play(); }).AddTo(gameObject); } else { base.Die(); } } } public partial class Automata { public Vector3 PredictPlayerPosition(float timeAhead) { Vector3 currentPosition = player.centerPoint.position; Vector3 currentVelocity = player.landMovementSc.horizontalMovement / player.selfTimeSm.DeltaTime; return currentPosition + currentVelocity * timeAhead; } } public partial class Automata { public void RegisterFuncAnims() { if (fullBodyFuncAnims == null) return; foreach (FuncAnimData funcAnim in fullBodyFuncAnims.animDataList) { animationSc.fullBodyFuncAnimSm.Add(funcAnim); } /*foreach (FuncAnimData funcAnim in upperBodyFuncAnims.animDataList) { animationSc.upperBodyFuncAnimSm.Add(funcAnim); }*/ } protected virtual void RegisterFunctionsToAnimSc(params Action[] functions) { if (fullBodyFuncAnims == null) return; RegisterFunctionsToAnimSc(); foreach (Action function in functions) { string functionName = function.Method.Name; if (!animationSc.registeredFunctions.TryAdd(functionName, anim => function())) { Debug.LogWarning($"Function {functionName} is already registered."); } else { registeredFunctionNames.Add(functionName); } } } protected virtual void RegisterFunctionsToAnimSc() { if (fullBodyFuncAnims == null) return; foreach (CustomFunction function in fullBodyFuncAnims.preloadFunctions) { string functionName = function.functionName; string FAPF_functionName = new StringBuilder(functionName).Insert(0, "FAPF_").ToString(); MethodInfo method = GetType().GetMethod(FAPF_functionName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogWarning($"Function {functionName} not found in {this.GetType().Name}. Skipping registration."); continue; } Action action = Delegate.CreateDelegate(typeof(Action), this, method) as Action; registeredFunctionNames.Add(functionName); animationSc.registeredFunctions.TryAdd(functionName, action); } } protected void RemoveAllRegisteredFunctions() { foreach (string functionName in registeredFunctionNames) { if (!animationSc.registeredFunctions.Remove(functionName)) { Debug.LogWarning($"Function {functionName} is not found."); } } registeredFunctionNames.Clear(); } } }