264 lines
7.8 KiB
C#
264 lines
7.8 KiB
C#
using System.Collections.Generic;
|
|
using BumpCombat.Combat;
|
|
using BumpCombat.Core;
|
|
using BumpCombat.Constants;
|
|
using BumpCombat.Enemies;
|
|
using UnityEngine;
|
|
|
|
namespace BumpCombat.Player
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public sealed class PlayerStats : CharacterModel
|
|
{
|
|
private const string PressureStreakSourceId = "player.pressure-streak";
|
|
private readonly HashSet<int> pressureStreakProcessedEnemyLifetimes = new();
|
|
private RunManager subscribedRunManager;
|
|
private PlayerHealth playerHealth;
|
|
private float pressureStreakExpiresAt = -1f;
|
|
private float pressureStreakLastKillAt = -1f;
|
|
|
|
public override float MoveSpeed => Evaluate(
|
|
CharacterStat.MoveSpeed,
|
|
GameplayConstants.Current.Player.BaseMoveSpeed);
|
|
public override float MaxHealth => Evaluate(
|
|
CharacterStat.MaxHealth,
|
|
GameplayConstants.Current.Player.BaseMaxHealth);
|
|
|
|
public int PressureStreakKillCount { get; private set; }
|
|
public int PressureStreakKillTarget => Mathf.Max(
|
|
1,
|
|
GameplayConstants.Current.Player.PressureStreakKillTarget);
|
|
public float PressureStreakRemaining => Mathf.Max(
|
|
0f,
|
|
pressureStreakExpiresAt - GetCombatTime());
|
|
public bool IsPressureStreakWindowActive => PressureStreakRemaining > 0f;
|
|
public bool IsPressureStreakActive => IsPressureStreakWindowActive
|
|
&& GetStackCount(
|
|
PressureStreakSourceId,
|
|
CharacterStat.MoveSpeed) > 0;
|
|
|
|
private void OnEnable()
|
|
{
|
|
playerHealth = GetComponent<PlayerHealth>();
|
|
if (playerHealth != null)
|
|
{
|
|
playerHealth.OnDied += HandlePlayerDied;
|
|
}
|
|
|
|
CombatEvents.OnValidHit += HandleValidHit;
|
|
RefreshRunManagerSubscription();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
RefreshRunManagerSubscription();
|
|
if (subscribedRunManager != null
|
|
&& !subscribedRunManager.IsTitleScreen
|
|
&& !subscribedRunManager.IsGameOver)
|
|
{
|
|
HandleRunStarted();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
RefreshRunManagerSubscription();
|
|
RefreshPressureStreak();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
CombatEvents.OnValidHit -= HandleValidHit;
|
|
if (playerHealth != null)
|
|
{
|
|
playerHealth.OnDied -= HandlePlayerDied;
|
|
}
|
|
|
|
UnsubscribeRunManager();
|
|
ResetPressureStreak();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
CombatEvents.OnValidHit -= HandleValidHit;
|
|
if (playerHealth != null)
|
|
{
|
|
playerHealth.OnDied -= HandlePlayerDied;
|
|
}
|
|
|
|
UnsubscribeRunManager();
|
|
}
|
|
|
|
public void RefreshPressureStreak()
|
|
{
|
|
float now = GetCombatTime();
|
|
PrunePressureStreak(now);
|
|
if (pressureStreakExpiresAt > 0f && now >= pressureStreakExpiresAt)
|
|
{
|
|
ClearPressureStreakBuff();
|
|
}
|
|
}
|
|
|
|
private void HandleValidHit(CombatHitResult result)
|
|
{
|
|
if (result.Attacker != gameObject
|
|
|| !result.IsOrdinaryBump
|
|
|| result.IsArtifactHit
|
|
|| result.Damage <= 0f
|
|
|| result.Target == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((playerHealth != null && playerHealth.CurrentHealth <= 0f)
|
|
|| RunManager.Instance?.IsGameOver == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EnemyController enemy = result.Target.GetComponent<EnemyController>()
|
|
?? result.Target.GetComponentInParent<EnemyController>();
|
|
if (enemy == null || !enemy.IsDead)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int lifetimeIdentity = enemy.SpawnLifetimeIdentity;
|
|
if (lifetimeIdentity <= 0)
|
|
{
|
|
lifetimeIdentity = enemy.GetInstanceID();
|
|
}
|
|
|
|
if (!pressureStreakProcessedEnemyLifetimes.Add(lifetimeIdentity))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float now = GetCombatTime();
|
|
RefreshPressureStreak();
|
|
if (pressureStreakLastKillAt < 0f
|
|
|| now - pressureStreakLastKillAt
|
|
> Mathf.Max(
|
|
0f,
|
|
GameplayConstants.Current.Player.PressureStreakWindowSeconds))
|
|
{
|
|
PressureStreakKillCount = 0;
|
|
}
|
|
|
|
PressureStreakKillCount++;
|
|
pressureStreakLastKillAt = now;
|
|
pressureStreakExpiresAt = now
|
|
+ Mathf.Max(
|
|
0f,
|
|
GameplayConstants.Current.Player.PressureStreakDuration);
|
|
|
|
if (PressureStreakKillCount >= PressureStreakKillTarget)
|
|
{
|
|
EnsurePressureStreakBuff();
|
|
}
|
|
else
|
|
{
|
|
RemoveModifiersFromSource(PressureStreakSourceId);
|
|
}
|
|
}
|
|
|
|
private void PrunePressureStreak(float now)
|
|
{
|
|
if (pressureStreakLastKillAt >= 0f
|
|
&& now - pressureStreakLastKillAt
|
|
> Mathf.Max(
|
|
0f,
|
|
GameplayConstants.Current.Player.PressureStreakWindowSeconds))
|
|
{
|
|
PressureStreakKillCount = 0;
|
|
pressureStreakLastKillAt = -1f;
|
|
ClearPressureStreakBuff();
|
|
}
|
|
}
|
|
|
|
private void EnsurePressureStreakBuff()
|
|
{
|
|
if (GetStackCount(
|
|
PressureStreakSourceId,
|
|
CharacterStat.MoveSpeed) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddModifier(new StatModifier(
|
|
PressureStreakSourceId,
|
|
CharacterStat.MoveSpeed,
|
|
ModifierOperation.Increased,
|
|
Mathf.Max(
|
|
0f,
|
|
GameplayConstants.Current.Player.PressureStreakMoveSpeedIncrease)));
|
|
}
|
|
|
|
private void ClearPressureStreakBuff()
|
|
{
|
|
RemoveModifiersFromSource(PressureStreakSourceId);
|
|
pressureStreakExpiresAt = -1f;
|
|
}
|
|
|
|
private void ResetPressureStreak()
|
|
{
|
|
pressureStreakProcessedEnemyLifetimes.Clear();
|
|
PressureStreakKillCount = 0;
|
|
pressureStreakLastKillAt = -1f;
|
|
ClearPressureStreakBuff();
|
|
}
|
|
|
|
private void HandlePlayerDied()
|
|
{
|
|
ResetPressureStreak();
|
|
}
|
|
|
|
private void HandleRunStarted()
|
|
{
|
|
ResetPressureStreak();
|
|
}
|
|
|
|
private void HandleGameOver()
|
|
{
|
|
ResetPressureStreak();
|
|
}
|
|
|
|
private float GetCombatTime()
|
|
{
|
|
RunManager current = RunManager.Instance;
|
|
return current != null ? current.ElapsedTime : Time.time;
|
|
}
|
|
|
|
private void RefreshRunManagerSubscription()
|
|
{
|
|
RunManager current = RunManager.Instance;
|
|
if (subscribedRunManager == current)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UnsubscribeRunManager();
|
|
subscribedRunManager = current;
|
|
if (subscribedRunManager == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
subscribedRunManager.OnRunStarted += HandleRunStarted;
|
|
subscribedRunManager.OnGameOver += HandleGameOver;
|
|
}
|
|
|
|
private void UnsubscribeRunManager()
|
|
{
|
|
if (subscribedRunManager == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
subscribedRunManager.OnRunStarted -= HandleRunStarted;
|
|
subscribedRunManager.OnGameOver -= HandleGameOver;
|
|
subscribedRunManager = null;
|
|
}
|
|
}
|
|
}
|