Implement passive relics and six-family defense towers

This commit is contained in:
2026-09-23 18:11:38 +09:00
parent 5d11288a6f
commit c94cbda1e6
21 changed files with 2882 additions and 152 deletions
+38 -1
View File
@@ -32,6 +32,8 @@ namespace BumpCombat.Player
private float hurtMovementLockedUntil;
private float guardUntil;
private float guardCooldownUntil;
private float shieldAmount;
private float shieldExpiresAt;
private int nextGuardActivationIdentity;
private int activeGuardActivationIdentity;
private bool activeGuardHasBlockedAttack;
@@ -41,12 +43,14 @@ namespace BumpCombat.Player
public event Action<Vector2, float> OnDamaged;
/// <summary>Raised only for positive health actually lost after mitigation and lethal clamping.</summary>
public event Action<float> OnDamageTaken;
public event Action<float> OnEnemyDamageTaken;
public event Action<int> OnGuardAttackBlocked;
public event Action<Vector2> OnGuardImpact;
public event Action OnDied;
public float MaxHealth => playerStats.MaxHealth;
public float CurrentHealth { get; private set; }
public float CurrentShield => Time.time < shieldExpiresAt ? shieldAmount : 0f;
public static float DefaultGuardCooldown =>
GameplayConstants.Current.Player.GuardCooldownDuration;
public static float DefaultGuardDuration =>
@@ -134,6 +138,10 @@ namespace BumpCombat.Player
private void Update()
{
RefreshRunManagerSubscription();
if (shieldAmount > 0f && Time.time >= shieldExpiresAt)
{
shieldAmount = 0f;
}
}
private void HandleInputSystemUpdate()
@@ -173,7 +181,7 @@ namespace BumpCombat.Player
return true;
}
public bool TryTakeDamage(float damage, Vector2 knockbackDirection, float knockbackDistance)
public bool TryTakeDamage(float damage, Vector2 knockbackDirection, float knockbackDistance, bool fromEnemyAttack = true)
{
if (CurrentHealth <= 0f)
{
@@ -212,6 +220,18 @@ namespace BumpCombat.Player
return false;
}
if (CurrentShield > 0f)
{
float absorbed = Mathf.Min(shieldAmount, damageTaken);
shieldAmount -= absorbed;
damageTaken -= absorbed;
if (damageTaken <= 0f)
{
invulnerableUntil = Time.time + InvulnerabilityDuration;
return true;
}
}
float healthBefore = CurrentHealth;
CurrentHealth = Mathf.Max(0f, CurrentHealth - damageTaken);
@@ -232,6 +252,7 @@ namespace BumpCombat.Player
if (actualDamageTaken > 0f)
{
OnDamageTaken?.Invoke(actualDamageTaken);
if (fromEnemyAttack) OnEnemyDamageTaken?.Invoke(actualDamageTaken);
}
if (CurrentHealth <= 0f)
@@ -277,6 +298,8 @@ namespace BumpCombat.Player
}
CurrentHealth = MaxHealth;
shieldAmount = 0f;
shieldExpiresAt = 0f;
invulnerableUntil = Time.time + Mathf.Max(0f, invulnerabilitySeconds);
hurtMovementLockedUntil = 0f;
guardUntil = 0f;
@@ -289,6 +312,18 @@ namespace BumpCombat.Player
return true;
}
public bool GrantPassiveRelicShield(float amount, float duration)
{
if (amount <= 0f || duration <= 0f || CurrentHealth <= 0f)
{
return false;
}
shieldAmount = amount;
shieldExpiresAt = Time.time + duration;
return true;
}
public void Heal(float amount)
{
if (amount <= 0f || CurrentHealth <= 0f)
@@ -325,6 +360,8 @@ namespace BumpCombat.Player
private void HandleRunStarted()
{
shieldAmount = 0f;
shieldExpiresAt = 0f;
guardUntil = 0f;
guardCooldownUntil = 0f;
nextGuardActivationIdentity = 0;