using System.Collections.Generic; using BumpCombat.Constants; using BumpCombat.Core; using UnityEngine; namespace BumpCombat.Enemies { public sealed class AttackTokenManager : MonoBehaviour { private int maxMeleeAttackers => GameplayConstants.Current.Enemies.MaxMeleeAttackers; private int maxRangedAttackers => GameplayConstants.Current.Enemies.MaxRangedAttackers; private int maxEarlyCrowdAttackers => GameplayConstants.Current.Enemies.MaxEarlyCrowdAttackers; private int maxLateCrowdAttackers => GameplayConstants.Current.Enemies.MaxLateCrowdAttackers; private float crowdAttackExpansionTime => GameplayConstants.Current.Enemies.CrowdAttackExpansionTime; private float crowdAttackGrantInterval => GameplayConstants.Current.Enemies.CrowdAttackGrantInterval; private readonly HashSet meleeOwners = new(); private readonly HashSet rangedOwners = new(); private readonly HashSet crowdOwners = new(); private float nextCrowdGrantTime; public static AttackTokenManager Instance { get; private set; } public int ActiveCrowdAttackers => crowdOwners.Count; private void Awake() { Instance = this; } private void OnDestroy() { if (Instance == this) { Instance = null; } } public bool TryAcquire(EnemyController enemy) { if (enemy.IsEventEnemy) { return true; } if (enemy.IsCrowd) { return TryAcquireCrowd(enemy); } HashSet owners = enemy.Definition.IsRanged ? rangedOwners : meleeOwners; int limit = enemy.Definition.IsRanged ? maxRangedAttackers : maxMeleeAttackers; int id = enemy.GetInstanceID(); if (owners.Contains(id)) { return true; } return owners.Count < limit && owners.Add(id); } public void Release(EnemyController enemy) { int id = enemy.GetInstanceID(); meleeOwners.Remove(id); rangedOwners.Remove(id); crowdOwners.Remove(id); } public static int GetCrowdAttackLimit( float elapsedTime, int earlyLimit, int lateLimit, float expansionTime) { return elapsedTime < expansionTime ? earlyLimit : lateLimit; } private bool TryAcquireCrowd(EnemyController enemy) { int id = enemy.GetInstanceID(); if (crowdOwners.Contains(id)) { return true; } float elapsedTime = RunManager.Instance?.ProgressionTime ?? 0f; int limit = GetCrowdAttackLimit( elapsedTime, maxEarlyCrowdAttackers, maxLateCrowdAttackers, crowdAttackExpansionTime); if (crowdOwners.Count >= limit || Time.time < nextCrowdGrantTime) { return false; } crowdOwners.Add(id); nextCrowdGrantTime = Time.time + crowdAttackGrantInterval; return true; } } }