Internal/RadialHitShape.cs
using System;
using Sandbox;

namespace HitShapes;

internal sealed class RadialHitShape : IHitShape
{
    readonly int _slots;
    readonly float _innerRatio;
    readonly float _outerRatio;
    readonly float _wedgeSize;
    readonly float _halfWedge;

    public RadialHitShape(int slots, float innerRatio, float outerRatio)
    {
        _slots = slots;
        _innerRatio = innerRatio;
        _outerRatio = outerRatio;
        _wedgeSize = MathF.Tau / slots;
        _halfWedge = _wedgeSize * 0.5f;
    }

    public int SlotCount => _slots;

    public int? Resolve(Vector2 local, Vector2 size)
    {
        var dx = local.x - size.x * 0.5f;
        var dy = local.y - size.y * 0.5f;
        var dist2 = dx * dx + dy * dy;

        var radius = MathF.Min(size.x, size.y) * 0.5f;
        var outerR = radius * _outerRatio;
        var innerR = radius * _innerRatio;
        if (dist2 < innerR * innerR || dist2 > outerR * outerR) return null;

        var angle = MathF.Atan2(dy, dx) + MathF.PI * 0.5f + _halfWedge;
        if (angle < 0) angle += MathF.Tau;
        if (angle >= MathF.Tau) angle -= MathF.Tau;
        return (int)(angle / _wedgeSize) % _slots;
    }
}