OMRTacticalMap.cs
using Sandbox;
using System;

[Flags]
public enum OMRTacticalRegionType
{
	None = 0,
	Open = 1 << 0,
	Tight = 1 << 1,
	LongLane = 1 << 2,
	CloseLane = 1 << 3,
	Crossing = 1 << 4,
	HighRisk = 1 << 5
}

[Flags]
public enum OMRTacticalPointType
{
	None = 0,
	Cover = 1 << 0,
	Vantage = 1 << 1,
	Ambush = 1 << 2,
	SearchAnchor = 1 << 3,
	FlankEntry = 1 << 4,
	Choke = 1 << 5
}

/// <summary>
/// Optional semantic hint for BOT 7C tactical reasoning.
///
/// The bot does not require these regions: geometry, NavMesh and traces are the
/// default source of truth. Regions are deliberately broad authoring hints for
/// information geometry alone cannot explain cheaply, such as a deliberately
/// dangerous crossing or a lane intended for long-range play.
/// </summary>
[Title( "OMR Tactical Region" )]
[Category( "One More Round/Bots" )]
[Icon( "map" )]
public sealed class OMRTacticalRegion : Component
{
	[Property, Group( "Tactical" )]
	public OMRTacticalRegionType Type { get; set; } = OMRTacticalRegionType.None;

	[Property, Group( "Tactical" ), Range( 48f, 640f )]
	public float Radius { get; set; } = 180f;

	[Property, Group( "Tactical" ), Range( 0f, 2f )]
	public float Weight { get; set; } = 1f;

	public bool Contains( Vector3 worldPosition )
	{
		float radius = MathF.Max( 24f, Radius );
		return ( worldPosition - WorldPosition ).WithZ( 0f ).Length <= radius;
	}
}

/// <summary>
/// Optional authored tactical anchor for BOT 7C.
///
/// These points complement procedural queries. They never force the bot to use
/// a position: the normal route, exposure, danger-memory, range and escape
/// evaluation still decides whether the point is sensible in the current fight.
/// </summary>
[Title( "OMR Tactical Point" )]
[Category( "One More Round/Bots" )]
[Icon( "location_on" )]
public sealed class OMRTacticalPoint : Component
{
	[Property, Group( "Tactical" )]
	public OMRTacticalPointType Type { get; set; } = OMRTacticalPointType.None;

	[Property, Group( "Tactical" ), Range( 0f, 2f )]
	public float Weight { get; set; } = 1f;

	[Property, Group( "Tactical" ), Range( 64f, 1200f )]
	public float InfluenceRadius { get; set; } = 480f;
}