private void OnTriggerComm(Collider other, SkillTriggerStyle skillTriggerStyle) { if (other.tag == "Monster" && skillProperties != null && skillProperties.Length > 0) { for (int i = 0; i < skillProperties.Length; i++) { if (skillProperties[i].skillTriggerStyle == skillTriggerStyle) { skillProperties[i].TriggerEnter(other.GetComponent <Unit>()); } } } }
/// <summary> /// Perform a skill in response to some input trigger. This is the common method to which all input-driven skill plays funnel. /// </summary> /// <param name="actionType">The action you want to play. Note that "Skill1" may be overriden contextually depending on the target.</param> /// <param name="triggerStyle">What sort of input triggered this skill?</param> /// <param name="targetId">(optional) Pass in a specific networkID to target for this action</param> private void PerformSkill(ActionType actionType, SkillTriggerStyle triggerStyle, ulong targetId = 0) { Transform hitTransform = null; if (targetId != 0) { // if a targetId is given, try to find the object NetworkObject targetNetObj; if (NetworkSpawnManager.SpawnedObjects.TryGetValue(targetId, out targetNetObj)) { hitTransform = targetNetObj.transform; } } else { // otherwise try to find an object under the input position int numHits = 0; if (triggerStyle == SkillTriggerStyle.MouseClick) { var ray = m_MainCamera.ScreenPointToRay(Input.mousePosition); numHits = Physics.RaycastNonAlloc(ray, k_CachedHit, k_MouseInputRaycastDistance, k_ActionLayerMask); } int networkedHitIndex = -1; for (int i = 0; i < numHits; i++) { if (k_CachedHit[i].transform.GetComponent <NetworkObject>()) { networkedHitIndex = i; break; } } hitTransform = networkedHitIndex >= 0 ? k_CachedHit[networkedHitIndex].transform : null; } if (GetActionRequestForTarget(hitTransform, actionType, triggerStyle, out ActionRequestData playerAction)) { //Don't trigger our move logic for another 500ms. This protects us from moving just because we clicked on them to target them. m_LastSentMove = Time.time + k_TargetMoveTimeout; m_NetworkCharacter.RecvDoActionServerRPC(playerAction); } else if (actionType != ActionType.GeneralTarget) { // clicked on nothing... perform a "miss" attack on the spot they clicked on var data = new ActionRequestData(); PopulateSkillRequest(k_CachedHit[0].point, actionType, ref data); m_NetworkCharacter.RecvDoActionServerRPC(data); } }
/// <summary> /// Request an action be performed. This will occur on the next FixedUpdate. /// </summary> /// <param name="action">the action you'd like to perform. </param> /// <param name="triggerStyle">What input style triggered this action.</param> public void RequestAction(ActionType action, SkillTriggerStyle triggerStyle, ulong targetId = 0) { // do not populate an action request unless said action is valid if (action == ActionType.None) { return; } Assert.IsTrue(GameDataSource.Instance.ActionDataByType.ContainsKey(action), $"Action {action} must be part of ActionData dictionary!"); if (m_ActionRequestCount < m_ActionRequests.Length) { m_ActionRequests[m_ActionRequestCount].RequestedAction = action; m_ActionRequests[m_ActionRequestCount].TriggerStyle = triggerStyle; m_ActionRequests[m_ActionRequestCount].TargetId = targetId; m_ActionRequestCount++; } }
/// <summary> /// When you right-click on something you will want to do contextually different things. For example you might attack an enemy, /// but revive a friend. You might also decide to do nothing (e.g. right-clicking on a friend who hasn't FAINTED). /// </summary> /// <param name="hit">The Transform of the entity we clicked on, or null if none.</param> /// <param name="actionType">The Action to build for</param> /// <param name="triggerStyle">How did this skill play get triggered? Mouse, Keyboard, UI etc.</param> /// <param name="resultData">Out parameter that will be filled with the resulting action, if any.</param> /// <returns>true if we should play an action, false otherwise. </returns> private bool GetActionRequestForTarget(Transform hit, ActionType actionType, SkillTriggerStyle triggerStyle, out ActionRequestData resultData) { resultData = new ActionRequestData(); var targetNetObj = hit != null?hit.GetComponent <NetworkObject>() : null; //if we can't get our target from the submitted hit transform, get it from our stateful target in our NetworkCharacterState. if (!targetNetObj && actionType != ActionType.GeneralTarget) { ulong targetId = m_NetworkCharacter.TargetId.Value; NetworkSpawnManager.SpawnedObjects.TryGetValue(targetId, out targetNetObj); } //sanity check that this is indeed a valid target. if (targetNetObj == null || !ActionUtils.IsValidTarget(targetNetObj.NetworkObjectId)) { return(false); } var targetNetState = targetNetObj.GetComponent <NetworkCharacterState>(); if (targetNetState != null) { //Skill1 may be contextually overridden if it was generated from a mouse-click. if (actionType == CharacterData.Skill1 && triggerStyle == SkillTriggerStyle.MouseClick) { if (!targetNetState.IsNpc && targetNetState.NetworkLifeState.Value == LifeState.Fainted) { //right-clicked on a downed ally--change the skill play to Revive. actionType = ActionType.GeneralRevive; } } } // record our target in case this action uses that info (non-targeted attacks will ignore this) resultData.ActionTypeEnum = actionType; resultData.TargetIds = new ulong[] { targetNetObj.NetworkObjectId }; PopulateSkillRequest(targetNetObj.transform.position, actionType, ref resultData); return(true); }