The loot/search panel for a roleplay gamemode, opened when searching an unconscious or cuffed player. Lists their cash and pocket items with per-item take buttons and a take-all button, and switches between civilian take requests and police seizure requests. Closes on Escape or when the target moves out of reach.
@using Sandbox;
@using Sandbox.UI;
@namespace HorizonRP
@inherits PanelComponent
@*
La fouille d'un inconscient (E maintenu 3 s, RoleplayPlayer.Death.cs) : son argent liquide et
ses poches, à prendre une par une ou tout d'un coup. Créée par le HUD sur chaque machine.
L'hôte revérifie tout (Money/Cash.cs : toujours inconscient, à côté, la place dans nos poches).
En mode police (menu F6 d'un agent en service, Police/PoliceActions.cs) : la fouille d'un
menotté (ou d'un inconscient), « Saisir » au lieu de « Prendre », chaque saisie journalisée.
*@
<root>
@if ( IsOpen && Target.IsValid() && Me is not null )
{
<div class="search-backdrop">
<div class="search-panel">
<div class="search-head">
<div class="search-icon"><i>search</i></div>
<div class="search-titles">
<div class="search-title">@Title</div>
<div class="search-sub">@Sub</div>
</div>
<div class="search-close" onclick=@(() => Close())><i>close</i></div>
</div>
<div class="search-row cash">
<div class="row-pic" style="background-image: url( ui/billets.png )"></div>
<div class="row-name">@($"Argent liquide · {(Format.Money( Target.Wallet ))}")</div>
<div class="btn small @(Target.Wallet > 0 ? "" : "off")" onclick=@(() => TakeCash())>@TakeLabel</div>
</div>
@if ( Pockets.Count == 0 )
{
<div class="search-empty">Rien dans ses poches.</div>
}
@foreach ( var slot in Pockets )
{
var index = slot.Slot;
<div class="search-row">
@if ( slot.Definition?.Picture is { } picture )
{
<div class="row-pic" style="background-image: url( @picture )"></div>
}
else
{
<div class="row-icon"><i>@(slot.Definition?.Icon ?? "inventory_2")</i></div>
}
<div class="row-name">@(slot.Count > 1 ? $"{slot.Definition?.Name} ×{slot.Count}" : slot.Definition?.Name)</div>
<div class="btn small" onclick=@(() => TakeItem( index ))>@TakeLabel</div>
</div>
}
<div class="btn primary @(Target.Wallet > 0 || Pockets.Count > 0 ? "" : "off")" onclick=@(() => TakeAll())><i>@(PoliceMode ? "gavel" : "back_hand")</i> @(PoliceMode ? "Tout saisir" : "Tout prendre")</div>
</div>
</div>
}
</root>
@code
{
static SearchMenu instance;
/// <summary>La fouille finie (E maintenu) : la fenêtre s'ouvre sur ce corps.</summary>
public static void Open( RoleplayPlayer target ) => instance?.Show( target, false );
/// <summary>La fouille de police (menu F6, l'hôte a vérifié) : sur un menotté ou un inconscient.</summary>
public static void OpenPolice( RoleplayPlayer target ) => instance?.Show( target, true );
/// <summary>Referme la fouille (un menotté ne fouille plus personne).</summary>
public static void CloseAll()
{
if ( instance is { IsOpen: true } menu )
menu.Close();
}
/// <summary>Fouille de police : saisies (PoliceActions) au lieu de prises (Cash).</summary>
bool PoliceMode { get; set; }
string TakeLabel => PoliceMode ? "Saisir" : "Prendre";
/// <summary>Un agent ne voit le nom que de ceux dont il a vu les papiers.</summary>
string Title => PoliceMode ? $"Fouille de police · {PoliceMenu.NameOf( Target )}" : $"Fouiller {Target.RpName}";
string Sub => PoliceMode ? (Target.Cuffed ? "Menotté · saisies journalisées" : "Inconscient · saisies journalisées") : "Inconscient";
void TakeCash()
{
if ( PoliceMode )
PoliceActions.RequestSeizeCash( Target.GameObject.Id );
else
Cash.RequestSearch( Target.GameObject.Id );
}
void TakeItem( int index )
{
if ( PoliceMode )
PoliceActions.RequestSeizeItem( Target.GameObject.Id, index );
else
Cash.RequestTakeItem( Target.GameObject.Id, index );
}
void TakeAll()
{
if ( PoliceMode )
PoliceActions.RequestSeizeAll( Target.GameObject.Id );
else
Cash.RequestTakeAll( Target.GameObject.Id );
}
public bool IsOpen { get; private set; }
RoleplayPlayer Target { get; set; }
RoleplayPlayer Me => RoleplayPlayer.Local;
List<InventorySlot> Pockets => Target?.PublishedInventory?.Where( x => x.Definition is not null ).OrderBy( x => x.Slot ).ToList() ?? new();
protected override void OnStart() => instance = this;
void Show( RoleplayPlayer target, bool police )
{
// Un menotté ne fouille personne. La fouille de police s'ouvre depuis le menu F6 (verrou « police »).
if ( Me is null || target is null || Me.Cuffed || (UiLock.IsLocked && !police) )
return;
instance = this;
Target = target;
PoliceMode = police;
IsOpen = true;
UiLock.Set( "fouille", true );
}
void Close()
{
IsOpen = false;
Target = null;
UiLock.Set( "fouille", false );
}
protected override void OnUpdate()
{
instance = this;
if ( !IsOpen )
return;
// Échap, ou le corps n'est plus là pour être fouillé (réanimé, mort, trop loin).
var gone = !Target.IsValid() || Me is null || Me.OnTheGround || Me.Cuffed
|| (PoliceMode
? (!Target.Cuffed && !Target.Downed) || !Me.IsCop || (Target.Downed ? Target.BodyPosition : Target.WorldPosition).Distance( Me.WorldPosition ) > PoliceActions.Reach * 1.4f
: !Target.Downed || Target.BodyPosition.Distance( Me.WorldPosition ) > Cash.Reach * 1.6f);
if ( Input.EscapePressed || gone )
{
Input.EscapePressed = false;
Close();
}
}
protected override void OnDisabled()
{
if ( IsOpen )
Close();
}
protected override int BuildHash() => HashCode.Combine( IsOpen, Target?.Wallet, Target?.InventoryJson, Target?.RpName, PoliceMode, Target?.Cuffed, PoliceMenu.KnownVersion );
}