2023-09-10 07:20:27 +01:00
using Content.Server.Chat.Systems ;
using Content.Server.GameTicking ;
using Content.Server.Ninja.Systems ;
using Content.Shared.Communications ;
using Content.Shared.DoAfter ;
using Content.Shared.Interaction ;
2023-09-25 04:16:09 +01:00
using Content.Shared.Random ;
using Content.Shared.Random.Helpers ;
using Robust.Shared.Prototypes ;
2023-09-10 07:20:27 +01:00
using Robust.Shared.Random ;
using Robust.Shared.Serialization ;
namespace Content.Server.Communications ;
public sealed class CommsHackerSystem : SharedCommsHackerSystem
{
[Dependency] private readonly ChatSystem _chat = default ! ;
[Dependency] private readonly GameTicker _gameTicker = default ! ;
2023-09-25 04:16:09 +01:00
[Dependency] private readonly IPrototypeManager _proto = default ! ;
2023-09-10 07:20:27 +01:00
[Dependency] private readonly IRobustRandom _random = default ! ;
// TODO: remove when generic check event is used
[Dependency] private readonly NinjaGlovesSystem _gloves = default ! ;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default ! ;
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < CommsHackerComponent , BeforeInteractHandEvent > ( OnBeforeInteractHand ) ;
SubscribeLocalEvent < CommsHackerComponent , TerrorDoAfterEvent > ( OnDoAfter ) ;
}
/// <summary>
/// Start the doafter to hack a comms console
/// </summary>
private void OnBeforeInteractHand ( EntityUid uid , CommsHackerComponent comp , BeforeInteractHandEvent args )
{
if ( args . Handled | | ! HasComp < CommunicationsConsoleComponent > ( args . Target ) )
return ;
// TODO: generic check event
if ( ! _gloves . AbilityCheck ( uid , args , out var target ) )
return ;
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , uid , comp . Delay , new TerrorDoAfterEvent ( ) , target : target , used : uid , eventTarget : uid )
2023-09-10 07:20:27 +01:00
{
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2023-09-10 07:20:27 +01:00
MovementThreshold = 0.5f ,
CancelDuplicate = false
} ;
_doAfter . TryStartDoAfter ( doAfterArgs ) ;
args . Handled = true ;
}
/// <summary>
/// Call in a random threat and do cleanup.
/// </summary>
private void OnDoAfter ( EntityUid uid , CommsHackerComponent comp , TerrorDoAfterEvent args )
{
2023-09-25 04:16:09 +01:00
if ( args . Cancelled | | args . Handled | | args . Target = = null )
2023-09-10 07:20:27 +01:00
return ;
2023-09-25 04:16:09 +01:00
var threats = _proto . Index < WeightedRandomPrototype > ( comp . Threats ) ;
var threat = threats . Pick ( _random ) ;
2023-10-01 07:01:13 +11:00
CallInThreat ( _proto . Index < NinjaHackingThreatPrototype > ( threat ) ) ;
2023-09-10 07:20:27 +01:00
// prevent calling in multiple threats
RemComp < CommsHackerComponent > ( uid ) ;
var ev = new ThreatCalledInEvent ( uid , args . Target . Value ) ;
RaiseLocalEvent ( args . User , ref ev ) ;
}
/// <summary>
/// Makes announcement and adds game rule of the threat.
/// </summary>
2023-10-01 07:01:13 +11:00
public void CallInThreat ( NinjaHackingThreatPrototype ninjaHackingThreat )
2023-09-10 07:20:27 +01:00
{
2023-10-01 07:01:13 +11:00
_gameTicker . StartGameRule ( ninjaHackingThreat . Rule , out _ ) ;
_chat . DispatchGlobalAnnouncement ( Loc . GetString ( ninjaHackingThreat . Announcement ) , playSound : true , colorOverride : Color . Red ) ;
2023-09-10 07:20:27 +01:00
}
}
/// <summary>
/// Raised on the user when a threat is called in on the communications console.
/// </summary>
/// <remarks>
/// If you add <see cref="CommsHackerComponent"/>, make sure to use this event to prevent adding it twice.
/// For example, you could add a marker component after a threat is called in then check if the user doesn't have that marker before adding CommsHackerComponent.
/// </remarks>
[ByRefEvent]
public record struct ThreatCalledInEvent ( EntityUid Used , EntityUid Target ) ;