improvements to magic attacks, full arena logic, improvements to NPCs fresnel rendering for targetting
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq; // Required for List.AddRange and ToArray
|
||||
using Invector.vCharacterController.AI.FSMBehaviour; // For vFSMBehaviourController
|
||||
using Beyond; // For GameStateManager and Player (ensure Player.cs is in this namespace or adjust)
|
||||
using System; // For Action
|
||||
@@ -16,8 +17,8 @@ public class AutoTargetting : MonoBehaviour
|
||||
public float targetingAngleThreshold = 90f;
|
||||
|
||||
[Header("Rotation Parameters")]
|
||||
[Tooltip("Speed at which the player rotates towards the current target when rotation is explicitly called.")]
|
||||
public float playerRotationSpeed = 10f;
|
||||
[Tooltip("Speed at which the player rotates towards the current target when rotation is explicitly called (e.g., by MagicAttacks).")]
|
||||
public float playerRotationSpeed = 10f; // This will be used by MagicAttacks
|
||||
|
||||
[Header("Visuals")]
|
||||
[Tooltip("Name of the material color property to animate for Fresnel effect.")]
|
||||
@@ -30,8 +31,8 @@ public class AutoTargetting : MonoBehaviour
|
||||
public Color deselectHighlightColor = Color.black;
|
||||
[Tooltip("Duration of the fade in/out animation for the highlight.")]
|
||||
public float highlightFadeDuration = 0.3f;
|
||||
[Tooltip("If true, will try to find a SkinnedMeshRenderer first, then MeshRenderer. If false, affects all renderers.")]
|
||||
public bool preferSkinnedMeshRenderer = true;
|
||||
[Tooltip("If true, was previously used to prefer SkinnedMeshRenderer. Now GetTargetRenderers collects both SkinnedMeshRenderers and MeshRenderers regardless of this flag. This flag might be repurposed or removed in the future.")]
|
||||
public bool preferSkinnedMeshRenderer = true; // Note: Its effect on GetTargetRenderers is changed.
|
||||
|
||||
public vFSMBehaviourController CurrentTarget { get; private set; }
|
||||
public event Action<vFSMBehaviourController> OnTargetSelected;
|
||||
@@ -45,7 +46,7 @@ public class AutoTargetting : MonoBehaviour
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (Player.Instance == null) // Player.Instance should be set by its own Awake
|
||||
if (Player.Instance == null)
|
||||
{
|
||||
Debug.LogError("AutoTargetting: Player.Instance is not available at Start! Ensure Player script with static Instance exists and runs before AutoTargetting.");
|
||||
enabled = false;
|
||||
@@ -57,7 +58,7 @@ public class AutoTargetting : MonoBehaviour
|
||||
if (_gameStateManager != null)
|
||||
{
|
||||
_gameStateManager.m_OnStateChanged.AddListener(HandleGameStateChanged);
|
||||
HandleGameStateChanged(_gameStateManager.CurrentState); // Initialize based on current state
|
||||
HandleGameStateChanged(_gameStateManager.CurrentState);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,17 +99,16 @@ public class AutoTargetting : MonoBehaviour
|
||||
_targetingLoopCoroutine = StartCoroutine(TargetingLoop());
|
||||
}
|
||||
}
|
||||
else // State is NORMAL or other non-combat
|
||||
else
|
||||
{
|
||||
if (_targetingLoopCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_targetingLoopCoroutine);
|
||||
_targetingLoopCoroutine = null;
|
||||
}
|
||||
if (CurrentTarget != null) // If there was a target, deselect it
|
||||
if (CurrentTarget != null)
|
||||
{
|
||||
vFSMBehaviourController oldTarget = CurrentTarget;
|
||||
SetNewTarget(null); // This will handle fade out and event
|
||||
SetNewTarget(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,12 +117,12 @@ public class AutoTargetting : MonoBehaviour
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_playerTransform == null && Player.Instance != null) // Defensive: re-cache if player was respawned or similar
|
||||
if (_playerTransform == null && Player.Instance != null)
|
||||
{
|
||||
_playerTransform = Player.Instance.transform;
|
||||
}
|
||||
|
||||
if (_playerTransform != null) // Only proceed if we have a valid player transform
|
||||
if (_playerTransform != null)
|
||||
{
|
||||
UpdateTarget();
|
||||
}
|
||||
@@ -130,9 +130,6 @@ public class AutoTargetting : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given AI target is within the specified angle from the source transform's forward direction.
|
||||
/// </summary>
|
||||
public bool IsTargetInAngle(Transform sourceTransform, vFSMBehaviourController targetAI, float angleThreshold)
|
||||
{
|
||||
if (targetAI == null || sourceTransform == null)
|
||||
@@ -141,9 +138,8 @@ public class AutoTargetting : MonoBehaviour
|
||||
}
|
||||
|
||||
Vector3 directionToTarget = (targetAI.transform.position - sourceTransform.position);
|
||||
directionToTarget.y = 0; // Consider only horizontal angle
|
||||
directionToTarget.y = 0;
|
||||
|
||||
// If target is effectively at the same horizontal position, consider it in angle.
|
||||
if (directionToTarget.sqrMagnitude < 0.0001f) return true;
|
||||
|
||||
directionToTarget.Normalize();
|
||||
@@ -162,7 +158,7 @@ public class AutoTargetting : MonoBehaviour
|
||||
|
||||
if (combatControllers == null || combatControllers.Count == 0)
|
||||
{
|
||||
if (CurrentTarget != null) SetNewTarget(null); // No enemies, clear current
|
||||
if (CurrentTarget != null) SetNewTarget(null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -173,20 +169,14 @@ public class AutoTargetting : MonoBehaviour
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check 1: Is target within selection angle?
|
||||
if (!IsTargetInAngle(_playerTransform, controller, targetingAngleThreshold))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check 2: Is target within selection distance?
|
||||
float distSqr = (controller.transform.position - _playerTransform.position).sqrMagnitude;
|
||||
if (distSqr <= minDistanceSqr) // distSqr must also be <= maxTargetingDistance^2 due to minDistanceSqr initialization
|
||||
if (distSqr <= minDistanceSqr)
|
||||
{
|
||||
// If multiple targets are at similar very close distances, this might pick the "last one" processed.
|
||||
// For more refined "closest", ensure this is strictly '<' for new candidates,
|
||||
// or add a secondary sort criterion if multiple are at exact same minDistanceSqr.
|
||||
// Current logic is fine for most cases.
|
||||
minDistanceSqr = distSqr;
|
||||
bestCandidate = controller;
|
||||
}
|
||||
@@ -196,27 +186,22 @@ public class AutoTargetting : MonoBehaviour
|
||||
{
|
||||
SetNewTarget(bestCandidate);
|
||||
}
|
||||
else if (CurrentTarget != null && !IsTargetValid(CurrentTarget)) // Current target became invalid (e.g. died, moved out of range/angle)
|
||||
else if (CurrentTarget != null && !IsTargetValid(CurrentTarget))
|
||||
{
|
||||
SetNewTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given target is still valid according to AutoTargetting's rules.
|
||||
/// </summary>
|
||||
private bool IsTargetValid(vFSMBehaviourController target)
|
||||
{
|
||||
if (target == null || !target.gameObject.activeInHierarchy || target.aiController.currentHealth <= 0)
|
||||
return false;
|
||||
|
||||
if (_playerTransform == null) return false; // Should not happen if script is active
|
||||
if (_playerTransform == null) return false;
|
||||
|
||||
// Check 1: Angle (using AutoTargetting's own targetingAngleThreshold)
|
||||
if (!IsTargetInAngle(_playerTransform, target, targetingAngleThreshold))
|
||||
return false;
|
||||
|
||||
// Check 2: Distance (using AutoTargetting's own maxTargetingDistance)
|
||||
float distSqr = (target.transform.position - _playerTransform.position).sqrMagnitude;
|
||||
return distSqr <= maxTargetingDistance * maxTargetingDistance;
|
||||
}
|
||||
@@ -225,26 +210,21 @@ public class AutoTargetting : MonoBehaviour
|
||||
{
|
||||
if (CurrentTarget == newTarget) return;
|
||||
|
||||
// Deselect previous target
|
||||
if (CurrentTarget != null)
|
||||
{
|
||||
ApplyHighlight(CurrentTarget, false); // Fade out
|
||||
ApplyHighlight(CurrentTarget, false);
|
||||
OnTargetDeselected?.Invoke(CurrentTarget);
|
||||
}
|
||||
|
||||
CurrentTarget = newTarget;
|
||||
|
||||
// Select new target
|
||||
if (CurrentTarget != null)
|
||||
{
|
||||
ApplyHighlight(CurrentTarget, true); // Fade in
|
||||
ApplyHighlight(CurrentTarget, true);
|
||||
OnTargetSelected?.Invoke(CurrentTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smoothly rotates the player character towards the CurrentTarget on the horizontal plane.
|
||||
/// </summary>
|
||||
public void ExecuteRotationTowardsCurrentTarget(float deltaTime)
|
||||
{
|
||||
if (CurrentTarget == null || _playerTransform == null)
|
||||
@@ -255,17 +235,13 @@ public class AutoTargetting : MonoBehaviour
|
||||
Vector3 directionToTarget = CurrentTarget.transform.position - _playerTransform.position;
|
||||
directionToTarget.y = 0f;
|
||||
|
||||
if (directionToTarget.sqrMagnitude < 0.0001f) return; // Already at target or too close to get a direction
|
||||
if (directionToTarget.sqrMagnitude < 0.0001f) return;
|
||||
|
||||
directionToTarget.Normalize();
|
||||
Quaternion targetRotation = Quaternion.LookRotation(directionToTarget);
|
||||
_playerTransform.rotation = Quaternion.Lerp(_playerTransform.rotation, targetRotation, deltaTime * playerRotationSpeed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the health of the CurrentTarget.
|
||||
/// </summary>
|
||||
/// <returns>The health of the CurrentTarget, or -1f if no target or target has no health component.</returns>
|
||||
public float GetCurrentTargetHealth()
|
||||
{
|
||||
if (CurrentTarget != null && CurrentTarget.aiController != null)
|
||||
@@ -280,26 +256,51 @@ public class AutoTargetting : MonoBehaviour
|
||||
SetNewTarget(null);
|
||||
if (findNewOneImmediately && _gameStateManager != null && _gameStateManager.CurrentState == GameStateManager.State.COMBAT)
|
||||
{
|
||||
UpdateTarget(); // Attempt to find a new one if in combat
|
||||
UpdateTarget();
|
||||
}
|
||||
}
|
||||
|
||||
// *** MODIFIED GetTargetRenderers METHOD ***
|
||||
private Renderer[] GetTargetRenderers(vFSMBehaviourController targetController)
|
||||
{
|
||||
if (targetController == null) return new Renderer[0];
|
||||
|
||||
if (preferSkinnedMeshRenderer)
|
||||
List<Renderer> collectedRenderers = new List<Renderer>();
|
||||
|
||||
// Collect all SkinnedMeshRenderers
|
||||
SkinnedMeshRenderer[] smrs = targetController.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
if (smrs != null && smrs.Length > 0)
|
||||
{
|
||||
SkinnedMeshRenderer smr = targetController.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
if (smr != null) return new Renderer[] { smr };
|
||||
|
||||
MeshRenderer mr = targetController.GetComponentInChildren<MeshRenderer>();
|
||||
if (mr != null) return new Renderer[] { mr };
|
||||
collectedRenderers.AddRange(smrs);
|
||||
}
|
||||
|
||||
// Collect all MeshRenderers
|
||||
MeshRenderer[] mrs = targetController.GetComponentsInChildren<MeshRenderer>(true);
|
||||
if (mrs != null && mrs.Length > 0)
|
||||
{
|
||||
collectedRenderers.AddRange(mrs);
|
||||
}
|
||||
|
||||
return targetController.GetComponentsInChildren<Renderer>(true); // Include inactive renderers if any
|
||||
// If no specific SMRs or MRs were found, fall back to all Renderers (optional, but good for safety)
|
||||
// Or, if the goal is *only* SMRs and MRs, this fallback can be removed.
|
||||
// For now, let's assume we want to highlight *something* if possible.
|
||||
// If you strictly want ONLY SMRs and MRs, and nothing else, remove this 'if' block.
|
||||
if (collectedRenderers.Count == 0)
|
||||
{
|
||||
Renderer[] allRenderers = targetController.GetComponentsInChildren<Renderer>(true);
|
||||
if (allRenderers != null && allRenderers.Length > 0)
|
||||
{
|
||||
collectedRenderers.AddRange(allRenderers);
|
||||
}
|
||||
}
|
||||
|
||||
// The preferSkinnedMeshRenderer flag is not directly used here for filtering types anymore.
|
||||
// It could potentially be used for ordering or other logic if needed in the future.
|
||||
|
||||
return collectedRenderers.Distinct().ToArray(); // Distinct() to avoid duplicates if an object somehow has multiple relevant renderer types
|
||||
}
|
||||
|
||||
|
||||
private void ApplyHighlight(vFSMBehaviourController targetController, bool fadeIn)
|
||||
{
|
||||
if (targetController == null || string.IsNullOrEmpty(materialHighlightPropertyName)) return;
|
||||
@@ -310,12 +311,10 @@ public class AutoTargetting : MonoBehaviour
|
||||
{
|
||||
if (rend == null) continue;
|
||||
|
||||
// Use rend.materials to get instances for modification
|
||||
foreach (Material mat in rend.materials)
|
||||
{
|
||||
if (mat == null || !mat.HasProperty(materialHighlightPropertyName)) continue;
|
||||
|
||||
// Stop any existing fade coroutine for this specific material
|
||||
if (_materialToFadeCoroutineMap.TryGetValue(mat, out Coroutine existingCoroutine) && existingCoroutine != null)
|
||||
{
|
||||
StopCoroutine(existingCoroutine);
|
||||
@@ -324,7 +323,6 @@ public class AutoTargetting : MonoBehaviour
|
||||
Color currentColor = mat.GetColor(materialHighlightPropertyName);
|
||||
Color targetColor = fadeIn ? highlightColor : deselectHighlightColor;
|
||||
|
||||
// Smartly store original color only if not already a highlight/deselect color.
|
||||
if (fadeIn)
|
||||
{
|
||||
if (!_originalMaterialColors.ContainsKey(mat) ||
|
||||
@@ -333,15 +331,6 @@ public class AutoTargetting : MonoBehaviour
|
||||
_originalMaterialColors[mat] = currentColor;
|
||||
}
|
||||
}
|
||||
// When fading out, if an original was stored, we could potentially use it instead of always deselectHighlightColor.
|
||||
// However, for a consistent "off" state, deselectHighlightColor (e.g., black) is usually desired.
|
||||
// If fading out and original exists and isn't black:
|
||||
// else if (_originalMaterialColors.TryGetValue(mat, out Color original) && original != deselectHighlightColor)
|
||||
// {
|
||||
// targetColor = original; // Fade back to true original
|
||||
// }
|
||||
|
||||
|
||||
Coroutine newFadeCoroutine = StartCoroutine(FadeMaterialPropertyCoroutine(mat, currentColor, targetColor, highlightFadeDuration));
|
||||
_materialToFadeCoroutineMap[mat] = newFadeCoroutine;
|
||||
}
|
||||
@@ -351,11 +340,10 @@ public class AutoTargetting : MonoBehaviour
|
||||
private IEnumerator FadeMaterialPropertyCoroutine(Material material, Color fromValue, Color toValue, float duration)
|
||||
{
|
||||
float timer = 0f;
|
||||
// yield return null; // Not strictly necessary here as StopCoroutine handles overlaps.
|
||||
|
||||
while (timer < duration)
|
||||
{
|
||||
if (material == null) yield break; // Material might have been destroyed
|
||||
if (material == null) yield break;
|
||||
|
||||
timer += Time.deltaTime;
|
||||
float progress = Mathf.Clamp01(timer / duration);
|
||||
@@ -363,15 +351,9 @@ public class AutoTargetting : MonoBehaviour
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (material != null) // Final set
|
||||
if (material != null)
|
||||
{
|
||||
material.SetColor(materialHighlightPropertyName, toValue);
|
||||
}
|
||||
|
||||
// Optional: Remove from map if coroutine completed naturally and is still the one in the map.
|
||||
// if (_materialToFadeCoroutineMap.TryGetValue(material, out Coroutine currentMappedCoroutine) && currentMappedCoroutine == /*this specific instance, tricky to get*/)
|
||||
// {
|
||||
// _materialToFadeCoroutineMap.Remove(material);
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ using Invector;
|
||||
using Invector.vCharacterController;
|
||||
using Invector.vCharacterController.vActions;
|
||||
using Sirenix.OdinInspector;
|
||||
// using UnityEditor; // Best to remove if not strictly needed for runtime
|
||||
// using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.VFX;
|
||||
// using static Invector.vObjectDamage; // Not used directly, consider removing
|
||||
// using static Invector.vObjectDamage;
|
||||
using DG.Tweening;
|
||||
using Invector.vCharacterController.AI.FSMBehaviour;
|
||||
using Beyond; // For Player, GameStateManager, AutoTargetting (if Player.Instance.AutoTarget is of this type)
|
||||
using Beyond;
|
||||
|
||||
namespace Beyond
|
||||
{
|
||||
@@ -51,8 +51,8 @@ namespace Beyond
|
||||
private Coroutine lastPushRoutine = null;
|
||||
private ParticleSystem flame;
|
||||
private BoxCollider flameDamager;
|
||||
private bLockOn lockOn; // Retained for fallback aiming or non-combat interactions if needed
|
||||
private const float fireballAimerThreshold = -1.0f; // Used for fallback aiming if no auto-target
|
||||
private bLockOn lockOn;
|
||||
private const float fireballAimerThreshold = -1.0f;
|
||||
private const float fireballAimerHeightAdjuster = 0.1f;
|
||||
private const float fireballDamagerDuration = 0.3f;
|
||||
private const float fireballTargetYPositionOffset = 0.75f;
|
||||
@@ -64,21 +64,12 @@ namespace Beyond
|
||||
private bool canPlayNoFaithClip = true;
|
||||
private bool canPlayCantDoClip = true;
|
||||
|
||||
// NEW: AutoTargetting fields
|
||||
private AutoTargetting _autoTargettingInstance;
|
||||
// REMOVED: public bool enableAutoTargetIntegration = true;
|
||||
// REMOVED: public float maxTurnTowardDistance = 10f;
|
||||
// REMOVED: public float rotationSpeed = 500f;
|
||||
// REMOVED: public float degreeThreshold = 100f; (already removed in previous step)
|
||||
|
||||
[BoxGroup("Auto targetting")]
|
||||
[Tooltip("Enable to use AutoTargetting for player rotation and spell aiming.")]
|
||||
public bool enableAutoTargetIntegration = true;
|
||||
[BoxGroup("Auto targetting")]
|
||||
[Tooltip("Max distance for player to turn towards an auto-target during spell casting.")]
|
||||
public float maxTurnTowardDistance = 10f;
|
||||
[BoxGroup("Auto targetting")]
|
||||
[Tooltip("Rotation speed when turning towards an auto-target.")]
|
||||
public float rotationSpeed = 500f;
|
||||
[BoxGroup("Auto targetting")]
|
||||
[Tooltip("Angle threshold within which the player will rotate towards an auto-target.")]
|
||||
public float degreeThreshold = 100f;
|
||||
|
||||
public UnityAction<Collider> onHitFireball;
|
||||
|
||||
@@ -86,20 +77,19 @@ namespace Beyond
|
||||
{
|
||||
tpInput = GetComponent<bThirdPersonInput>();
|
||||
|
||||
// NEW: Initialize AutoTargetting instance
|
||||
if (Player.Instance != null)
|
||||
{
|
||||
_autoTargettingInstance = Player.Instance.AutoTarget; // Assuming Player.Instance has an AutoTarget property of type AutoTargetting
|
||||
if (_autoTargettingInstance == null && enableAutoTargetIntegration)
|
||||
_autoTargettingInstance = Player.Instance.AutoTarget;
|
||||
if (_autoTargettingInstance == null) // Simplified warning
|
||||
{
|
||||
Debug.LogWarning("MagicAttacks: AutoTargetting component not found on Player.Instance.AutoTarget, but enableAutoTargetIntegration is true. Targeting features will be limited.");
|
||||
Debug.LogWarning("MagicAttacks: AutoTargetting component not found on Player.Instance.AutoTarget. Auto-targeting features will not be available.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("MagicAttacks: Player.Instance is null in Awake. Cannot get AutoTargetting component.");
|
||||
}
|
||||
lockOn = GetComponent<bLockOn>(); // Keep for potential fallback
|
||||
lockOn = GetComponent<bLockOn>();
|
||||
|
||||
EffectDesc mpush = m_effects[(int)EffectType.MAGIC_PUSH];
|
||||
EffectDesc flameThrowe = m_effects[(int)EffectType.FLAME_THROWER];
|
||||
@@ -165,8 +155,8 @@ namespace Beyond
|
||||
[Button]
|
||||
private void OnSilentPeek()
|
||||
{
|
||||
StopCoroutine(SilentPeekCoroutine());
|
||||
StartCoroutine(SilentPeekCoroutine());
|
||||
StopCoroutine(nameof(SilentPeekCoroutine));
|
||||
StartCoroutine(nameof(SilentPeekCoroutine));
|
||||
}
|
||||
|
||||
private IEnumerator SilentPeekCoroutine()
|
||||
@@ -202,13 +192,12 @@ namespace Beyond
|
||||
private IEnumerator MagicPushCoroutine()
|
||||
{
|
||||
EffectDesc mpush = m_effects[(int)EffectType.MAGIC_PUSH];
|
||||
// MODIFIED: Use TurnTowardTargetCoroutine for potential rotation during wind-up
|
||||
yield return TurnTowardTargetCoroutine(mpush.startTime);
|
||||
mpush.effectObject.SetActive(false);
|
||||
mpush.effectObject.SetActive(true);
|
||||
yield return new WaitForSeconds(mpush.delay);
|
||||
Debug.Log("Bum!"); // Consider replacing with actual effect logic
|
||||
yield return new WaitForSeconds(mpush.endTime); // This is endTime after delay, might be confusing.
|
||||
Debug.Log("Bum!");
|
||||
yield return new WaitForSeconds(mpush.endTime);
|
||||
mpush.effectObject.SetActive(false);
|
||||
yield return null;
|
||||
}
|
||||
@@ -221,13 +210,12 @@ namespace Beyond
|
||||
private IEnumerator FlameThrowerhCoroutine()
|
||||
{
|
||||
EffectDesc flameThrowe = m_effects[(int)EffectType.FLAME_THROWER];
|
||||
// MODIFIED: TurnTowardTargetCoroutine will handle rotation based on AutoTargetting
|
||||
yield return TurnTowardTargetCoroutine(flameThrowe.startTime);
|
||||
flameDamager.enabled = true;
|
||||
flame.Play();
|
||||
yield return new WaitForSeconds(flameThrowe.endTime); // Duration of flame
|
||||
yield return new WaitForSeconds(flameThrowe.endTime);
|
||||
flame.Stop();
|
||||
yield return new WaitForSeconds(flameThrowe.delay); // Cooldown/after-effect
|
||||
yield return new WaitForSeconds(flameThrowe.delay);
|
||||
flameDamager.enabled = false;
|
||||
yield return null;
|
||||
}
|
||||
@@ -241,11 +229,10 @@ namespace Beyond
|
||||
private IEnumerator ScanCoroutine()
|
||||
{
|
||||
EffectDesc scan = m_effects[(int)EffectType.SCAN];
|
||||
// Scan might not need rotation, but if it had a wind-up animation, TurnTowardTargetCoroutine could be used.
|
||||
yield return new WaitForSeconds(scan.startTime);
|
||||
float time = scan.startTime - scan.delay; // This calculation seems off if delay is for after effect. Assuming startTime is actual start.
|
||||
float time = scan.startTime - scan.delay;
|
||||
float maxRange = 50f;
|
||||
float speed = maxRange / (scan.endTime - scan.startTime); // scan.endTime is duration here
|
||||
float speed = maxRange / (scan.endTime - scan.startTime);
|
||||
int mask = 1 << LayerMask.NameToLayer("Triggers") | 1 << LayerMask.NameToLayer("HiddenObject");
|
||||
if (scan.effectObject)
|
||||
{
|
||||
@@ -258,11 +245,11 @@ namespace Beyond
|
||||
|
||||
while (waveEffectTimer < waveEffectDuration)
|
||||
{
|
||||
Shader.SetGlobalFloat("_WaveTime", speed * waveEffectTimer); // Use timer relative to effect start
|
||||
Shader.SetGlobalFloat("_WaveTime", speed * waveEffectTimer);
|
||||
waveEffectTimer += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
Shader.SetGlobalFloat("_WaveTime", 0f); // Reset shader global
|
||||
Shader.SetGlobalFloat("_WaveTime", 0f);
|
||||
var colliders = Physics.OverlapSphere(transform.position, maxRange, mask);
|
||||
foreach (var c in colliders)
|
||||
{
|
||||
@@ -270,7 +257,7 @@ namespace Beyond
|
||||
if (h != null)
|
||||
h.OnScanned();
|
||||
}
|
||||
if (scan.effectObject) scan.effectObject.SetActive(false); // Deactivate after use
|
||||
if (scan.effectObject) scan.effectObject.SetActive(false);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
@@ -279,12 +266,11 @@ namespace Beyond
|
||||
StartCoroutine(FireballCoroutine());
|
||||
}
|
||||
|
||||
// MODIFIED: Centralized coroutine for turning towards target during spell animations
|
||||
private IEnumerator TurnTowardTargetCoroutine(float maxDuration)
|
||||
{
|
||||
if (!enableAutoTargetIntegration || _autoTargettingInstance == null)
|
||||
// *** MODIFIED: Condition relies only on _autoTargettingInstance and its CurrentTarget ***
|
||||
if (_autoTargettingInstance == null || _autoTargettingInstance.CurrentTarget == null)
|
||||
{
|
||||
// If auto-targeting is off or unavailable, just wait for the duration without rotation.
|
||||
if (maxDuration > 0) yield return new WaitForSeconds(maxDuration);
|
||||
yield break;
|
||||
}
|
||||
@@ -292,31 +278,34 @@ namespace Beyond
|
||||
float timeElapsed = 0;
|
||||
while (timeElapsed < maxDuration)
|
||||
{
|
||||
// Re-check CurrentTarget in loop in case it becomes null (e.g., target dies mid-turn)
|
||||
if (_autoTargettingInstance.CurrentTarget != null)
|
||||
{
|
||||
vFSMBehaviourController currentTarget = _autoTargettingInstance.CurrentTarget;
|
||||
Transform playerTransform = transform; // Character's transform
|
||||
Transform playerTransform = transform;
|
||||
|
||||
float distSqr = (currentTarget.transform.position - playerTransform.position).sqrMagnitude;
|
||||
|
||||
// Check distance using MagicAttacks.maxTurnTowardDistance
|
||||
if (distSqr <= maxTurnTowardDistance * maxTurnTowardDistance)
|
||||
if (distSqr <= _autoTargettingInstance.maxTargetingDistance * _autoTargettingInstance.maxTargetingDistance)
|
||||
{
|
||||
// Check angle using MagicAttacks.degreeThreshold and AutoTargetting's utility
|
||||
if (_autoTargettingInstance.IsTargetInAngle(playerTransform, currentTarget, degreeThreshold))
|
||||
if (_autoTargettingInstance.IsTargetInAngle(playerTransform, currentTarget, _autoTargettingInstance.targetingAngleThreshold))
|
||||
{
|
||||
Vector3 directionToTarget = currentTarget.transform.position - playerTransform.position;
|
||||
directionToTarget.y = 0f; // Horizontal rotation only
|
||||
directionToTarget.y = 0f;
|
||||
|
||||
if (directionToTarget.sqrMagnitude > 0.0001f) // Ensure there's a direction
|
||||
if (directionToTarget.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(directionToTarget.normalized);
|
||||
// Use MagicAttacks.rotationSpeed for the rotation
|
||||
playerTransform.rotation = Quaternion.RotateTowards(playerTransform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
|
||||
// *** MODIFIED: Use playerRotationSpeed from AutoTargetting ***
|
||||
playerTransform.rotation = Quaternion.RotateTowards(playerTransform.rotation, targetRotation, Time.deltaTime * _autoTargettingInstance.playerRotationSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Target became null during the loop
|
||||
{
|
||||
yield break; // Exit if no target
|
||||
}
|
||||
timeElapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
@@ -324,11 +313,10 @@ namespace Beyond
|
||||
|
||||
private IEnumerator FireballCoroutine()
|
||||
{
|
||||
EffectDesc fireball = m_effects[(int)EffectType.FIREBALL];
|
||||
// MODIFIED: Use new TurnTowardTargetCoroutine
|
||||
yield return TurnTowardTargetCoroutine(fireball.startTime);
|
||||
EffectDesc fireballDesc = m_effects[(int)EffectType.FIREBALL]; // Renamed to avoid conflict
|
||||
yield return TurnTowardTargetCoroutine(fireballDesc.startTime);
|
||||
|
||||
var fireballClone = Instantiate(fireball.effectObject, fireball.effectObject.transform.position, fireball.effectObject.transform.rotation);
|
||||
var fireballClone = Instantiate(fireballDesc.effectObject, fireballDesc.effectObject.transform.position, fireballDesc.effectObject.transform.rotation);
|
||||
fireballClone.SetActive(true);
|
||||
RFX4_PhysicsMotion fireballMotionController = fireballClone.GetComponentInChildren<RFX4_PhysicsMotion>();
|
||||
if (fireballMotionController != null)
|
||||
@@ -341,66 +329,81 @@ namespace Beyond
|
||||
fireballDamageComponent.onHit.AddListener(onHitFireball);
|
||||
}
|
||||
|
||||
// MODIFIED: Use new AimFireball method
|
||||
AimFireball(fireballClone);
|
||||
|
||||
Destroy(fireballClone, 10f); // Self-destruct after time
|
||||
Destroy(fireballClone, 10f);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void EnableBrieflyFireballDamager(object sender, RFX4_PhysicsMotion.RFX4_CollisionInfo e)
|
||||
{
|
||||
RFX4_PhysicsMotion rFX4_PhysicsMotion = (RFX4_PhysicsMotion)sender;
|
||||
CapsuleCollider collider = rFX4_PhysicsMotion.GetComponentInChildren<CapsuleCollider>(); // Assuming damager is a CapsuleCollider
|
||||
CapsuleCollider collider = rFX4_PhysicsMotion.GetComponentInChildren<CapsuleCollider>();
|
||||
if(collider != null) StartCoroutine(EnableBrieflyFireballDamagerCoroutine(collider));
|
||||
}
|
||||
|
||||
// NEW: Refactored fireball aiming logic
|
||||
private void AimFireball(GameObject fireballClone)
|
||||
{
|
||||
Vector3 aimDirection = transform.forward; // Default aim is player's forward
|
||||
Vector3 aimDirection = transform.forward;
|
||||
|
||||
if (enableAutoTargetIntegration && _autoTargettingInstance != null && _autoTargettingInstance.CurrentTarget != null)
|
||||
// *** MODIFIED: Condition relies only on _autoTargettingInstance and its CurrentTarget ***
|
||||
if (_autoTargettingInstance != null && _autoTargettingInstance.CurrentTarget != null)
|
||||
{
|
||||
vFSMBehaviourController autoTarget = _autoTargettingInstance.CurrentTarget;
|
||||
Vector3 targetPosition = autoTarget.transform.position;
|
||||
targetPosition.y += fireballTargetYPositionOffset; // Adjust height for aiming
|
||||
aimDirection = (targetPosition - fireballClone.transform.position).normalized;
|
||||
Transform playerTransform = transform;
|
||||
|
||||
float distSqrToAutoTarget = (autoTarget.transform.position - playerTransform.position).sqrMagnitude;
|
||||
|
||||
if (distSqrToAutoTarget <= _autoTargettingInstance.maxTargetingDistance * _autoTargettingInstance.maxTargetingDistance &&
|
||||
_autoTargettingInstance.IsTargetInAngle(playerTransform, autoTarget, _autoTargettingInstance.targetingAngleThreshold))
|
||||
{
|
||||
Vector3 targetPosition = autoTarget.transform.position;
|
||||
targetPosition.y += fireballTargetYPositionOffset;
|
||||
aimDirection = (targetPosition - fireballClone.transform.position).normalized;
|
||||
}
|
||||
}
|
||||
else if (lockOn != null && lockOn.isLockingOn && lockOn.currentTarget != null) // Fallback to bLockOn target
|
||||
|
||||
if (aimDirection == transform.forward && lockOn != null && lockOn.isLockingOn && lockOn.currentTarget != null)
|
||||
{
|
||||
Vector3 targetPosition = lockOn.currentTarget.position;
|
||||
targetPosition.y += fireballTargetYPositionOffset;
|
||||
aimDirection = (targetPosition - fireballClone.transform.position).normalized;
|
||||
}
|
||||
else if (lockOn != null) // Fallback to nearest enemy in front (from bLockOn)
|
||||
else if (aimDirection == transform.forward && lockOn != null)
|
||||
{
|
||||
List<Transform> closeEnemies = lockOn.GetNearbyTargets();
|
||||
List<Transform> closeEnemies = lockOn.GetNearbyTargets();
|
||||
if (closeEnemies.Count > 0)
|
||||
{
|
||||
foreach (var enemyTransform in closeEnemies) // Find first suitable enemy in front
|
||||
Transform bestFallbackTarget = null;
|
||||
float minAngle = float.MaxValue;
|
||||
|
||||
foreach (var enemyTransform in closeEnemies)
|
||||
{
|
||||
Vector3 targetPosition = enemyTransform.position;
|
||||
targetPosition.y += fireballTargetYPositionOffset;
|
||||
Vector3 directionToEnemy = (targetPosition - fireballClone.transform.position).normalized;
|
||||
|
||||
// Check if enemy is generally in front of the player (fireball origin)
|
||||
if (Vector3.Dot(transform.forward, directionToEnemy) > fireballAimerThreshold)
|
||||
Vector3 directionToEnemyFromPlayer = (enemyTransform.position - transform.position).normalized;
|
||||
float angleToEnemy = Vector3.Angle(transform.forward, directionToEnemyFromPlayer);
|
||||
|
||||
if (Vector3.Dot(transform.forward, directionToEnemyFromPlayer) > fireballAimerThreshold)
|
||||
{
|
||||
aimDirection = directionToEnemy;
|
||||
break;
|
||||
if (angleToEnemy < minAngle) {
|
||||
minAngle = angleToEnemy;
|
||||
bestFallbackTarget = enemyTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestFallbackTarget != null)
|
||||
{
|
||||
Vector3 targetPosition = bestFallbackTarget.position;
|
||||
targetPosition.y += fireballTargetYPositionOffset;
|
||||
aimDirection = (targetPosition - fireballClone.transform.position).normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply calculated aim direction to the fireball, adding vertical adjustment
|
||||
Vector3 finalAimDirection = new Vector3(aimDirection.x, aimDirection.y + fireballAimerHeightAdjuster, aimDirection.z);
|
||||
if (finalAimDirection.sqrMagnitude > 0.001f)
|
||||
{
|
||||
fireballClone.transform.rotation = Quaternion.LookRotation(finalAimDirection.normalized);
|
||||
}
|
||||
// If aimDirection is zero (shouldn't happen with defaults), it will use its instantiated rotation.
|
||||
}
|
||||
|
||||
|
||||
@@ -413,26 +416,24 @@ namespace Beyond
|
||||
|
||||
public void Shield()
|
||||
{
|
||||
StopCoroutine(ShieldCoroutine()); // Ensure only one shield coroutine runs
|
||||
StartCoroutine(ShieldCoroutine());
|
||||
StopCoroutine(nameof(ShieldCoroutine));
|
||||
StartCoroutine(nameof(ShieldCoroutine));
|
||||
}
|
||||
|
||||
private IEnumerator ShieldCoroutine()
|
||||
{
|
||||
shieldAnimationIsActive = true;
|
||||
// Shield typically doesn't need offensive targeting/rotation.
|
||||
// If there was a wind-up animation where player *should* face an enemy, TurnTowardTargetCoroutine could be used.
|
||||
yield return new WaitForSeconds(shield.startTime);
|
||||
shieldEffectIsActive = true;
|
||||
shieldEffectController.InitializeEffect();
|
||||
shield.effectObject.SetActive(true);
|
||||
shieldCollisionController.shieldCollider.enabled = true;
|
||||
yield return new WaitForSeconds(shield.endTime); // Duration shield is active
|
||||
yield return new WaitForSeconds(shield.endTime);
|
||||
shieldEffectController.DisableEffect();
|
||||
yield return new WaitForSeconds(shield.delay / 2f); // Fade out time part 1
|
||||
yield return new WaitForSeconds(shield.delay / 2f);
|
||||
shieldEffectIsActive = false;
|
||||
shieldCollisionController.shieldCollider.enabled = false;
|
||||
yield return new WaitForSeconds(shield.delay / 2f); // Fade out time part 2
|
||||
yield return new WaitForSeconds(shield.delay / 2f);
|
||||
shield.effectObject.SetActive(false);
|
||||
shieldAnimationIsActive = false;
|
||||
}
|
||||
@@ -450,21 +451,21 @@ namespace Beyond
|
||||
[Tooltip("Input to trigger the custom animation")]
|
||||
public GenericInput actionInput = new GenericInput("L", "L", "L");
|
||||
[Tooltip("Name of the animation clip")]
|
||||
public string animationClip; // This will be set by selectedEffect.animClipName
|
||||
public string animationClip;
|
||||
[Tooltip("Where in the end of the animation will trigger the event OnEndAnimation")]
|
||||
public float animationEnd = 0.8f;
|
||||
|
||||
public UnityEvent OnPlayAnimation; // Consider if this is still needed or how it fits
|
||||
public UnityEvent OnPlayAnimation;
|
||||
public UnityEvent OnEndAnimation;
|
||||
|
||||
public bool isPlaying; // Tracks if the spell animation is currently playing
|
||||
protected bool triggerOnce; // For OnEndAnimation event
|
||||
protected vThirdPersonInput tpInput; // Renamed from tpInput to avoid conflict with Invector's tpInput if any confusion
|
||||
public bool isPlaying;
|
||||
protected bool triggerOnce;
|
||||
protected bThirdPersonInput tpInput;
|
||||
internal bool shieldEffectIsActive;
|
||||
private bool shieldAnimationIsActive;
|
||||
private int equipAreaSelectedIndex = 0;
|
||||
|
||||
protected virtual void LateUpdate() // LateUpdate for animation state checks is common
|
||||
protected virtual void LateUpdate()
|
||||
{
|
||||
TriggerSpellAnimation();
|
||||
AnimationBehaviour();
|
||||
@@ -481,7 +482,7 @@ namespace Beyond
|
||||
|
||||
public void TryToPlaySpellAnimation()
|
||||
{
|
||||
selectedEffect = GetCurrentlySelectedPower(); // Ensure current selected effect is fetched
|
||||
selectedEffect = GetCurrentlySelectedPower();
|
||||
|
||||
if (selectedEffect == shield && shieldAnimationIsActive)
|
||||
{
|
||||
@@ -489,7 +490,7 @@ namespace Beyond
|
||||
return;
|
||||
}
|
||||
|
||||
if (Player.Instance == null) // Safeguard
|
||||
if (Player.Instance == null)
|
||||
{
|
||||
Debug.LogError("Player.Instance is null. Cannot cast spell.");
|
||||
return;
|
||||
@@ -498,37 +499,33 @@ namespace Beyond
|
||||
if (selectedEffect != null && currentSpellFaithCost <= Player.Instance.GetCurrentFaithValue())
|
||||
{
|
||||
Player.Instance.UpdateFaithCurrentValue(-currentSpellFaithCost);
|
||||
animationClip = selectedEffect.animClipName; // Set animation clip for AnimationBehaviour
|
||||
animationClip = selectedEffect.animClipName;
|
||||
|
||||
// NEW: Perform initial snap rotation if auto-targeting is enabled
|
||||
if (enableAutoTargetIntegration)
|
||||
// *** MODIFIED: Snap look if AutoTargetting is available and has a target ***
|
||||
if (_autoTargettingInstance != null && _autoTargettingInstance.CurrentTarget != null)
|
||||
{
|
||||
SnapLookTowardsAutoTarget();
|
||||
SnapLookTowardsAutoTarget();
|
||||
}
|
||||
// else // OLD logic for turning - can be removed or kept as fallback
|
||||
// {
|
||||
// TryToTurnTowordsEnemy();
|
||||
// }
|
||||
|
||||
if (tpInput != null && tpInput.cc != null && tpInput.cc.animator != null)
|
||||
{
|
||||
tpInput.cc.animator.CrossFadeInFixedTime(animationClip, 0.1f);
|
||||
OnPlayAnimation.Invoke(); // Invoke OnPlay event
|
||||
triggerOnce = true; // Allow OnEndAnimation to be called
|
||||
OnPlayAnimation.Invoke();
|
||||
triggerOnce = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Cannot play spell animation: tpInput or its components are null.");
|
||||
return; // Don't proceed to call delegate if animation components are missing
|
||||
return;
|
||||
}
|
||||
|
||||
selectedEffect.del?.Invoke(); // Call the spell's primary action delegate
|
||||
selectedEffect.del?.Invoke();
|
||||
|
||||
if (powersArea.equipSlots[equipAreaSelectedIndex].item.destroyAfterUse)
|
||||
{
|
||||
if (selectedEffect == silentPeek)
|
||||
{
|
||||
// Special handling for Silent Peek item destruction (likely in its controller)
|
||||
// Special handling
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -536,39 +533,37 @@ namespace Beyond
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectedEffect != null) // Not enough faith
|
||||
else if (selectedEffect != null)
|
||||
{
|
||||
TryToPlayNoEnoughFaithClip();
|
||||
}
|
||||
// If selectedEffect is null, nothing happens (no spell selected/valid)
|
||||
}
|
||||
|
||||
// NEW: Method for an immediate snap-look towards the auto-target
|
||||
private void SnapLookTowardsAutoTarget()
|
||||
{
|
||||
// *** MODIFIED: Condition relies only on _autoTargettingInstance and its CurrentTarget ***
|
||||
// This check is somewhat redundant due to call site, but good for safety if called elsewhere.
|
||||
if (_autoTargettingInstance == null || _autoTargettingInstance.CurrentTarget == null)
|
||||
{
|
||||
return; // No auto-target system or no current target
|
||||
return;
|
||||
}
|
||||
|
||||
vFSMBehaviourController currentTarget = _autoTargettingInstance.CurrentTarget;
|
||||
Transform playerTransform = transform;
|
||||
|
||||
// Check distance condition from MagicAttacks settings
|
||||
float distSqr = (currentTarget.transform.position - playerTransform.position).sqrMagnitude;
|
||||
if (distSqr > maxTurnTowardDistance * maxTurnTowardDistance)
|
||||
if (distSqr > _autoTargettingInstance.maxTargetingDistance * _autoTargettingInstance.maxTargetingDistance)
|
||||
{
|
||||
return; // Target is too far for this specific snap-look interaction
|
||||
return;
|
||||
}
|
||||
|
||||
// Check angle condition from MagicAttacks settings
|
||||
if (!_autoTargettingInstance.IsTargetInAngle(playerTransform, currentTarget, degreeThreshold))
|
||||
if (!_autoTargettingInstance.IsTargetInAngle(playerTransform, currentTarget, _autoTargettingInstance.targetingAngleThreshold))
|
||||
{
|
||||
return; // Target is not within the desired cone for snap-look
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 directionToTarget = currentTarget.transform.position - playerTransform.position;
|
||||
directionToTarget.y = 0f; // Horizontal rotation only
|
||||
directionToTarget.y = 0f;
|
||||
|
||||
if (directionToTarget.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
@@ -580,26 +575,26 @@ namespace Beyond
|
||||
{
|
||||
if (!canPlayCantDoClip) return;
|
||||
canPlayCantDoClip = false;
|
||||
DOVirtual.DelayedCall(1f, () => canPlayCantDoClip = true); // Reset flag
|
||||
DOVirtual.DelayedCall(1f, () => canPlayCantDoClip = true);
|
||||
|
||||
var text = "Spell is already active"; // Example message
|
||||
var text = "Spell is already active";
|
||||
if (bItemCollectionDisplay.Instance != null)
|
||||
bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f);
|
||||
if (Player.Instance != null)
|
||||
Player.Instance.PlayICantDoThatYet(); // Assuming this method exists on Player
|
||||
Player.Instance.PlayICantDoThatYet();
|
||||
}
|
||||
|
||||
private void TryToPlayNoEnoughFaithClip()
|
||||
{
|
||||
if (!canPlayNoFaithClip) return;
|
||||
canPlayNoFaithClip = false;
|
||||
DOVirtual.DelayedCall(1.5f, () => canPlayNoFaithClip = true); // Reset flag
|
||||
DOVirtual.DelayedCall(1.5f, () => canPlayNoFaithClip = true);
|
||||
|
||||
var text = "Not enough Faith";
|
||||
if (bItemCollectionDisplay.Instance != null)
|
||||
bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f);
|
||||
if (Player.Instance != null)
|
||||
Player.Instance.PlayNoFaithClip(); // Assuming this method exists on Player
|
||||
Player.Instance.PlayNoFaithClip();
|
||||
}
|
||||
|
||||
public EffectDesc GetCurrentlySelectedPower()
|
||||
@@ -613,7 +608,7 @@ namespace Beyond
|
||||
}
|
||||
|
||||
bItem selectedSpellItem = powersArea.equipSlots[equipAreaSelectedIndex].item;
|
||||
currentSelectedSpellName = selectedSpellItem.name; // Store for display or debugging
|
||||
currentSelectedSpellName = selectedSpellItem.name;
|
||||
currentSpellFaithCost = selectedSpellItem.GetItemAttribute(bItemAttributes.Faith).value;
|
||||
|
||||
return m_effects.Find(effect => effect.name == selectedSpellItem.name || effect.secondaryName == selectedSpellItem.name);
|
||||
@@ -622,30 +617,9 @@ namespace Beyond
|
||||
public void SelectPowerBasedOnArea(int newIndex)
|
||||
{
|
||||
equipAreaSelectedIndex = newIndex;
|
||||
selectedEffect = GetCurrentlySelectedPower(); // Update current effect based on selection
|
||||
selectedEffect = GetCurrentlySelectedPower();
|
||||
}
|
||||
|
||||
// OLD rotation methods - can be removed or commented out if new system is preferred
|
||||
/*
|
||||
private void LerpRotation()
|
||||
{
|
||||
// ... original LerpRotation code using GetNearestEnemy ...
|
||||
}
|
||||
|
||||
private bool IsEnemyInAngleRange(vFSMBehaviourController ai)
|
||||
{
|
||||
// ... original IsEnemyInAngleRange code ...
|
||||
}
|
||||
private vFSMBehaviourController GetNearestEnemy(ref float minDist)
|
||||
{
|
||||
// ... original GetNearestEnemy code ...
|
||||
}
|
||||
private void TryToTurnTowordsEnemy() // Replaced by SnapLookTowardsAutoTarget
|
||||
{
|
||||
// ... original TryToTurnTowordsEnemy code ...
|
||||
}
|
||||
*/
|
||||
|
||||
protected virtual void AnimationBehaviour()
|
||||
{
|
||||
if (tpInput == null || tpInput.cc == null || tpInput.cc.animator == null || string.IsNullOrEmpty(animationClip))
|
||||
@@ -654,7 +628,6 @@ namespace Beyond
|
||||
return;
|
||||
}
|
||||
|
||||
// isPlaying should reflect if the *specific spell animation* is active.
|
||||
isPlaying = tpInput.cc.animator.GetCurrentAnimatorStateInfo(spellLayerIndex).IsName(animationClip) ||
|
||||
tpInput.cc.animator.GetNextAnimatorStateInfo(spellLayerIndex).IsName(animationClip);
|
||||
|
||||
@@ -673,13 +646,9 @@ namespace Beyond
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not playing the specific animation clip, ensure triggerOnce is reset
|
||||
// This handles cases where animation might be interrupted before reaching animationEnd
|
||||
if (triggerOnce)
|
||||
{
|
||||
triggerOnce = false;
|
||||
// Optionally, invoke OnEndAnimation if it should always fire on exiting the state,
|
||||
// but current logic only fires it if normalizedTime >= animationEnd.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Beyond
|
||||
}
|
||||
|
||||
[Button]
|
||||
private void Respawn()
|
||||
public void Respawn()
|
||||
{
|
||||
transform.position = respawnPos;
|
||||
if (m_player)
|
||||
|
||||
Reference in New Issue
Block a user