using System; using System.Collections.Generic; using System.Reflection; using System.Text; using Cielonos.MainGame.Characters; using Cielonos.MainGame.FunctionalAnimation; using MoreMountains.Feedbacks; using MoreMountains.FeedbacksForThirdParty; using Sirenix.OdinInspector; using SLSUtilities.WwiseAssistance; using SLSUtilities.FunctionalAnimation; using UnityEngine; using UnityEngine.Serialization; namespace Cielonos.MainGame.Characters.Inventory { public abstract partial class ItemBase : SerializedMonoBehaviour { public Player player => MainGameManager.Instance.player; protected PlayerAnimationSubcontroller animationSc => player.animationSc; protected FunctionalAnimationSubmodule fullBodyFuncAnimSm => animationSc.fullBodyFuncAnimSm; protected FunctionalAnimationSubmodule upperBodyFuncAnimSm => animationSc.upperBodyFuncAnimSm; [HideInInspector] private List registeredFunctionNames = new List(); [TitleGroup("Data")] public FuncAnimDataCollection fullBodyFuncAnims; public FuncAnimDataCollection upperBodyFuncAnims; public ContentData contentData; public ViewObjectData viewObjectData; public VFXData vfxData; public AttributeData passiveAttributeData; public ComboData comboData; public AttackData attackData; public FunctionData functionData; public AmmoData ammoData; public BlockData blockData; [TitleGroup("Audio")] public AudioContainer audioContainer; [TitleGroup("Submodules")] public AttributeSubmodule passiveAttributeSm; public ComboSubmodule comboSm; public FunctionSubmodule functionSm; public AmmoSubmodule ammoSm; [TitleGroup("Subcontrollers")] public FeedbackSubcontroller feedbackSc; [TitleGroup("View Objects")] public Dictionary viewObjects = new Dictionary(); } public partial class ItemBase { public virtual void Initialize() { vfxData?.Initialize(player); if(comboData != null) comboSm = new ComboSubmodule(this, comboData); if(functionData != null) functionSm = new FunctionSubmodule(this, functionData); if(ammoData != null) ammoSm = new AmmoSubmodule(this, ammoData); if(passiveAttributeData != null) passiveAttributeSm = new AttributeSubmodule(this, passiveAttributeData); } public virtual void OnObtained() { passiveAttributeSm?.RefreshAllModifiedAttributes(); } public virtual void OnDiscarded() { passiveAttributeSm?.RefreshAllModifiedAttributes(); } protected virtual void Update() { functionSm?.Update(player.selfTimeSm.DeltaTime); } } public partial class ItemBase { protected void SpawnViewObjects() { if (viewObjectData != null) { foreach (ViewObjectData.ViewObjectDataUnit unit in viewObjectData.viewObjectUnits) { Transform attachPoint = !unit.isCustomAttachPoint ? player.bodyPartsSc.GetPart(unit.normalAttachBodyPart) : player.bodyPartsSc.GetPart(unit.customAttachPartName); if (attachPoint != null) { ItemViewObject view = Instantiate(unit.objectPrefab, attachPoint).GetComponent(); if (unit.applyOffset) { view.transform.localPosition = unit.positionOffset; view.transform.localEulerAngles = unit.rotationOffset; } viewObjects[unit.objectName] = view; } } } } public void DespawnViewObjects() { foreach (KeyValuePair kvp in viewObjects) { Destroy(kvp.Value.gameObject); } viewObjects.Clear(); } } public partial class ItemBase { protected bool PlayTargetedAnimation(string animationName, CharacterBase target = null, float adsorptionMinDistance = 1f, bool keepAdsorption = false, bool autoRotate = true, FunctionalAnimationSubmodule funcAnimSm = null, float animationSpeedMultiplier = 1f, float transitionDuration = 0.1f, bool isNormalizedTransition = false, string comboTreeName = "Main") { funcAnimSm ??= fullBodyFuncAnimSm; FuncAnimData data = funcAnimSm.collection[animationName]; if (data.animInfo.tags.Contains("Attack") && data.animInfo.isAffectedBySpeedMultiplier) { animationSpeedMultiplier *= player.attributeSm["AttackSpeed"]; } if (funcAnimSm.Play(data, animationSpeedMultiplier, transitionDuration, isNormalizedTransition)) { float actionCoolDownTime = funcAnimSm.currentData.Interval(IntervalType.ActionDisruption).StartTime / funcAnimSm.currentPlaySpeedMultiplier; comboSm?[comboTreeName].SuspendThenSetup(actionCoolDownTime); if (target != null) { if (autoRotate) player.landMovementSc.TurnToTarget(target); if (keepAdsorption) { funcAnimSm.currentRuntimeFuncAnim.AddUpdateEvent(new SetRootAdsorptionAdjustment.Keep(target, adsorptionMinDistance)); } else { funcAnimSm.currentRuntimeFuncAnim.AddUpdateUntilEvent(new SetRootAdsorptionAdjustment.Once(target, adsorptionMinDistance)); } } return true; } return false; } protected virtual void Swing(string feedBackName, Vector3 swingRotation = default, Vector3 swingPosition = default) { Vector3 playerForward = player.transform.forward; Vector3 cameraForward = player.viewSc.playerCamera.transform.forward; Vector3 flatPlayerFwd = Vector3.ProjectOnPlane(playerForward, Vector3.up).normalized; Vector3 flatCameraFwd = Vector3.ProjectOnPlane(cameraForward, Vector3.up).normalized; Quaternion deltaRotation = Quaternion.FromToRotation(flatCameraFwd, flatPlayerFwd); Vector3 tempRotVec = new Vector3(swingRotation.y, swingRotation.x, swingRotation.z); Vector3 rotatedTemp = deltaRotation * tempRotVec; Vector3 finalRotation = new Vector3(rotatedTemp.y, rotatedTemp.x, rotatedTemp.z); Vector3 finalPosition = deltaRotation * swingPosition; MMF_CinemachineRotation cinemachineRotation = feedbackSc[feedBackName].feedback.GetFeedbackOfType(); if (cinemachineRotation != null) { cinemachineRotation.RotationAmplitude = finalRotation; } MMF_CinemachinePosition cinemachinePosition = feedbackSc[feedBackName].feedback.GetFeedbackOfType(); if (cinemachinePosition != null) { cinemachinePosition.PositionAmplitude = finalPosition; } feedbackSc[feedBackName].Play(); } } public partial class ItemBase { public void RegisterFuncAnims() { if (fullBodyFuncAnims == null) return; foreach (FuncAnimData funcAnim in fullBodyFuncAnims.animDataList) { player.animationSc.fullBodyFuncAnimSm.Add(funcAnim); } foreach (FuncAnimData funcAnim in upperBodyFuncAnims.animDataList) { player.animationSc.upperBodyFuncAnimSm.Add(funcAnim); } } protected virtual void RegisterFunctionsToAnimSc(params Action[] functions) { RegisterFunctionsToAnimSc(); foreach (Action function in functions) { string functionName = function.Method.Name; if (!player.animationSc.registeredFunctions.TryAdd(functionName, anim => function())) { Debug.LogWarning($"Function {functionName} is already registered."); } else { registeredFunctionNames.Add(functionName); } } } protected virtual void RegisterFunctionsToAnimSc() { 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); player.animationSc.registeredFunctions.TryAdd(functionName, action); } } protected void RemoveAllRegisteredFunctions() { foreach (string functionName in registeredFunctionNames) { if (!player.animationSc.registeredFunctions.Remove(functionName)) { Debug.LogWarning($"Function {functionName} is not found."); } } registeredFunctionNames.Clear(); } } public partial class ItemBase { protected virtual void FAPF_Swing(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringVector3Vector3 p = rtFuncAnim.GetParams(); Swing(p.str0, p.vec3_0, p.vec3_1); } } }