using Godot; using System.Collections.Generic; using System.Linq; using Rokojori.Extensions; namespace Rokojori; [Tool] [GlobalClass] public partial class FightManager:Node { [Export] public int maxEngaged = 3; [Export] public int maxAttacking = 1; List _slots = new List(); Dictionary _lastAttackTime = new Dictionary(); ulong _cachedFrame = ulong.MaxValue; List _cachedEngaged = new List(); List _cachedAttackers = new List(); public static FightManager Get() { return Unique.Get(); } public int registeredCount => _slots.Count; public int engagedCount => EngagedSlots().Count; public int attackingCount => AttackingSlots().Count; public void Register( FightSlot slot ) { if ( slot == null || _slots.Contains( slot ) ) { return; } _slots.Add( slot ); } public void Unregister( FightSlot slot ) { _slots.Remove( slot ); _lastAttackTime.Remove( slot ); } List EngagedSlots() { RefreshFrameCache(); return _cachedEngaged; } List AttackingSlots() { RefreshFrameCache(); return _cachedAttackers; } void RefreshFrameCache() { var frame = Engine.GetPhysicsFrames(); if ( frame == _cachedFrame ) { return; } _cachedFrame = frame; _cachedEngaged = _slots .OrderByDescending( s => s.priority ) .Take( Mathf.Max( 0, maxEngaged ) ) .ToList(); var now = Time.GetTicksMsec() / 1000.0; _cachedAttackers = _cachedEngaged .OrderByDescending( s => s.priority ) .ThenBy( s => _lastAttackTime.TryGetValue( s, out var t ) ? t : -1 ) .Take( Mathf.Max( 0, maxAttacking ) ) .ToList(); _cachedAttackers.ForEach( s => _lastAttackTime[ s ] = now ); } public bool IsEngaged( FightSlot slot ) { return slot != null && EngagedSlots().Contains( slot ); } public bool HasAttackPermission( FightSlot slot ) { return slot != null && AttackingSlots().Contains( slot ); } public bool IsAnyOtherAttacking( FightSlot self ) { return AttackingSlots().Any( s => s != self ); } }