UI/ReplayReactionOverlay.razor
@using System
@using Sandbox
@using Sandbox.UI
@inherits Panel
@namespace BlockParty
@attribute [StyleSheet( "ReplayReactionOverlay.razor.scss" )]
<root>
@if ( Visible && Manager.CurrentReplayReactions is { } reactions )
{
@if ( Manager.IsPlacingReaction && Manager.CanReact )
{
<div class="placement-catcher" style=@PlayfieldStyle() onclick=@(() => Manager.PlaceReaction())></div>
}
@for ( int order = 0; order < reactions.OrderedEntries.Count; order++ )
{
var (steamId, reaction) = reactions.OrderedEntries[order];
@if ( reaction.IsVisibleAt( Manager.ReplayFrame ) )
{
var effect = ReplayReactionEffects.Find( reaction.Effect );
var layout = ReplayReactionDisplay.At( effect, new Vector2( reaction.X, reaction.Y ), Manager.ReplayFrame - reaction.Frame );
<div @key="steamId" class="reaction @(Manager.IsPlacingReaction ? "passive" : "")" style=@PairStyle( layout, order )>
<div class="avatar" style=@AvatarStyle() onmouseover=@Tip( steamId )></div>
<div class="effect" style=@EffectStyle( effect ) onmouseover=@Tip( steamId )></div>
</div>
}
}
@if ( Manager.IsPlacingReaction && Manager.CanReact && Manager.ReactionCursorPosition( out var cursor ) )
{
var effect = ReplayReactionEffects.Find( Manager.ReactionEffect );
var layout = ReplayReactionDisplay.At( effect, cursor, 0, preview: true );
<div class="reaction passive" style=@PairStyle( layout, reactions.OrderedEntries.Count )>
<div class="avatar" style=@AvatarStyle()></div>
<div class="effect" style=@EffectStyle( effect )></div>
</div>
}
}
</root>
@code
{
public GameStage Stage { get; set; }
private GameManager Manager => GameManager.Instance;
private bool Visible => ReplayReactionDisplay.IsVisible( Manager, Stage );
private Panel _hovered;
private long _hoveredId;
private Action<PanelEvent> Tip( long id ) => e => { _hovered = e.This; _hoveredId = id; };
public override void Tick()
{
base.Tick();
if ( Visible ) Stage.EnsureReactionSprites();
bool hasReaction = Visible && !Manager.IsPlacingReaction && _hovered.IsValid() && _hovered.HasHovered
&& Manager.CurrentReplayReactions?.Entries.TryGetValue( _hoveredId, out var reaction ) == true
&& reaction.IsVisibleAt( Manager.ReplayFrame );
if ( hasReaction ) Stage?.ShowReactionTooltip( Manager.CurrentReplayReactions.NameFor( _hoveredId ) );
else Stage?.ReactionTooltip?.Hide();
}
private float PixelScale => Screen.Height * ScaleFromScreen / Manager.Camera.OrthographicHeight;
private string PlayfieldStyle()
{
var screen = Manager.Camera.PointToScreenNormal( new Vector3( Arena.WALL_SIZE, Arena.HEIGHT - Arena.WALL_SIZE, 0f ) );
return FormattableString.Invariant( $"left:{screen.x * Screen.Width * ScaleFromScreen:0.###}px;top:{screen.y * Screen.Height * ScaleFromScreen:0.###}px;width:{(Arena.WIDTH - 2 * Arena.WALL_SIZE) * PixelScale:0.###}px;height:{(Arena.HEIGHT - 2 * Arena.WALL_SIZE) * PixelScale:0.###}px;" );
}
private string PairStyle( ReplayReactionDisplay.Layout layout, int order )
{
var screen = Manager.Camera.PointToScreenNormal( new Vector3( layout.Left, layout.Top, 0f ) );
return FormattableString.Invariant( $"left:{screen.x * Screen.Width * ScaleFromScreen:0.###}px;top:{screen.y * Screen.Height * ScaleFromScreen:0.###}px;width:{layout.Width * PixelScale:0.###}px;height:{layout.Height * PixelScale:0.###}px;opacity:{layout.Alpha:0.###};gap:{ReplayReactionDisplay.Gap * PixelScale:0.###}px;z-index:{order + 1};" );
}
private string EffectStyle( ReplayReactionEffect effect ) => FormattableString.Invariant(
$"width:{effect.Width * PixelScale:0.###}px;height:{effect.Height * PixelScale:0.###}px;" );
private string AvatarStyle() => FormattableString.Invariant(
$"width:{ReplayReactionDisplay.AvatarSize * PixelScale:0.###}px;height:{ReplayReactionDisplay.AvatarSize * PixelScale:0.###}px;" );
protected override int BuildHash() => HashCode.Combine( Visible, Manager?.ReplayFrame ?? 0,
Manager?.CurrentReplayReactions?.Revision ?? 0, Manager?.IsPlacingReaction ?? false,
HashCode.Combine( Manager?.ReactionEffect, Manager?.CanReact ?? false ), Manager?.IsPlacingReaction == true ? Mouse.Position : Vector2.Zero,
Screen.Size, Manager?.Camera?.OrthographicHeight ?? 0f );
}