using System.Collections.Generic; using UnityEngine; using Colosseum.Enemy; using Colosseum.Passives; using Colosseum.Skills; namespace Colosseum.Combat { /// /// 힐, 보호막, 버프 등 비공격 스킬에서 위협을 생성할 때 사용하는 공통 유틸리티입니다. /// 시전자 주변의 적을 탐색하고, 위협 배율 체인을 적용하여 위협을 누적합니다. /// public static class ThreatUtility { private const float DefaultThreatRadius = 50f; private static readonly Collider[] overlapBuffer = new Collider[256]; private static readonly HashSet processedEnemies = new HashSet(); /// /// 시전자 주변의 적들에게 위협을 분배합니다. /// 위협 공식: baseThreat × (Gem 배율 × ThreatController 배율 × Passive 배율) /// /// 시전자 (위협을 얻을 주체) /// 배율 적용 전 기본 위협 수치 /// 위협을 생성할 반경 (기본 50m) public static void GenerateThreatOnNearbyEnemies(GameObject caster, float baseThreat, float radius = DefaultThreatRadius) { if (caster == null || baseThreat <= 0f) return; float multiplier = ResolveThreatMultiplier(caster); float finalThreat = baseThreat * multiplier; processedEnemies.Clear(); int hitCount = Physics.OverlapSphereNonAlloc( caster.transform.position, Mathf.Max(radius, 1f), overlapBuffer); for (int i = 0; i < hitCount; i++) { Collider hit = overlapBuffer[i]; if (hit == null) continue; EnemyBase enemy = hit.GetComponentInParent(); if (enemy == null || processedEnemies.Contains(enemy)) continue; if (!enemy.UseThreatSystem || enemy.IsDead) continue; // 같은 팀(적이 아님)은 제외 if (Colosseum.Team.IsSameTeam(caster, enemy.gameObject)) continue; processedEnemies.Add(enemy); enemy.AddThreat(caster, finalThreat); } if (processedEnemies.Count > 0) { CombatBalanceTracker.RecordThreat(caster, finalThreat); } } /// /// 시전자의 전체 위협 배율을 계산합니다. /// 체인: SkillGem 배율 × ThreatController 배율 × Passive 배율 /// public static float ResolveThreatMultiplier(GameObject source) { if (source == null) return 1f; float gemMultiplier = SkillRuntimeModifierUtility.GetThreatMultiplier(source); ThreatController threatController = source.GetComponent(); float runtimeMultiplier = threatController != null ? Mathf.Max(0f, threatController.CurrentThreatMultiplier) : 1f; float passiveMultiplier = PassiveRuntimeModifierUtility.GetThreatGeneratedMultiplier(source); return gemMultiplier * runtimeMultiplier * passiveMultiplier; } } }