UI/OMRCrosshairHUD.razor
@using System;
@using System.Linq;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
<root>
@if ( ShouldShowCrosshair )
{
<div
class="omr-crosshair"
style="@CrosshairRootStyle"
>
<div
class="omr-crosshair-line horizontal"
style="@CrosshairLeftStyle"
></div>
<div
class="omr-crosshair-line horizontal"
style="@CrosshairRightStyle"
></div>
<div
class="omr-crosshair-line vertical"
style="@CrosshairUpStyle"
></div>
<div
class="omr-crosshair-line vertical"
style="@CrosshairDownStyle"
></div>
</div>
}
</root>
@code
{
private readonly OMRSceneReferences _sceneReferences = new();
private OMRSceneReferences SceneReferences
{
get { _sceneReferences.Refresh( Scene ); return _sceneReferences; }
}
private PlayerState LocalPlayerState => SceneReferences.LocalPlayer;
private BaseInventoryComponent LocalInventory => SceneReferences.LocalInventory;
private OneMoreRoundWeapon LocalWeapon =>
LocalInventory?
.ActiveItem as OneMoreRoundWeapon;
private RoundManager LocalRoundManager => SceneReferences.Rounds;
/// <summary>
/// Crosshair visibility follows actual gameplay context rather than only
/// weapon state.
///
/// Visible:
/// - Sandbox gameplay
/// - Online warmup
/// - Active Fighting phase
///
/// Hidden:
/// - pause/settings
/// - pre-match lobby/ready screen
/// - countdown
/// - round end
/// - winner/modifier decisions
/// - match end/menu
/// </summary>
private bool IsCrosshairGameplayContext
{
get
{
if ( PauseMenu.IsAnyPauseOpen )
return false;
RoundManager roundManager =
LocalRoundManager;
if ( roundManager is null )
return false;
return roundManager.Mode switch
{
SessionMode.Sandbox =>
true,
SessionMode.Match =>
roundManager.Phase ==
RoundPhase.Fighting,
SessionMode.Menu =>
LocalPlayerState?.
PreMatchState ==
PreMatchPlayerState.Warmup,
_ =>
false
};
}
}
private bool ShouldShowCrosshair =>
IsCrosshairGameplayContext &&
LocalWeapon is not null &&
LocalWeapon.IsValid &&
LocalWeapon.ShouldShowScreenCrosshair;
private Vector2 Gap =>
LocalWeapon?
.ScreenCrosshairGap ??
Vector2.Zero;
private float LineLength =>
MathF.Max(
LocalWeapon?
.CrosshairLineLength ??
0f,
0f
);
private float LineWidth =>
MathF.Max(
LocalWeapon?
.CrosshairLineWidth ??
0.5f,
0.5f
);
private string CrosshairRootStyle
{
get
{
Color color =
LocalWeapon?
.CrosshairColor ??
Color.White;
return $"color: {color.Rgba};";
}
}
private string CrosshairLeftStyle =>
$"width: {Css( LineLength )}px; " +
$"height: {Css( LineWidth )}px; " +
$"left: {Css( -(Gap.x + LineLength) )}px; " +
$"top: {Css( -LineWidth * 0.5f )}px;";
private string CrosshairRightStyle =>
$"width: {Css( LineLength )}px; " +
$"height: {Css( LineWidth )}px; " +
$"left: {Css( Gap.x )}px; " +
$"top: {Css( -LineWidth * 0.5f )}px;";
private string CrosshairUpStyle =>
$"width: {Css( LineWidth )}px; " +
$"height: {Css( LineLength )}px; " +
$"left: {Css( -LineWidth * 0.5f )}px; " +
$"top: {Css( -(Gap.y + LineLength) )}px;";
private string CrosshairDownStyle =>
$"width: {Css( LineWidth )}px; " +
$"height: {Css( LineLength )}px; " +
$"left: {Css( -LineWidth * 0.5f )}px; " +
$"top: {Css( Gap.y )}px;";
private static string Css(
float value
)
{
return value.ToString(
"0.###",
System.Globalization.CultureInfo.InvariantCulture
);
}
protected override int BuildHash()
{
OneMoreRoundWeapon weapon =
LocalWeapon;
RoundManager roundManager =
LocalRoundManager;
PlayerState player =
LocalPlayerState;
HashCode hash =
new();
//
// UI context belongs in the hash too. Without this, opening Pause or
// entering a decision phase can change ShouldShowCrosshair without
// giving Razor a weapon-property change to rebuild from.
//
hash.Add(
PauseMenu.IsAnyPauseOpen
);
hash.Add(
roundManager?.
Mode ??
SessionMode.Menu
);
hash.Add(
roundManager?.
Phase ??
RoundPhase.Waiting
);
hash.Add(
player?.
PreMatchState ??
PreMatchPlayerState.Lobby
);
if (
weapon is null ||
!weapon.IsValid
)
{
return hash.ToHashCode();
}
Vector2 gap =
weapon.ScreenCrosshairGap;
hash.Add(
weapon.IsAiming
);
hash.Add(
gap.x
);
hash.Add(
gap.y
);
hash.Add(
weapon.CrosshairLineLength
);
hash.Add(
weapon.CrosshairLineWidth
);
hash.Add(
weapon.CrosshairColor
);
return hash.ToHashCode();
}
}