187 lines
5.2 KiB
C#
187 lines
5.2 KiB
C#
using Invector.vCharacterController.AI.FSMBehaviour;
|
|
using Lean.Pool;
|
|
using UnityEngine;
|
|
|
|
namespace DemonBoss.Magic
|
|
{
|
|
/// <summary>
|
|
/// StateAction for Magic Shield spell - boss casts magical shield for 5 seconds
|
|
/// During casting boss stands still, after completion returns to Combat
|
|
/// </summary>
|
|
[CreateAssetMenu(menuName = "Invector/FSM/Actions/DemonBoss/Cast Shield")]
|
|
public class SA_CastShield : vStateAction
|
|
{
|
|
public override string categoryName => "DemonBoss/Magic";
|
|
public override string defaultName => "Cast Shield";
|
|
|
|
[Header("Shield Configuration")]
|
|
[Tooltip("Prefab with magical shield particle effect")]
|
|
public GameObject shieldFXPrefab;
|
|
|
|
[Tooltip("Shield duration in seconds")]
|
|
public float shieldDuration = 5f;
|
|
|
|
[Tooltip("Animator bool parameter name for blocking state")]
|
|
public string animatorBlockingBool = "IsBlocking";
|
|
|
|
[Header("Debug")]
|
|
[Tooltip("Enable debug logging")]
|
|
public bool enableDebug = false;
|
|
|
|
private GameObject spawnedShield;
|
|
private Animator npcAnimator;
|
|
private Transform npcTransform;
|
|
private float shieldStartTime;
|
|
private bool shieldActive = false;
|
|
|
|
/// <summary>
|
|
/// Main action execution method called by FSM
|
|
/// </summary>
|
|
public override void DoAction(vIFSMBehaviourController fsmBehaviour, vFSMComponentExecutionType executionType = vFSMComponentExecutionType.OnStateUpdate)
|
|
{
|
|
if (executionType == vFSMComponentExecutionType.OnStateEnter)
|
|
{
|
|
OnStateEnter(fsmBehaviour);
|
|
}
|
|
else if (executionType == vFSMComponentExecutionType.OnStateUpdate)
|
|
{
|
|
OnStateUpdate(fsmBehaviour);
|
|
}
|
|
else if (executionType == vFSMComponentExecutionType.OnStateExit)
|
|
{
|
|
OnStateExit(fsmBehaviour);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when entering state - starts shield casting
|
|
/// </summary>
|
|
private void OnStateEnter(vIFSMBehaviourController fsmBehaviour)
|
|
{
|
|
if (enableDebug) Debug.Log("[SA_CastShield] Entering shield casting state");
|
|
|
|
// Store NPC references
|
|
npcTransform = fsmBehaviour.transform;
|
|
npcAnimator = npcTransform.GetComponent<Animator>();
|
|
|
|
var aiController = fsmBehaviour as Invector.vCharacterController.AI.vIControlAI;
|
|
if (aiController != null)
|
|
{
|
|
aiController.Stop();
|
|
if (enableDebug) Debug.Log("[SA_CastShield] AI stopped");
|
|
}
|
|
|
|
if (npcAnimator != null && !string.IsNullOrEmpty(animatorBlockingBool))
|
|
{
|
|
npcAnimator.SetBool(animatorBlockingBool, true);
|
|
if (enableDebug) Debug.Log($"[SA_CastShield] Set bool: {animatorBlockingBool} = true");
|
|
}
|
|
|
|
SpawnShieldEffect(fsmBehaviour);
|
|
|
|
shieldStartTime = Time.time;
|
|
shieldActive = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called every frame during state duration
|
|
/// </summary>
|
|
private void OnStateUpdate(vIFSMBehaviourController fsmBehaviour)
|
|
{
|
|
if (shieldActive && Time.time - shieldStartTime >= shieldDuration)
|
|
{
|
|
if (enableDebug) Debug.Log("[SA_CastShield] Shield time passed, finishing state");
|
|
FinishShield(fsmBehaviour);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when exiting state - cleanup
|
|
/// </summary>
|
|
private void OnStateExit(vIFSMBehaviourController fsmBehaviour)
|
|
{
|
|
if (enableDebug) Debug.Log("[SA_CastShield] Exiting shield state");
|
|
|
|
if (npcAnimator != null && !string.IsNullOrEmpty(animatorBlockingBool))
|
|
{
|
|
npcAnimator.SetBool(animatorBlockingBool, false);
|
|
if (enableDebug) Debug.Log($"[SA_CastShield] Set bool: {animatorBlockingBool} = false");
|
|
}
|
|
|
|
if (shieldActive)
|
|
{
|
|
CleanupShield();
|
|
}
|
|
|
|
var aiController = fsmBehaviour as Invector.vCharacterController.AI.vIControlAI;
|
|
if (aiController != null)
|
|
{
|
|
if (enableDebug) Debug.Log("[SA_CastShield] AI resumed");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Spawns magical shield particle effect
|
|
/// </summary>
|
|
private void SpawnShieldEffect(vIFSMBehaviourController fsmBehaviour)
|
|
{
|
|
if (shieldFXPrefab == null)
|
|
{
|
|
Debug.LogWarning("[SA_CastShield] Missing shieldFXPrefab!");
|
|
return;
|
|
}
|
|
|
|
// Spawn shield at NPC's position and rotation
|
|
Vector3 spawnPosition = npcTransform.position;
|
|
Quaternion spawnRotation = npcTransform.rotation;
|
|
|
|
spawnedShield = LeanPool.Spawn(shieldFXPrefab, spawnPosition, spawnRotation);
|
|
|
|
if (enableDebug) Debug.Log($"[SA_CastShield] Shield spawned at NPC position: {spawnPosition}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finishes shield operation and transitions to next state
|
|
/// </summary>
|
|
private void FinishShield(vIFSMBehaviourController fsmBehaviour)
|
|
{
|
|
shieldActive = false;
|
|
CleanupShield();
|
|
|
|
DEC_CheckCooldown.SetCooldownStatic(fsmBehaviour, "Shield", 15f);
|
|
|
|
// End state - FSM will transition to next state
|
|
// FYI: In Invector FSM, state completion is handled automatically
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans up spawned shield
|
|
/// </summary>
|
|
private void CleanupShield()
|
|
{
|
|
if (spawnedShield != null)
|
|
{
|
|
LeanPool.Despawn(spawnedShield);
|
|
spawnedShield = null;
|
|
if (enableDebug) Debug.Log("[SA_CastShield] Shield despawned");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if shield is currently active
|
|
/// </summary>
|
|
public bool IsShieldActive()
|
|
{
|
|
return shieldActive;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns remaining shield time
|
|
/// </summary>
|
|
public float GetRemainingShieldTime()
|
|
{
|
|
if (!shieldActive) return 0f;
|
|
return Mathf.Max(0f, shieldDuration - (Time.time - shieldStartTime));
|
|
}
|
|
}
|
|
} |