using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using RPGCreationKit; using RPGCreationKit.CellsSystem; using RPGCreationKit.DialogueSystem; using UnityEngine.UI; using UnityEngine.EventSystems; using RPGCreationKit.AI; using XNode; namespace RPGCreationKit.Player { public class PlayerInteractor : PlayerMovements, IDialoguable { //[SerializeField] private PlayerInteractorUI interactorUI; [SerializeField] private LayerMask rayMask; [SerializeField] private Transform camT; public bool isInConversation; public bool isInteracting; public bool isReadingBook; public bool isPickingLock; public bool isLooting; public bool isCrafting; Ray ray; RaycastHit rayHit; [SerializeField] private Transform rayStartPoint; // Dialogue public IDialoguable speakingTo; [SerializeField] private float dialogueDistance = 2.5f; // The distance of which a dialogue is possible // Interact object public InteractiveObject_Behaviour interactiveObject; [SerializeField] private float interactiveObjectDistance = 2.5f; // The distance of which a dialogue is possible // Looting [HideInInspector] public LootingPoint objLooting; // If so, track the InteractiveObject [SerializeField] private float lootingPointDistance = 2.5f; // The distance to interact with an InteractiveObject // Crafting [HideInInspector] public CraftingPoint objCrafting; // If so, track the InteractiveObject [SerializeField] private float CraftingDistance = 2.5f; // Items [SerializeField] private float itemDistance = 2.5f; [SerializeField] private float doorDistance = 2.5f; private bool cameraLookNPC; Rigidbody itemRigidbody; private ItemInWorld dragItemScript; Vector3 dragDirection; [SerializeField] private float dragDistance = 2.5f; public float dragForce = 50f; public bool dragKeyBeingHeld; public bool isDragging; string cmdStr; public void INPUT_DragKey(InputAction.CallbackContext value) { if (value.started) dragKeyBeingHeld = true; else if (value.canceled) dragKeyBeingHeld = false; } public override void Start() { base.Start(); } public override void Update() { base.Update(); // DialogueFix if (isInConversation && !RckInput.isUsingGamepad && uiManager.allPlayerQuestions.Count > 0 && uiManager.playerQuestionsContainer.gameObject.activeInHierarchy) Cursor.lockState = CursorLockMode.None; if (isInCutsceneMode || !isLoaded || !IsControlledByPlayer()) { if (uiManager.Interact_text.isActiveAndEnabled) uiManager.Interact_text.gameObject.SetActive(false); return; } if (uiManager.Interact_text.isActiveAndEnabled) uiManager.Interact_text.gameObject.SetActive(false); cmdStr = RckInput.isUsingGamepad ? "(A)" : "E)"; Raycast(); } public override void FixedUpdate() { base.FixedUpdate(); ManageDraggable(); } public void Raycast() { ray = new Ray(camT.position, camT.forward); if(Physics.Raycast(ray, out rayHit, RCKSettings.INTERACTOR_RAYCAST_MAXDISTANCE, rayMask)) { if (!RckPlayer.instance.iscrouching) { if (rayHit.distance <= dialogueDistance) { CheckForIDialoguable(); } } else if (rayHit.distance <= lootingPointDistance) { CheckForLootingPoint(true); } if (rayHit.distance <= itemDistance) CheckForItemsInWorld(); if (rayHit.distance <= RCKSettings.PLAYER_DISTANCE_TO_DISPLAY_ENEMY_BAR) { CheckForIDamageable(); } else { // UnityEngine.Utility.WaitForSeconds(3.0f); @ Schaken -- Find another way to do this. uiManager.enemyHealthContainer.SetActive(false); } if (rayHit.distance <= interactiveObjectDistance) CheckForInteractiveObjects(); if (rayHit.distance <= lootingPointDistance) CheckForLootingPoint(false); if (rayHit.distance <= doorDistance) CheckForDoors(); if (rayHit.distance <= dragDistance) CheckForIDraggable(); if (rayHit.distance <= CraftingDistance) CheckForCrafting(); } } private void CheckForIDialoguable() { IDialoguable dialoguable = rayHit.transform.gameObject.GetComponent(); if(dialoguable != null && dialoguable.CanDialogue() && !isInConversation) { // Set the UI uiManager.Interact_text.gameObject.SetActive(true); uiManager.Interact_text.text = cmdStr+" Speak: " + dialoguable.GetDialoguableName(); if (input.actions.FindAction("Interact").triggered) { StartDialogue(dialoguable); } } } private void CheckForItemsInWorld() { if(rayHit.transform.CompareTag("RPG Creation Kit/ItemInWorld")) { // When we find one, we save this reference ItemInWorld obj = rayHit.transform.gameObject.GetComponent(); if (obj == null) return; if (obj.hasBeenTaken) return; uiManager.Interact_text.gameObject.SetActive(true); if (obj.Item is BookItem) { uiManager.Interact_text.text = cmdStr+" Read: " + obj.Item.ItemName; } else { string action = obj.Metadata.IsOwnedByNPC ? " Steal: " : " Take: "; if (obj.Amount == 1) uiManager.Interact_text.text = cmdStr + action + obj.Item.ItemName; else // E) Take item.name (Number) uiManager.Interact_text.text = cmdStr + action + obj.Item.ItemName + " (" + obj.Amount + ")"; } if (input.actions.FindAction("Interact").triggered) { if (obj.Item is BookItem) { // ReadBook if(!RckPlayer.instance.isReadingBook) { BookReaderManager.instance.ReadBook((BookItem)obj.Item, true, obj); } } else { TakeItemInWorld(obj); } } } } public void TakeItemInWorld(ItemInWorld _item) { _item.hasBeenTaken = true; inventory.AddItem(_item.Item, _item.Metadata, _item.Amount); // We trigger activators if (_item.events.EvaluateConditions()) { QuestManager.instance.QuestDealerActivator(_item.events.questDealers); QuestManager.instance.QuestUpdaterActivator(_item.events.questUpdaters); ConsequenceManager.instance.ConsequencesActivator(gameObject, _item.events.consequences); } // Play sound if (_item.Item.sOnPickUp) GameAudioManager.instance.PlayOneShot(AudioSources.GeneralSounds, _item.Item.sOnPickUp); // If It's NOT created item, save the state if(!_item.isCreatedItem) _item.SaveOnFile(true); else { // Otherwise, remove it from the dictionary _item.DeleteCreatedRecord(); } // Steal if (_item.Metadata.IsOwnedByNPC) { // Aggro nearby NPC's since you stole something // TODO: Optomize this, Just going over everything could become an issue when theres hundreds of NPC's // maybe use factions? getowner() - getfaction() - ifisinfaction,then... ? foreach (var activeCell in CellInformation.activeCells) { foreach (var AI in activeCell.Value.aiInWorld) { // if is in faction... AI.Value.TryEngageWithPlayer(); } } } Destroy(_item.gameObject); } private void CheckForIDamageable() { IDamageable damageable = rayHit.transform.gameObject.GetComponent(); if (damageable != null && damageable.IsAlive() && !damageable.IsUnconscious()) { if (damageable.ShouldDisplayHealthIfHostile() && (damageable.IsHostile() || damageable.IsHostileAgainstPC())) { uiManager.enemyHealthSlider.maxValue = damageable.GetMaxHP(); uiManager.enemyHealthSlider.value = damageable.GetCurrentHP(); uiManager.enemyName.text = damageable.GetEntityName(); uiManager.enemyHealthContainer.SetActive(true); } else uiManager.enemyHealthContainer.SetActive(false); } else uiManager.enemyHealthContainer.SetActive(false); } /// /// Check with Rays if we're near InteractiveObjects /// private void CheckForInteractiveObjects() { // When we find one, we save this reference InteractiveObject_Behaviour obj = rayHit.transform.gameObject.GetComponent(); if (obj == null ||obj.interactiveObj == null) return; // If the NPC is interactable (not dead and not hostile and we're not yet in a conversation with him) if (obj.canInteract && !isInteracting) { // Set the UI uiManager.Interact_text.gameObject.SetActive(true); uiManager.Interact_text.text = cmdStr+" " + obj.interactiveObj.Action + ": " + obj.interactiveObj.Name; // Check for Key to speak with him if (input.actions.FindAction("Interact").triggered) InteractWithObject(obj); } else uiManager.Interact_text.gameObject.SetActive(false); } /// /// Called when we select to interact with an Object /// private void InteractWithObject(InteractiveObject_Behaviour obj) { input.SwitchCurrentActionMap("InteractUI"); // Flag that we're interacting isInteracting = true; // If we can choose between multiple options if (obj.interactiveObj.InteractiveOptions.Length > 1) { // Disable player controls RckPlayer.instance.EnableDisableControls(false); // Set UI uiManager.interactiveObjectUIContainer.SetActive(true); uiManager.interactiveObjectName.text = obj.interactiveObj.Name; uiManager.interactiveObjectDescription.text = obj.interactiveObj.Description; // Instantiate InteractiveOptionsUI if (obj.interactiveObj.InteractiveOptions.Length > 0) { for (int i = 0; i < obj.interactiveObj.InteractiveOptions.Length; i++) { GameObject newOption = Instantiate(uiManager.interactiveOptionUIPrefab, uiManager.interactiveOptionContent); newOption.GetComponent().Init(obj, obj.interactiveObj, obj.interactiveObj.InteractiveOptions[i]); if (i == 0 && RckInput.isUsingGamepad) newOption.GetComponent().Select(); } } // Otherwise if we have only one option } else if (obj.interactiveObj.InteractiveOptions.Length == 1) { // We just trigger the events DoInteractiveAction(obj, obj.interactiveObj.InteractiveOptions[0]); } } /// /// Called by InteractiveObject UI Buttons, perform interactive actions /// /// /// public void DoInteractiveAction(InteractiveObject_Behaviour obj, InteractiveOptions option) { // We initialize the array element int arrayElement = -1; // We find at what index are the Events of the selected 'option' for (int i = 0; i < obj.interactiveObj.InteractiveOptions.Length; i++) { if (option == obj.interactiveObj.InteractiveOptions[i]) { // We save it arrayElement = i; break; } } // We trigger activators if (obj.events[arrayElement].EvaluateConditions()) { QuestManager.instance.QuestDealerActivator(obj.events[arrayElement].questDealers); QuestManager.instance.QuestUpdaterActivator(obj.events[arrayElement].questUpdaters); ConsequenceManager.instance.ConsequencesActivator(gameObject, obj.events[arrayElement].consequences); } // Trigger the Result Script if (!string.IsNullOrEmpty(obj.resultScripts[arrayElement])) RCKFunctions.ExecuteScript(obj.resultScripts[arrayElement]); // Enable player controls EnableDisableControls(true); uiManager.interactiveObjectUIContainer.SetActive(false); // Remove all the previous instantiated options foreach (Transform t in uiManager.interactiveOptionContent) Destroy(t.gameObject); StartCoroutine(StopInteractingFixed()); input.SwitchCurrentActionMap("Player"); } IEnumerator StopInteractingFixed() { yield return new WaitForEndOfFrame(); isInteracting = false; } private void CheckForLootingPoint(bool isPickPocket) { if (isPickPocket == false) { if (rayHit.transform.CompareTag("RPG Creation Kit/Looting Point")) { // When we find one, we save this reference LootingPoint obj = rayHit.collider.transform.gameObject.GetComponent(); // Set the UI if (!isLooting) { uiManager.Interact_text.gameObject.SetActive(true); if (obj.inventory.Items.Count > 0) { if (obj.locked) { uiManager.Interact_text.text = cmdStr+" Search: " + obj.pointName + " (Locked)"; } else { uiManager.Interact_text.text = cmdStr+" Search: " + obj.pointName; } } else { if (obj.locked) { uiManager.Interact_text.text = cmdStr+" Search: " + obj.pointName + " (Empty) (Locked)"; } else { uiManager.Interact_text.text = cmdStr+" Search: " + obj.pointName + " (Empty)"; } } } // Check for Key to speak with him if (input.actions.FindAction("Interact").triggered) { if (obj.locked) { if (obj.key != null && Inventory.PlayerInventory.GetItemCount(obj.key.ItemID) > 0) { if (obj.onLocked != null) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.onLocked); } else { Debug.Log("SCHAKEN - You need a UNLOCKING sound!!!"); } StartCoroutine(UnlockThenOpen(obj)); // Added a delay for locking sound and realism } else { // We don't have the key, alert message the player AlertMessage.instance.InitAlertMessage("You don't have the key", 3f); if (obj.onUnlocked != null) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.onUnlocked); } } } else { OpenLootPoint(obj); } } } } else { // When we find one, we save this reference RckAI obj = rayHit.transform.gameObject.GetComponent(); if (obj != null) { // Set the UI if (!isLooting) { uiManager.Interact_text.gameObject.SetActive(true); uiManager.Interact_text.text = cmdStr + " Pickpocket: " + obj.GetEntityName(); } // Check for Key to speak with him if (input.actions.FindAction("Interact").triggered) { OpenLootPoint(obj); } } // Check for Key to speak with him } } IEnumerator UnlockThenOpen(LootingPoint obj) { yield return new WaitForSeconds(0.7f); obj.UnlockContainer(); OpenLootPoint(obj); } private void OpenLootPoint(RckAI _AI) { isLooting = true; LootingInventoryUI.instance.OpenLootingPanel(_AI.gameObject.GetComponentInChildren(), true, true, _AI); } private void OpenLootPoint(LootingPoint _point) { isLooting = true; objLooting = _point; if (_point.openSound) GameAudioManager.instance.PlayOneShot(AudioSources.GeneralSounds, _point.openSound); if (_point.anim != null) { _point.OpenCloseContainer(); StartCoroutine(DelayOpenLootingPoint(_point)); } else { LootingInventoryUI.instance.OpenLootingPanel(_point); } } IEnumerator DelayOpenLootingPoint(LootingPoint _point) { yield return new WaitForSeconds(0.7f); LootingInventoryUI.instance.OpenLootingPanel(_point); } private void CheckForDoors() { if(rayHit.transform.CompareTag("RPG Creation Kit/Door") || (rayHit.transform.CompareTag("RPG Creation Kit/Cave"))) { // When we find one, we save this reference Door obj = rayHit.transform.gameObject.GetComponent(); // Set the UI uiManager.Interact_text.gameObject.SetActive(true); if (obj.teleports && rayHit.transform.CompareTag("RPG Creation Kit/Door")) { uiManager.Interact_text.text = cmdStr+" Door to: " + obj.toCell.cellName; } else if (obj.teleports && rayHit.transform.CompareTag("RPG Creation Kit/Cave")) { uiManager.Interact_text.text = cmdStr+" Enter: " + obj.toCell.cellName; } else { if (obj.isOpened) { uiManager.Interact_text.text = cmdStr+" Close: Door"; } else { if (obj.locked) { bool HasPick = false; if (obj.key != null && Inventory.PlayerInventory.GetItemCount(obj.key.ItemID) <= 0) { if (Inventory.PlayerInventory.HasItem(LockpickingManager.instance.LockpickItemID)) { uiManager.Interact_text.text = cmdStr + " Lockpick: Door"; HasPick = true; } } if (HasPick == false) { uiManager.Interact_text.text = cmdStr+" Open: Door (Locked)"; } } else { uiManager.Interact_text.text = cmdStr+" Open: Door"; } } } // Check for opening door if (input.actions.FindAction("Interact").triggered && !WorldManager.instance.isLoading) { if (obj.locked) { // We have the key if (obj.key != null && Inventory.PlayerInventory.GetItemCount(obj.key.ItemID) > 0) { if (obj.onDoorOpenLocked != null) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.onDoorOpenUnlocked); } StartCoroutine(UnlockDoorThenOpen(obj));// Just delaying for realism and sounds //obj.UnlockDoor(); //OpenDoor(obj); } else { if (obj.key != null && Inventory.PlayerInventory.HasItem(LockpickingManager.instance.LockpickItemID)) { if (!RckPlayer.instance.isPickingLock) { LockpickingManager.instance.StartPicking(obj, true); } } else { // We don't have the key, alert message the player AlertMessage.instance.InitAlertMessage("You don't have the key to open this door", 3f); if (obj.onDoorOpenLocked != null) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.onDoorOpenLocked); } } } } else { if (obj.onDoorOpen != null) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.onDoorOpen); } OpenDoor(obj); } } } } IEnumerator UnlockDoorThenOpen(Door obj) { yield return new WaitForSeconds(0.7f); obj.UnlockDoor(); OpenDoor(obj); } private void OpenDoor(Door obj) { if (obj.onDoorOpen) { GameAudioManager.instance.PlayOneShot(AudioSources.GeneralSounds, obj.onDoorOpen); } else { Debug.Log("SCHAKEN - Add sounds here!"); } if (obj.teleports) { FreezeAndDisableControl(); WorldManager.instance.LoadCell(obj.toCell, UnityEngine.Random.Range(int.MinValue, int.MaxValue), false, obj, null, true); } else { // Open door by rotating pivot/playing animation obj.OpenCloseDoor(); } } private void CheckForCrafting() { if (rayHit.transform.CompareTag("RPG Creation Kit/Crafting")) { // When we find one, we save this reference CraftingPoint obj = rayHit.collider.transform.gameObject.GetComponent(); // Set the UI if (!isCrafting) { uiManager.Interact_text.gameObject.SetActive(true); uiManager.Interact_text.text = cmdStr+" Use: " + obj.pointName; } // Check for Key to speak with him if (input.actions.FindAction("Interact").triggered) { GameAudioManager.instance.PlayOneShot(AudioSources.PlayerFPS, obj.Using); AlchemyManager.instance.OpenAlchemyPanel(); } } } public void StartDialogue(IDialoguable dialoguable) { speakingTo = dialoguable; dialoguable.SetSpeakerIndex(0); // Always 0 here because the player is talking to someone dialoguable.OnDialogueStarts(this.gameObject); DialogueLogic(dialoguable.GetCurrentDialogueGraph()); } void DialogueLogic(DialogueGraph dialogue) { if (dialogue != null) { StartCoroutine(ExecuteNode(dialogue.GetEntryNode())); } } public bool isPlainLineDialogue = false; IEnumerator ExecuteNode(XNode.Node _node) { // Trigger Events and Script DialogueNode globalNode = (DialogueNode)_node; RCKFunctions.ExecuteEvents(globalNode.events); if (!string.IsNullOrEmpty(globalNode.resultScript)) RCKFunctions.ExecuteScript(globalNode.resultScript); if (_node is EntryNode) { EntryNode thisNode = (EntryNode)_node; StartCoroutine(ExecuteNode(thisNode.GetOutputPort("firstNode").Connection.node)); } else if (_node is ConditionsNode) { ConditionsNode thisNode = (ConditionsNode)_node; bool conditionsResult = RCKFunctions.VerifyConditions(thisNode.conditions); if (conditionsResult) StartCoroutine(ExecuteNode(thisNode.GetOutputPort("resultTrue").Connection.node)); else StartCoroutine(ExecuteNode(thisNode.GetOutputPort("resultFalse").Connection.node)); } else if (_node is NPCDialogueLineNode) { NPCDialogueLineNode thisNode = (NPCDialogueLineNode)_node; // Set the Dialoguable state speakingTo.OnSpeakALine(thisNode); if (!thisNode.plainLine) { input.SwitchCurrentActionMap("DialogueUI"); // Flag that we're in conversation isInConversation = true; // Disable player controls mouseLook.SetLookAtTarget(speakingTo.GetEntityLookAtPos()); EnableDisableControls(false); // Set the UI properly uiManager.heardDialogues.gameObject.SetActive(false); uiManager.playerQuestionsContainer.SetActive(false); uiManager.compassGameObject.SetActive(false); uiManager.crosshairGameObject.SetActive(false); // Npc Name uiManager.npc_Name.text = speakingTo.GetDialoguableName(); uiManager.npc_Name.gameObject.SetActive(true); // Npc Line uiManager.npc_Line.text = thisNode.line; uiManager.npc_Line.gameObject.SetActive(true); // Whole Dialogue UI uiManager.dialogueContainer.SetActive(true); cameraLookNPC = true; } else { // Flag that we're in conversation isInConversation = true; isPlainLineDialogue = true; uiManager.heardDialogues.text = thisNode.line; uiManager.heardDialogues.gameObject.SetActive(true); } // - End UI // - End Updaters // Play the audio if exists if (thisNode.audioClip != null) { speakingTo.PlayAudioClip(thisNode.audioClip); } // Play talking animation if choosen if(!string.IsNullOrEmpty(thisNode.dialogueAnimationStr)) { speakingTo.GetAnimator().CrossFade(thisNode.dialogueAnimationStr, .1f); } // Check for the timing of the line bool outOfTime = false; float startTime = Time.time; // To wait until the line ends while (!outOfTime) { // If we press X button if (input.actions.FindAction("SkipDialogue").triggered && Time.time - startTime >= 0.5f && !thisNode.plainLine || WorldManager.instance.isLoading) outOfTime = true; // If the time expires if (!thisNode.useLenghtOfClip) { if (Time.time - startTime >= thisNode.lineTime) outOfTime = true; } else { if (Time.time - startTime >= thisNode.audioClip.length) outOfTime = true; } yield return null; } // Line has finished and player was teleported if (WorldManager.instance.isLoading) { // Reset the player status isInConversation = false; isPlainLineDialogue = false; // Disable the UI if (!thisNode.plainLine) { uiManager.dialogueContainer.SetActive(false); uiManager.compassGameObject.SetActive(true); uiManager.crosshairGameObject.SetActive(true); EnableDisableControls(false); cameraLookNPC = false; } else { uiManager.heardDialogues.gameObject.SetActive(false); } // Destroy every previous question foreach (Transform t in uiManager.playerQuestionsContent) Destroy(t.gameObject); speakingTo = null; yield break; } // Stop the audio source if(speakingTo != null) speakingTo.StopAudio(); // Check what we have to do next switch (thisNode.afterLine) { case AfterLine.NPC_DialogueLine: // If we have to trigger another dialogue line, we just re-start this courutine with the new line StartCoroutine(ExecuteNode(thisNode.GetOutputPort("nextLine").Connection.node)); yield break; case AfterLine.PlayerQuestions: // Play listening animation if choosen if (!string.IsNullOrEmpty(thisNode.dialogueAnimationListeningStr)) { speakingTo.GetAnimator().CrossFade(thisNode.dialogueAnimationListeningStr, .1f); } if (thisNode.removePreviousQuestions) { foreach (Transform t in uiManager.playerQuestionsContent) Destroy(t.gameObject); } else if (thisNode.questionsToRemove.Length > 0) { List toDelete = new List(); foreach (Transform t in uiManager.playerQuestionsContent) { for (int i = 0; i < thisNode.questionsToRemove.Length; i++) { if (t.GetComponent().question.qID == thisNode.questionsToRemove[i]) toDelete.Add(t.gameObject); } } foreach (GameObject go in toDelete) { Destroy(go); } } List questions = new List(); // Check if we have to add some new question for (int i = 0; i < thisNode.playerQuestions.Count; i++) { int tempPosition = thisNode.playerQuestions[i].Position; // In case, add them GameObject newQuestion = Instantiate(uiManager.playerQuestionPrefab, uiManager.playerQuestionsContent); if (tempPosition == 0) tempPosition = i; questions.Add(newQuestion.GetComponent()); newQuestion.GetComponent() .Init(thisNode.playerQuestions[i], speakingTo, (DialogueNode)thisNode.GetOutputPort("playerQuestions " + i).Connection.node, thisNode.playerQuestions[i].Question, thisNode.playerQuestions[i].DeleteAfterAnswer, tempPosition); newQuestion.GetComponent().SetSiblingIndex(tempPosition); } // Set the UI to allow the player to ask questions uiManager.npc_Line.gameObject.SetActive(false); uiManager.playerQuestionsContainer.SetActive(true); // Reset the scroll bar of the PlayerQuestionScrollView if (uiManager.playerQuestionsContainer.GetComponentInChildren() != null) uiManager.playerQuestionsContainer.GetComponentInChildren().value = 1f; speakingTo.OnFinishedSpeakingALine(); yield return new WaitForEndOfFrame(); uiManager.ReorderQuestions(); uiManager.PreventUnselectedQuestionWithGamepad(); yield return new WaitForEndOfFrame(); uiManager.PreventUnselectedQuestionWithGamepad(); yield break; case AfterLine.EndDialogue: speakingTo.OnDialogueEnds(this.gameObject); // Reset the player status isInConversation = false; // Disable the UI if (!thisNode.plainLine) { uiManager.dialogueContainer.SetActive(false); uiManager.compassGameObject.SetActive(true); uiManager.crosshairGameObject.SetActive(true); EnableDisableControls(true); cameraLookNPC = false; EndDialogue(); } else { isPlainLineDialogue = false; uiManager.heardDialogues.gameObject.SetActive(false); } // Destroy every previous question foreach (Transform t in uiManager.playerQuestionsContent) Destroy(t.gameObject); // Reset speaking to animator if(speakingTo != null && speakingTo.GetAnimator() != null) speakingTo.GetAnimator().SetTrigger("CancelDialogueAnimation"); speakingTo = null; yield break; case AfterLine.Continue: StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); break; } } else if (_node is PlayerQuestionsNode) { PlayerQuestionsNode thisNode = (PlayerQuestionsNode)_node; // Play listening animation if choosen if (!string.IsNullOrEmpty(thisNode.dialogueAnimationListeningStr)) { speakingTo.GetAnimator().CrossFade(thisNode.dialogueAnimationListeningStr, .1f); } else { // Reset speaking to animator speakingTo.GetAnimator().SetTrigger("CancelDialogueAnimation"); } // Flag that we're in conversation isInConversation = true; input.SwitchCurrentActionMap("DialogueUI"); mouseLook.SetLookAtTarget(speakingTo.GetEntityLookAtPos()); // Disable player controls EnableDisableControls(false); // Set the UI properly uiManager.heardDialogues.gameObject.SetActive(false); uiManager.playerQuestionsContainer.SetActive(false); uiManager.compassGameObject.SetActive(false); uiManager.crosshairGameObject.SetActive(false); // Npc Name uiManager.npc_Name.text = speakingTo.GetDialoguableName(); uiManager.npc_Name.gameObject.SetActive(true); // Whole Dialogue UI uiManager.dialogueContainer.SetActive(true); cameraLookNPC = true; if (thisNode.removePreviousQuestions) { foreach (Transform t in uiManager.playerQuestionsContent) Destroy(t.gameObject); } else if (thisNode.questionsToRemove.Length > 0) { List toDelete = new List(); foreach (Transform t in uiManager.playerQuestionsContent) { for (int i = 0; i < thisNode.questionsToRemove.Length; i++) { if (t.GetComponent().question.qID == thisNode.questionsToRemove[i]) toDelete.Add(t.gameObject); } } foreach (GameObject go in toDelete) { Destroy(go); } } List questions = new List(); // Check if we have to add some new question for (int i = 0; i < thisNode.playerQuestions.Count; i++) { int tempPosition = thisNode.playerQuestions[i].Position; // In case, add them GameObject newQuestion = Instantiate(uiManager.playerQuestionPrefab, uiManager.playerQuestionsContent); if (tempPosition == 0) tempPosition = i; questions.Add(newQuestion.GetComponent()); newQuestion.GetComponent() .Init(thisNode.playerQuestions[i], speakingTo, (DialogueNode)thisNode.GetOutputPort("playerQuestions " + i).Connection.node, thisNode.playerQuestions[i].Question, thisNode.playerQuestions[i].DeleteAfterAnswer, tempPosition); newQuestion.GetComponent().SetSiblingIndex(tempPosition); } // Set the UI to allow the player to ask questions uiManager.npc_Line.gameObject.SetActive(false); uiManager.playerQuestionsContainer.SetActive(true); // Reset the scroll bar of the PlayerQuestionScrollView if (uiManager.playerQuestionsContainer.GetComponentInChildren() != null) uiManager.playerQuestionsContainer.GetComponentInChildren().value = 1f; speakingTo.OnFinishedSpeakingALine(); yield return new WaitForEndOfFrame(); uiManager.ReorderQuestions(); uiManager.PreventUnselectedQuestionWithGamepad(); yield return new WaitForEndOfFrame(); uiManager.PreventUnselectedQuestionWithGamepad(); } else if (_node is ChangeDialogueNode) { ChangeDialogueNode thisNode = (ChangeDialogueNode)_node; if (thisNode.onNPCWhosSpeaking) { speakingTo.ChangeDialogueGraph(thisNode.newDialogue); if (thisNode.startDialogueImmediatly) { var npcSpeakingSaved = speakingTo; EndDialogue(); StartDialogue(npcSpeakingSaved); } else StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); } else { RCKFunctions.ChangeDialogueToRckAI(thisNode.npcRef, thisNode.newDialogue.ID); StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); } yield break; } else if (_node is ChangeStateNode) { ChangeStateNode thisNode = (ChangeStateNode)_node; switch (thisNode.stateChange) { case ChangeStateNode.DialogueStateChange.Trade: if (thisNode.toCurrentNPC) RCKFunctions.StartTrading(speakingTo.GetEntityGameObject().GetComponent()); // TODO find npc and do stuff break; case ChangeStateNode.DialogueStateChange.Loot: // TODO find looting point and do stuff break; case ChangeStateNode.DialogueStateChange.Teleport: //WorldStreaming.manager.Teleport(thisNode.coordinates); break; case ChangeStateNode.DialogueStateChange.ChangeCell: //WorldStreaming.manager.StartLoadingInterior(thisNode.cell.worldspace, thisNode.cell, null, thisNode.coordinates); break; case ChangeStateNode.DialogueStateChange.SpeakToNPC: // TODO Find the NPC and do stuff break; } if (thisNode.interruptsDialogue) EndDialogue(); StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); } else if (_node is RandomNode) { RandomNode thisNode = (RandomNode)_node; StartCoroutine(ExecuteNode(thisNode.PickRandomExit())); } else if(_node is Dialogue_AISetFieldNode) { Dialogue_AISetFieldNode thisNode = (Dialogue_AISetFieldNode)_node; thisNode.OnStart(); if(thisNode.speakerID == 0) // Its to the NPC we're talking to { var component = speakingTo.GetEntityGameObject().GetComponent(); // it's always the speaker with id 0 because it's player to ai dialogue if (component == null) { Debug.Log("Dialogue Node : Tried to SetField but the given Component: \"RckAI\" was not found on Speaker Index 0. Node fails."); yield break; } var field = component.GetType().GetField(thisNode.FieldToSet); field.SetValue(component, thisNode.storedValue.GetValue()); } StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); } else if(_node is Dialogue_AIInvokeNode) { Dialogue_AIInvokeNode thisNode = (Dialogue_AIInvokeNode)_node; NodesHelper.AIInvokeCall(thisNode.MethodToCall, speakingTo.GetEntityGameObject().GetComponent(), thisNode.parameters); StartCoroutine(ExecuteNode(thisNode.GetOutputPort("output").Connection.node)); } else if (_node is EndNode) { EndNode thisNode = (EndNode)_node; // Reset speaking to animator speakingTo.GetAnimator().SetTrigger("CancelDialogueAnimation"); speakingTo.OnDialogueEnds(this.gameObject); EndDialogue(); yield break; } yield return null; } void EndDialogue() { //speakingTo.OnDialogueEnds(this.gameObject); mouseLook.ApplyCurrentRotation(); mouseLook.ClearLookAt(); // Reset the player status isInConversation = false; isPlainLineDialogue = false; // Disable the UI uiManager.dialogueContainer.SetActive(false); uiManager.compassGameObject.SetActive(true); uiManager.crosshairGameObject.SetActive(true); EnableDisableControls(true); cameraLookNPC = false; uiManager.heardDialogues.gameObject.SetActive(false); // Destroy every previous question foreach (Transform t in uiManager.playerQuestionsContent) Destroy(t.gameObject); speakingTo = null; // Input scheme input.SwitchCurrentActionMap("Player"); } public static int SortByPosition(PlayerQuestionUI p1, PlayerQuestionUI p2) { return p1.position.CompareTo(p2.position); } /// /// Method called from PlayerQuestionUI to ask a question /// /// The NPC with we are speaking with /// His response to our question /// Destroy the question after answer? /// The question to destroy public void AskQuestion(IDialoguable _dialoguable, XNode.Node response, bool DestroyQuestion, GameObject theQuestion = null, bool isNpcToNpcDialogue = false, IDialoguable[] _dialoguables = null) { if (!isNpcToNpcDialogue) StartCoroutine(ExecuteNode(response)); else { isInConversation = false; speakingTo = null; _dialoguable.ExecuteDialogueNode(response, _dialoguables); } // DestroyQuestion = What we said in the ScriptableObject // Destroy after .05f seconds to not have bad effects in the PlayerQuestionUI (Question disappear before the panel's fadeout) if (DestroyQuestion) Destroy(theQuestion, .05f); } private void CheckForIDraggable() { IDraggable draggable = rayHit.transform.gameObject.GetComponent(); if (draggable != null && !isDragging) { if(!isDragging && dragKeyBeingHeld) { itemRigidbody = draggable.GetGameObject().GetComponent(); dragItemScript = draggable.GetGameObject().GetComponent(); if (itemRigidbody != null) { draggable.OnBeingDragged(); BeginDragItem(); } } } } private void BeginDragItem() { //if (ItemUnderFeet()) // return; itemRigidbody.angularVelocity = Vector3.zero; itemRigidbody.velocity = Vector3.zero; itemRigidbody.useGravity = false; isDragging = true; } public float powerVector = 5f; public float droppingDistance = 3f; public float moveThresold = .1f; public float stopThresold = .1f; private void ManageDraggable() { if (isDragging && itemRigidbody != null) { if (!dragKeyBeingHeld) StopDragging(); else if(itemRigidbody != null && dragKeyBeingHeld && dragItemScript.canBeDragged) { //if (ItemUnderFeet()) //{ // StopDragging(); // return; //} //itemRigidbody.position = Vector3.Lerp(itemRigidbody.position, mainCamera.transform.position + mainCamera.transform.forward * 1f, (dragForce * Time.deltaTime)); //itemRigidbody.MovePosition(Vector3.Lerp(itemRigidbody.transform.position, mainCamera.transform.position + mainCamera.transform.forward, Time.fixedDeltaTime * dragForce)); //Vector3 toCameraCenterVector = (mainCamera.transform.position + mainCamera.transform.forward) - itemRigidbody.transform.position; //toCameraCenterVector = toCameraCenterVector.normalized; //itemRigidbody.AddForce(Vector3.MoveTowards(itemRigidbody.transform.position, toCameraCenterVector, dragForce * Time.deltaTime) * powerVector, ForceMode.VelocityChange); //itemRigidbody.velocity = Vector3.zero; Vector3 toCameraCenterVector = (mainCamera.transform.position + mainCamera.transform.forward) - itemRigidbody.transform.position; toCameraCenterVector = toCameraCenterVector.normalized * .25f; var dst = Vector3.Distance(itemRigidbody.transform.position, mainCamera.transform.position + mainCamera.transform.forward); if (dst > moveThresold) dragForce = 1000f; else dragForce = 150f; if(dst > stopThresold) itemRigidbody.AddForce(toCameraCenterVector * (dragForce * Time.fixedDeltaTime), ForceMode.VelocityChange); itemRigidbody.velocity = Vector3.zero; Debug.DrawRay(itemRigidbody.transform.position, toCameraCenterVector, Color.red); if (Mathf.Abs(mouseLook.x) > 2f || Mathf.Abs(mouseLook.y) > 2f) { dragDirection = new Vector3(mouseLook.x, mouseLook.y, 0); dragDirection = transform.TransformDirection(dragDirection.normalized * (dragForce * Time.fixedDeltaTime)); } else dragDirection = Vector3.zero; if (Vector3.Distance(mainCamera.transform.position + mainCamera.transform.forward, itemRigidbody.transform.position) > droppingDistance) StopDragging(); } } else { isDragging = false; } } public void DisplayHeardLine(string _line, float _time) { uiManager.heardDialogues.text = _line; uiManager.heardDialogues.gameObject.SetActive(true); Invoke("HideHeardLine", _time); } public void HideHeardLine() { uiManager.heardDialogues.gameObject.SetActive(false); } /// /// Called when we stop to drag the item, reset its state to default world item /// public void StopDragging() { itemRigidbody.useGravity = true; itemRigidbody.velocity = Vector3.zero; itemRigidbody = null; isDragging = false; } public void SetSpeakerIndex(int index) { throw new System.NotImplementedException(); } public void DialogueLogic(IDialoguable[] entities, DialogueGraph dialogue) { throw new System.NotImplementedException(); } public IEnumerator ExecuteDialogueNode(Node _node, IDialoguable[] _entities) { throw new System.NotImplementedException(); } public void SpeakToEntity(IDialoguable target) { throw new System.NotImplementedException(); } public void ChangeDialogueGraph(DialogueGraph _newDialogueGraph) { throw new System.NotImplementedException(); } public bool CanDialogue() { return (isAlive && !isInConversation && !isInteracting && !isLooting && isLoaded); } public string GetDialoguableName() { throw new System.NotImplementedException(); } public void OnDialogueStarts(GameObject target) { throw new System.NotImplementedException(); } public void OnDialogueEnds(GameObject target) { throw new System.NotImplementedException(); } public DialogueGraph GetCurrentDialogueGraph() { throw new System.NotImplementedException(); } public void OnSpeakALine(NPCDialogueLineNode currentNode) { throw new System.NotImplementedException(); } public void OnFinishedSpeakingALine() { throw new System.NotImplementedException(); } public Transform GetEntityLookAtPos() { throw new System.NotImplementedException(); } public GameObject GetEntityGameObject() { return gameObject; } public void PlayAudioClip(AudioClip clip) { throw new System.NotImplementedException(); } public void StopAudio() { throw new System.NotImplementedException(); } public bool IsTalking() { throw new System.NotImplementedException(); } Animator IDialoguable.GetAnimator() { throw new System.NotImplementedException(); } int IDialoguable.GetSpeakerIndex() { throw new System.NotImplementedException(); } void IDialoguable.ForceToStopDialogue() { throw new System.NotImplementedException(); } } }