We've got enemies and movement!!
This commit is contained in:
parent
42ee0bf65d
commit
3287e8ea43
26 changed files with 1409 additions and 161 deletions
|
|
@ -17,45 +17,42 @@ namespace TD.Gameplay
|
|||
/// <item>Poison — damage per second applied as a DoT tick</item>
|
||||
/// <item>Others — unused (magnitude = 0)</item>
|
||||
/// </list>
|
||||
/// <b>SourceOwner</b> carries the <see cref="PlayerSlot"/> of the tower that
|
||||
/// applied this effect so DoT kill credit goes to the right player.
|
||||
/// </remarks>
|
||||
public struct StatusEffect
|
||||
{
|
||||
public DamageType Source;
|
||||
public float Magnitude;
|
||||
public float RemainingDuration;
|
||||
public PlayerSlot SourceOwner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks and ticks lingering status effects (slow, burn, poison) on an enemy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Authority:</b> The active-effect list is server-local (not replicated).
|
||||
/// Only the derived <see cref="speedMultiplier"/> NetworkVariable is replicated,
|
||||
/// so <c>EnemyMovement</c> (Phase 1.5/1.6) can scale speed on all peers without
|
||||
/// re-broadcasting the full effect list.
|
||||
/// <b>Authority:</b> The active-effect list is server-local. Only the derived
|
||||
/// <see cref="speedMultiplier"/> NetworkVariable is replicated so
|
||||
/// <c>EnemyMovement</c> can scale speed on all peers.
|
||||
///
|
||||
/// <b>Stacking rule:</b> A second hit of the same <see cref="DamageType"/> refreshes
|
||||
/// the duration and magnitude rather than stacking. Cross-type interactions (e.g.
|
||||
/// Cold + Fire) are not yet implemented; <see cref="HasEffect"/> is the hook for
|
||||
/// when that design is worked out.
|
||||
/// <b>Stacking rule:</b> Re-hitting with the same <see cref="DamageType"/>
|
||||
/// refreshes duration and magnitude; it does not stack. Cross-type interactions
|
||||
/// are not implemented; <see cref="HasEffect"/> is the hook for future work.
|
||||
///
|
||||
/// <b>DoT damage</b> is applied by calling <see cref="EnemyHealth.TakeDamage"/> each
|
||||
/// tick so resistance lookups remain in one place.
|
||||
/// <b>DoT damage</b> calls <see cref="EnemyHealth.TakeDamage"/> with the original
|
||||
/// <see cref="StatusEffect.SourceOwner"/> so kill attribution stays correct.
|
||||
/// </remarks>
|
||||
[RequireComponent(typeof(NetworkObject))]
|
||||
public class EnemyStatus : NetworkBehaviour
|
||||
{
|
||||
// Replicated so EnemyMovement can read it on all clients without
|
||||
// knowing anything about which effects are active.
|
||||
private readonly NetworkVariable<float> speedMultiplier = new NetworkVariable<float>(
|
||||
1f,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
// Server-local — only the derived speedMultiplier NV crosses the wire.
|
||||
private readonly List<StatusEffect> activeEffects = new List<StatusEffect>();
|
||||
|
||||
// Resolved once; used by Tick for DoT TakeDamage calls.
|
||||
private EnemyHealth health;
|
||||
|
||||
// ----- NGO lifecycle -----------------------------------------------
|
||||
|
|
@ -67,10 +64,10 @@ namespace TD.Gameplay
|
|||
|
||||
// ----- Public API --------------------------------------------------
|
||||
|
||||
/// <summary>Current speed fraction (0–1). 1 = full speed, 0.5 = half speed, etc.</summary>
|
||||
/// <summary>Current speed fraction (0–1). 1 = full speed, 0.5 = half speed.</summary>
|
||||
public float GetSpeedMultiplier() => speedMultiplier.Value;
|
||||
|
||||
/// <summary>True if an effect of the given type is currently active on this enemy.</summary>
|
||||
/// <summary>True if an effect of the given type is currently active.</summary>
|
||||
public bool HasEffect(DamageType type)
|
||||
{
|
||||
for (int i = 0; i < activeEffects.Count; i++)
|
||||
|
|
@ -80,9 +77,12 @@ namespace TD.Gameplay
|
|||
|
||||
/// <summary>
|
||||
/// Applies or refreshes a lingering effect. Server-only; no-op on clients.
|
||||
/// Re-hitting with the same damage type refreshes duration and magnitude.
|
||||
/// Re-hitting with the same source type refreshes duration and magnitude.
|
||||
/// <paramref name="owner"/> is the tower's <see cref="PlayerSlot"/> — carried
|
||||
/// on the effect so DoT ticks credit the right player on a kill.
|
||||
/// </summary>
|
||||
public void ApplyEffect(DamageType source, float magnitude, float duration)
|
||||
public void ApplyEffect(DamageType source, float magnitude, float duration,
|
||||
PlayerSlot owner)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
|
||||
|
|
@ -91,9 +91,10 @@ namespace TD.Gameplay
|
|||
if (activeEffects[i].Source != source) continue;
|
||||
|
||||
var e = activeEffects[i];
|
||||
e.Magnitude = magnitude;
|
||||
e.RemainingDuration = duration;
|
||||
activeEffects[i] = e;
|
||||
e.Magnitude = magnitude;
|
||||
e.RemainingDuration = duration;
|
||||
e.SourceOwner = owner;
|
||||
activeEffects[i] = e;
|
||||
RecalculateSpeedMultiplier();
|
||||
return;
|
||||
}
|
||||
|
|
@ -103,6 +104,7 @@ namespace TD.Gameplay
|
|||
Source = source,
|
||||
Magnitude = magnitude,
|
||||
RemainingDuration = duration,
|
||||
SourceOwner = owner,
|
||||
});
|
||||
RecalculateSpeedMultiplier();
|
||||
}
|
||||
|
|
@ -123,11 +125,11 @@ namespace TD.Gameplay
|
|||
{
|
||||
var e = activeEffects[i];
|
||||
|
||||
// Apply DoT for Fire and Poison.
|
||||
if (e.Source == DamageType.Fire || e.Source == DamageType.Poison)
|
||||
// DoT tick — pass the original source owner so kill credit is correct.
|
||||
if ((e.Source == DamageType.Fire || e.Source == DamageType.Poison)
|
||||
&& health != null && !health.IsDead)
|
||||
{
|
||||
if (health != null && !health.IsDead)
|
||||
health.TakeDamage(e.Magnitude * dt, e.Source);
|
||||
health.TakeDamage(e.Magnitude * dt, e.Source, e.SourceOwner);
|
||||
}
|
||||
|
||||
e.RemainingDuration -= dt;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue