80 lines
3.7 KiB
C#
80 lines
3.7 KiB
C#
// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs
|
|
using UnityEngine;
|
|
using TD.Audio;
|
|
using TD.Core;
|
|
|
|
namespace TD.Gameplay.BuilderSpells
|
|
{
|
|
/// <summary>
|
|
/// Builder spell #2 — slow every enemy within an area for a duration.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para><see cref="BuilderSpellDefinition.TargetType"/> is <see cref="SpellTargetType.AreaOfEffect"/>
|
|
/// — the cast controller previews <see cref="BuilderSpellDefinition.Radius"/> as a decal
|
|
/// while aiming, and this spell resolves against that same radius (no separate field).
|
|
/// </para>
|
|
/// <para><b>Zone, not a snapshot.</b> <see cref="ServerCast"/> spawns a <see
|
|
/// cref="SlowZoneRuntime"/> that keeps re-checking the area for <see cref="EffectDuration"/>
|
|
/// seconds, so only enemies currently standing inside the radius are ever slowed — walking
|
|
/// out drops the slow almost immediately. Always succeeds and starts the cooldown, even if
|
|
/// no enemy is in the radius at the moment of cast, since the zone can still catch one later.
|
|
/// </para>
|
|
/// </remarks>
|
|
[CreateAssetMenu(fileName = "SlowAreaSpell", menuName = "TD/Builder Spells/Slow Area")]
|
|
public class SlowAreaSpellDefinition : BuilderSpellDefinition
|
|
{
|
|
public override BuilderSpellKind Kind => BuilderSpellKind.SlowArea;
|
|
|
|
[Header("Area VFX")]
|
|
[Tooltip("Prefab spawned at the target point on a successful cast, authored at a 1-unit " +
|
|
"radius — scaled up to match Radius here. Lives for EffectDuration, matching " +
|
|
"how long the slow itself lasts. Optional — leave empty for no visual.")]
|
|
[SerializeField] private GameObject areaVfxPrefab;
|
|
|
|
[Tooltip("Sound played on every peer when this spell resolves successfully.")]
|
|
[SerializeField] private SoundConfig areaSound;
|
|
|
|
[Header("Slow Area")]
|
|
[Tooltip("Speed multiplier applied to affected enemies for EffectDuration " +
|
|
"(e.g. 0.5 = half speed).")]
|
|
[Range(0f, 1f)]
|
|
public float SlowFactor = 0.5f;
|
|
|
|
[Tooltip("Seconds the zone itself persists. Enemies are only slowed while standing " +
|
|
"inside it — walking out drops the slow almost immediately.")]
|
|
[Min(0f)]
|
|
public float EffectDuration = 3f;
|
|
|
|
public override bool ServerCast(ulong clientId, Vector3 targetPoint)
|
|
{
|
|
PlayerSlot owner = PlayerMatchState.SlotForClient(clientId);
|
|
|
|
var zoneObject = new GameObject("SlowZone (server)");
|
|
zoneObject.AddComponent<SlowZoneRuntime>().Initialize(
|
|
targetPoint, Mathf.Max(Radius, 0.01f), SlowFactor, EffectDuration,
|
|
enemyLayerMask, owner);
|
|
|
|
// Always succeeds — placing the zone starts the cooldown even if no enemy is
|
|
// standing in it yet, since it keeps slowing whoever walks in for EffectDuration.
|
|
return true;
|
|
}
|
|
|
|
public override void ClientSpawnVfx(Vector3 targetPoint)
|
|
{
|
|
if (areaVfxPrefab != null)
|
|
{
|
|
var instance = Instantiate(areaVfxPrefab, targetPoint, Quaternion.identity);
|
|
instance.transform.localScale *= Mathf.Max(Radius, 0.01f);
|
|
Destroy(instance, EffectDuration);
|
|
}
|
|
}
|
|
|
|
public override void ClientPlayImpact(Vector3 targetPoint)
|
|
{
|
|
// Instant spell (ImpactDelay = 0), so this fires on cast alongside ClientSpawnVfx.
|
|
if (areaSound.clip != null)
|
|
AudioManager.Instance?.Play(areaSound.clip, AudioCategory.Combat,
|
|
areaSound.RandomPitch(), areaSound.volume);
|
|
}
|
|
}
|
|
}
|