Summoner
This commit is contained in:
@@ -2,6 +2,7 @@ using Invector;
|
||||
using Invector.vCharacterController.AI;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DemonBoss.Summoner
|
||||
@@ -43,6 +44,16 @@ namespace DemonBoss.Summoner
|
||||
[Tooltip("Minimum distance to player before engaging in melee")]
|
||||
public float meleeEngageDistance = 3f;
|
||||
|
||||
[Header("Melee Cooldown")]
|
||||
[Tooltip("Minimum seconds between melee attacks")]
|
||||
public float meleeCooldownMin = 5f;
|
||||
|
||||
[Tooltip("Maximum seconds between melee attacks")]
|
||||
public float meleeCooldownMax = 8f;
|
||||
|
||||
[Tooltip("Preferred safe distance from player (used for flee/spacing)")]
|
||||
public float safeDistance = 8f;
|
||||
|
||||
[Tooltip("Should summoner fight when minions are alive?")]
|
||||
public bool fightWithMinions = false;
|
||||
|
||||
@@ -61,6 +72,29 @@ namespace DemonBoss.Summoner
|
||||
[Tooltip("Sound played when spawning minions")]
|
||||
public AudioClip summonSound;
|
||||
|
||||
[Header("Summon Restrictions")]
|
||||
[Tooltip("If true, summoner will only summon when no minions are alive")]
|
||||
public bool requireZeroMinionsToSummon = true;
|
||||
|
||||
[Header("Spell Casting")]
|
||||
[Tooltip("Fireball prefab (projectile handles its own targeting)")]
|
||||
public GameObject fireballPrefab;
|
||||
|
||||
[Tooltip("Optional spawn pivot for spells (e.g. staff tip). If null, uses summoner transform.")]
|
||||
public Transform spellSpawnPivot;
|
||||
|
||||
[Tooltip("Cooldown between spell casts (seconds)")]
|
||||
public float spellCooldown = 6f;
|
||||
|
||||
[Tooltip("Minimum distance required to cast spell")]
|
||||
public float spellMinDistance = 5f;
|
||||
|
||||
[Tooltip("Maximum distance allowed to cast spell (0 = no limit)")]
|
||||
public float spellMaxDistance = 20f;
|
||||
|
||||
[Tooltip("Only cast spell when minions are alive")]
|
||||
public bool spellRequiresMinionsAlive = true;
|
||||
|
||||
[Header("Debug")]
|
||||
[Tooltip("Enable debug logging")]
|
||||
public bool enableDebug = false;
|
||||
@@ -76,12 +110,23 @@ namespace DemonBoss.Summoner
|
||||
private vHealthController healthController;
|
||||
private bool isSpawning = false;
|
||||
private Coroutine spawnCoroutine;
|
||||
private float lastSpellTime = -999f;
|
||||
private bool spawnRequested = false;
|
||||
private float nextMeleeTime = 0f;
|
||||
|
||||
// Public properties for FSM decisions
|
||||
public bool IsSpawning => isSpawning;
|
||||
|
||||
public int ActiveMinionCount => activeMinions.Count;
|
||||
public bool CanSpawnMinions => activeMinions.Count < maxActiveMinions && !isSpawning;
|
||||
public bool CanSpawnMinions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isSpawning) return false;
|
||||
if (requireZeroMinionsToSummon && activeMinions.Count > 0) return false;
|
||||
return activeMinions.Count < maxActiveMinions;
|
||||
}
|
||||
}
|
||||
public bool HasActiveMinions => activeMinions.Count > 0;
|
||||
|
||||
private void Awake()
|
||||
@@ -125,6 +170,7 @@ namespace DemonBoss.Summoner
|
||||
/// </summary>
|
||||
public void StartSpawning()
|
||||
{
|
||||
spawnRequested = false;
|
||||
if (isSpawning)
|
||||
{
|
||||
if (enableDebug) Debug.Log("[SummonerAI] Already spawning minions");
|
||||
@@ -137,9 +183,44 @@ namespace DemonBoss.Summoner
|
||||
return;
|
||||
}
|
||||
|
||||
if (requireZeroMinionsToSummon && HasActiveMinions)
|
||||
{
|
||||
if (enableDebug) Debug.Log("[SummonerAI] Minions alive - summon blocked");
|
||||
return;
|
||||
}
|
||||
|
||||
spawnCoroutine = StartCoroutine(SpawnMinionsCoroutine());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request spawning to begin on an animation event.
|
||||
/// </summary>
|
||||
public void RequestSpawn()
|
||||
{
|
||||
spawnRequested = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel a pending spawn request (e.g., on state exit).
|
||||
/// </summary>
|
||||
public void CancelSpawnRequest()
|
||||
{
|
||||
spawnRequested = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animation event hook. Call from the summon animation.
|
||||
/// </summary>
|
||||
public void OnSummonAnimationEvent()
|
||||
{
|
||||
if (!spawnRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StartSpawning();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop spawning minions immediately
|
||||
/// </summary>
|
||||
@@ -282,14 +363,102 @@ namespace DemonBoss.Summoner
|
||||
return GetDistanceToPlayer() <= meleeEngageDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if player is within the desired safe distance
|
||||
/// </summary>
|
||||
public bool IsPlayerTooCloseForSafeDistance()
|
||||
{
|
||||
return GetDistanceToPlayer() < safeDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if summoner has reached/maintains safe distance
|
||||
/// </summary>
|
||||
public bool IsAtSafeDistance()
|
||||
{
|
||||
return GetDistanceToPlayer() >= safeDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should summoner try to flee to reach safe distance
|
||||
/// </summary>
|
||||
public bool ShouldFleeToSafeDistance()
|
||||
{
|
||||
float distance = GetDistanceToPlayer();
|
||||
if (distance <= meleeEngageDistance) return false;
|
||||
if (CanSpawnMinions || CanCastSpell()) return false;
|
||||
return distance < safeDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if summoner should engage in melee combat
|
||||
/// </summary>
|
||||
public bool ShouldEngageMelee()
|
||||
{
|
||||
if (!IsPlayerInMeleeRange()) return false;
|
||||
if (fightWithMinions) return true;
|
||||
return !HasActiveMinions;
|
||||
if (!CanMeleeNow()) return false;
|
||||
return !CanSpawnMinions && !CanCastSpell();
|
||||
}
|
||||
|
||||
public bool CanMeleeNow()
|
||||
{
|
||||
return Time.time >= nextMeleeTime;
|
||||
}
|
||||
|
||||
public void NotifyMeleeAttack()
|
||||
{
|
||||
float min = Mathf.Min(meleeCooldownMin, meleeCooldownMax);
|
||||
float max = Mathf.Max(meleeCooldownMin, meleeCooldownMax);
|
||||
if (max <= 0f)
|
||||
{
|
||||
nextMeleeTime = 0f;
|
||||
return;
|
||||
}
|
||||
nextMeleeTime = Time.time + Random.Range(min, max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if summoner can cast a ranged spell now
|
||||
/// </summary>
|
||||
public bool CanCastSpell()
|
||||
{
|
||||
if (isSpawning) return false;
|
||||
if (fireballPrefab == null) return false;
|
||||
if (spellRequiresMinionsAlive && !HasActiveMinions) return false;
|
||||
|
||||
float distance = GetDistanceToPlayer();
|
||||
if (distance < spellMinDistance) return false;
|
||||
if (spellMaxDistance > 0f && distance > spellMaxDistance) return false;
|
||||
|
||||
return (Time.time - lastSpellTime) >= spellCooldown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notify that a spell was cast (updates cooldown timer)
|
||||
/// </summary>
|
||||
public void NotifySpellCast()
|
||||
{
|
||||
lastSpellTime = Time.time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawn a fireball from pivot towards player
|
||||
/// </summary>
|
||||
public void CastFireball()
|
||||
{
|
||||
if (!CanCastSpell()) return;
|
||||
|
||||
Transform pivot = spellSpawnPivot != null ? spellSpawnPivot : transform;
|
||||
Vector3 targetPos = playerTransform != null ? playerTransform.position + Vector3.up * 1f : (pivot.position + pivot.forward);
|
||||
Vector3 dir = (targetPos - pivot.position).normalized;
|
||||
if (dir == Vector3.zero) dir = pivot.forward;
|
||||
|
||||
Quaternion rot = Quaternion.LookRotation(dir);
|
||||
LeanPool.Spawn(fireballPrefab, pivot.position, rot);
|
||||
|
||||
NotifySpellCast();
|
||||
|
||||
if (enableDebug) Debug.Log("[SummonerAI] Cast fireball");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -327,6 +496,10 @@ namespace DemonBoss.Summoner
|
||||
Gizmos.color = Color.red;
|
||||
DrawCircle(transform.position, meleeEngageDistance, 16);
|
||||
|
||||
// Draw safe distance
|
||||
Gizmos.color = Color.yellow;
|
||||
DrawCircle(transform.position, safeDistance, 24);
|
||||
|
||||
// Draw lines to active minions
|
||||
Gizmos.color = Color.green;
|
||||
foreach (GameObject minion in activeMinions)
|
||||
@@ -356,4 +529,4 @@ namespace DemonBoss.Summoner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user