using UnityEngine; using System.Collections.Generic; using Sirenix.OdinInspector; using PixelCrushers.DialogueSystem; using PixelCrushers.QuestMachine; // Required using Invector.vCharacterController.vActions; using UnityEngine.Events; namespace Beyond { [AddComponentMenu("Beyond/Quests/Generic Quest Trigger")] [RequireComponent(typeof(bTriggerGenericAction))] public class GenericQuestTrigger : MonoBehaviour { #region --- ODIN-POWERED INSPECTOR --- [Title("Invector Trigger Link")] [InfoBox("Links into bTriggerGenericAction to add quest/dialogue functionality.")] [Required("A bTriggerGenericAction component is required.")] [OnInspectorInit("FindTriggerReference")] public bTriggerGenericAction invectorTrigger; [Title("Quest and Dialogue Actions")] [ListDrawerSettings(Expanded = true, DraggableItems = true, NumberOfItemsPerPage = 10)] public List actions = new List(); #endregion private GameObject _lastInteractor; private void FindTriggerReference() { if (invectorTrigger == null) invectorTrigger = GetComponent(); } #region --- CORE LOGIC --- private void Start() { if (invectorTrigger == null) { this.enabled = false; return; } // Subscribe to Invector Events invectorTrigger.OnPressActionInput.AddListener(() => HandleEvent(TriggerEventType.OnPressActionInput, _lastInteractor)); invectorTrigger.OnStartAnimation.AddListener(() => HandleEvent(TriggerEventType.OnStartAnimation, _lastInteractor)); invectorTrigger.OnEndAnimation.AddListener(() => HandleEvent(TriggerEventType.OnEndAnimation, _lastInteractor)); invectorTrigger.OnPlayerEnter.AddListener(HandlePlayerEnter); invectorTrigger.OnPlayerExit.AddListener(HandlePlayerExit); invectorTrigger.OnValidate.AddListener((interactor) => HandleEvent(TriggerEventType.OnValidate, interactor)); invectorTrigger.OnInvalidate.AddListener((interactor) => HandleEvent(TriggerEventType.OnInvalidate, interactor)); if (DialogueManager.instance != null) DialogueManager.instance.conversationEnded += OnConversationEnded; } private void OnDisable() { if (DialogueManager.instance != null) DialogueManager.instance.conversationEnded -= OnConversationEnded; if (invectorTrigger != null) { invectorTrigger.OnPressActionInput.RemoveAllListeners(); invectorTrigger.OnStartAnimation.RemoveAllListeners(); invectorTrigger.OnEndAnimation.RemoveAllListeners(); invectorTrigger.OnPlayerEnter.RemoveListener(HandlePlayerEnter); invectorTrigger.OnPlayerExit.RemoveListener(HandlePlayerExit); } } private void HandlePlayerEnter(GameObject interactor) { _lastInteractor = interactor; HandleEvent(TriggerEventType.OnPlayerEnter, interactor); } private void HandlePlayerExit(GameObject interactor) { HandleEvent(TriggerEventType.OnPlayerExit, interactor); _lastInteractor = null; } private void OnConversationEnded(Transform actor) { if (_lastInteractor != null && actor.gameObject == _lastInteractor) { HandleEvent(TriggerEventType.OnConversationEnd, actor.gameObject); } } private void HandleEvent(TriggerEventType eventType, GameObject interactor) { foreach (var action in actions) { if (action.triggerEvent == eventType) { // 1. Check Dialogue System (Lua) bool dsConditionMet = action.condition == null || action.condition.IsTrue(interactor?.transform); // 2. Check Quest Machine (Synchronous State Check) bool qmConditionMet = true; if (action.questRequirements != null && action.questRequirements.Count > 0) { foreach (var req in action.questRequirements) { if (!req.IsMet()) { qmConditionMet = false; break; } } } if (dsConditionMet && qmConditionMet) { PerformAction(action, interactor); } } } } private void PerformAction(TriggeredAction action, GameObject interactor) { var actorTransform = interactor?.transform; switch (action.actionType) { case ActionType.StartConversation: if (!string.IsNullOrEmpty(action.conversation)) { Transform conversant = action.conversant != null ? action.conversant : this.transform; DialogueManager.StartConversation(action.conversation, actorTransform, conversant); } break; case ActionType.ExecuteLua: if (!string.IsNullOrEmpty(action.luaCode)) Lua.Run(action.luaCode, true); break; case ActionType.SendQuestMachineMessage: if (!string.IsNullOrEmpty(action.questMachineMessage)) QuestMachineMessages.SendCompositeMessage(this, action.questMachineMessage); break; case ActionType.SetQuestState: if (!string.IsNullOrEmpty(action.questID)) QuestMachine.SetQuestState(action.questID, action.questState); break; case ActionType.SetQuestNodeState: if (!string.IsNullOrEmpty(action.questID) && !string.IsNullOrEmpty(action.questNodeID)) QuestMachine.SetQuestNodeState(action.questID, action.questNodeID, action.questNodeState); break; case ActionType.InvokeUnityEvent: action.onExecute?.Invoke(); break; } } #endregion } #region --- Definitions --- public enum TriggerEventType { OnPlayerEnter, OnPlayerExit, OnValidate, OnInvalidate, OnPressActionInput, OnStartAnimation, OnEndAnimation, OnConversationEnd } public enum ActionType { StartConversation, ExecuteLua, SendQuestMachineMessage, SetQuestState, SetQuestNodeState, InvokeUnityEvent } [System.Serializable] public class TriggeredAction { [HorizontalGroup("Top", 120)] [BoxGroup("Top/Trigger", showLabel: false)] [EnumToggleButtons, HideLabel] public TriggerEventType triggerEvent; [BoxGroup("Top/Action", showLabel: false)] [EnumToggleButtons, HideLabel] public ActionType actionType; [BoxGroup("Conditions")] [LabelText("Dialogue Condition")] [DrawWithUnity] public Condition condition; [BoxGroup("Conditions")] [LabelText("Quest Requirements")] [InfoBox("All requirements listed here must be met.")] public List questRequirements = new List(); [BoxGroup("Settings")] [ShowIf("actionType", ActionType.StartConversation)] [ConversationPopup(false)] [DrawWithUnity] public string conversation; [BoxGroup("Settings")] [ShowIf("actionType", ActionType.StartConversation)] public Transform conversant; [BoxGroup("Settings")] [ShowIf("actionType", ActionType.ExecuteLua)] [TextArea(2, 5)] public string luaCode; [BoxGroup("Settings")] [ShowIf("actionType", ActionType.SendQuestMachineMessage)] public string questMachineMessage; [BoxGroup("Settings")] [ShowIf("@this.actionType == ActionType.SetQuestState || this.actionType == ActionType.SetQuestNodeState")] public string questID; // --- AMBIGUITY FIXED: Explicitly using Quest Machine types --- [BoxGroup("Settings")] [ShowIf("actionType", ActionType.SetQuestState)] public PixelCrushers.QuestMachine.QuestState questState; [BoxGroup("Settings")] [ShowIf("actionType", ActionType.SetQuestNodeState)] public string questNodeID; // --- AMBIGUITY FIXED: Explicitly using Quest Machine types --- [BoxGroup("Settings")] [ShowIf("actionType", ActionType.SetQuestNodeState)] public PixelCrushers.QuestMachine.QuestNodeState questNodeState; [BoxGroup("Settings")] [ShowIf("actionType", ActionType.InvokeUnityEvent)] public UnityEvent onExecute; } #endregion }