using Invector; using Invector.vCharacterController; using Invector.vCharacterController.vActions; using System.Collections; using System.Collections.Generic; // Required for List using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; using Sirenix.OdinInspector; using PixelCrushers.QuestMachine; // Required for Quest Machine using PixelCrushers.DialogueSystem; using TMPro; namespace Beyond { [vClassHeader("bTrigger Generic Action", false, iconName = "triggerIcon")] public class bTriggerGenericAction : vTriggerGenericAction { #region --- CONDITIONS --- [vEditorToolbar("Conditions", order = 0)] [LabelText("Dialogue Condition")] [Tooltip("Lua condition from Dialogue System")] [SerializeField] private Condition m_questCondition; [LabelText("Quest Requirements")] [InfoBox("The trigger will only activate if these Quest Machine states are met.")] [SerializeField] public List questRequirements = new List(); [Title("Item Checking")] public bool m_itemChecking; [ShowIf("m_itemChecking")] public int m_itemToCheckId; #endregion #region --- SETTINGS --- [vHelpBox("Disable Selected HUD OnValidate, and enable OnInvalidate. Script ActionTriggerEvent.cs")] public bool disableHUD = true; public TriggerDescriptor.TriggerType triggerType = TriggerDescriptor.TriggerType.Generic; public UnityEvent OnPlayerMatchTargetPosition; [vEditorToolbar("Animation", order = 2)] [SerializeField] public bool useFadeOnMatchingToTarget; [SerializeField] private AnimationCurve m_fadeInCurve; [SerializeField] private AnimationCurve m_fadeOutCurve; [SerializeField] private float m_fadeSpeed = 2f; [vEditorToolbar("Interaction", order = 4)] [SerializeField] private bool m_enableInteractionLegality; public Quest m_guilt; private bool m_faded; public bool Faded => m_faded; public float animationDelay = 0f; private TriggerDescriptor m_triggerDescriptor; #endregion #region --- LIFECYCLE --- private void OnEnable() { if (useFadeOnMatchingToTarget) { OnPressActionInput.AddListener(ToggleFade); OnPlayerMatchTargetPosition.AddListener(ToggleFade); if (FadeCanvasGroup.Instance) { FadeCanvasGroup.Instance.OnFadeInEnd.AddListener(OnFadeInEnd); FadeCanvasGroup.Instance.OnFadeOutEnd.AddListener(OnFadeOutEnd); } } } private void OnDisable() { if (useFadeOnMatchingToTarget) { OnPressActionInput.RemoveListener(ToggleFade); OnPlayerMatchTargetPosition.RemoveListener(ToggleFade); if (FadeCanvasGroup.Instance) { FadeCanvasGroup.Instance.OnFadeInEnd.RemoveListener(OnFadeInEnd); FadeCanvasGroup.Instance.OnFadeOutEnd.RemoveListener(OnFadeOutEnd); } } } protected override void Start() { base.Start(); m_triggerDescriptor = new TriggerDescriptor(gameObject, triggerType); OnValidate.AddListener(OnActionTriggerEnter); OnInvalidate.AddListener(OnActionTriggerExit); OnEndAnimation.AddListener(() => OnActionEndAnimation(gameObject)); } #endregion #region --- ACTION LOGIC --- public override IEnumerator OnPressActionDelay(GameObject obj) { // 1. Security Check: Re-validate conditions before executing // This prevents race conditions where the player pressed the button just as the quest state changed. if (!AreConditionsMet()) { yield break; } if (!m_itemChecking) { yield return base.OnPressActionDelay(obj); } else { if (Player.Instance.ItemManager.ContainItem(m_itemToCheckId)) { yield return base.OnPressActionDelay(obj); } else { var item = Player.Instance.ItemManager.itemListData.items.Find(x => x.id == m_itemToCheckId); string itemName = item != null ? item.name : "Item"; DialogueManager.BarkString($"{itemName} Required", Player.Instance.transform); } } } private void OnActionTriggerEnter(GameObject gameObject) { // 1. Check all conditions (Dialogue System + Quest Machine) if (!AreConditionsMet()) { return; } if (disableHUD) { ActionTriggerEvent.ActionTriggerEnter?.Invoke(m_triggerDescriptor); } if (triggerType == TriggerDescriptor.TriggerType.Dialogue) { Player.Instance.SetDialogueIntaractableButtonImage(); } } private void OnActionTriggerExit(GameObject gameObject) { if (disableHUD) { ActionTriggerEvent.ActionTriggerExit?.Invoke(m_triggerDescriptor); } if (triggerType == TriggerDescriptor.TriggerType.Dialogue) { Player.Instance.ResetIntaractableButtonImage(); } } #endregion #region --- HELPER METHODS --- private bool AreConditionsMet() { // 1. Check Dialogue System Condition if (!m_questCondition.IsTrue(null)) { return false; } // 2. Check Quest Machine Requirements if (questRequirements != null && questRequirements.Count > 0) { foreach (var req in questRequirements) { if (!req.IsMet()) return false; } } return true; } private void OnActionEndAnimation(GameObject gameObject) { if (disableHUD) { ActionTriggerEvent.ActionTriggerExit?.Invoke(m_triggerDescriptor); } if (triggerType == TriggerDescriptor.TriggerType.Dialogue) { Player.Instance.ResetIntaractableButtonImage(); } if (!m_enableInteractionLegality) { return; } if (m_guilt == null) { Debug.LogError("There is no guilt assigned to interactable game object: " + gameObject.name); return; } Player.Instance.PlayerConfessionController.AddGuilt(m_guilt); } private void ToggleFade() { if (FadeCanvasGroup.Instance == null) return; if (!m_faded) { m_faded = true; FadeCanvasGroup.Instance.FadeOut(1f / m_fadeSpeed); return; } FadeCanvasGroup.Instance.FadeIn(1f / m_fadeSpeed); } private void OnFadeInEnd() => m_faded = false; private void OnFadeOutEnd() => m_faded = true; #endregion } }