2023-01-02 22:39:48 -06:00
using Content.Server.Administration.Logs ;
2023-08-10 03:33:03 -05:00
using Content.Server.Construction ;
2022-05-09 08:51:52 +03:00
using Content.Server.Tools.Components ;
2023-08-10 03:33:03 -05:00
using Content.Server.Wires ;
using Content.Shared.Construction.Steps ;
2023-01-02 22:39:48 -06:00
using Content.Shared.Database ;
2023-04-03 13:13:48 +12:00
using Content.Shared.DoAfter ;
2022-05-09 08:51:52 +03:00
using Content.Shared.Examine ;
using Content.Shared.Interaction ;
2023-02-24 19:01:25 -05:00
using Content.Shared.Tools ;
2022-05-09 08:51:52 +03:00
using Content.Shared.Tools.Components ;
2023-04-03 13:13:48 +12:00
using Content.Shared.Tools.Systems ;
2023-08-10 03:33:03 -05:00
using Content.Shared.Wires ;
2023-03-13 15:26:20 -04:00
using Robust.Shared.Physics ;
using Robust.Shared.Physics.Systems ;
2023-08-10 03:33:03 -05:00
using System.Linq ;
2022-05-09 08:51:52 +03:00
namespace Content.Server.Tools.Systems ;
public sealed class WeldableSystem : EntitySystem
{
2023-01-02 22:39:48 -06:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2023-02-24 19:01:25 -05:00
[Dependency] private readonly SharedToolSystem _toolSystem = default ! ;
2023-02-02 17:34:53 +01:00
[Dependency] private readonly SharedAppearanceSystem _appearance = default ! ;
2023-03-13 15:26:20 -04:00
[Dependency] private readonly SharedPhysicsSystem _physics = default ! ;
2023-08-10 03:33:03 -05:00
[Dependency] private readonly ConstructionSystem _construction = default ! ;
2022-05-09 08:51:52 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < WeldableComponent , InteractUsingEvent > ( OnInteractUsing ) ;
SubscribeLocalEvent < WeldableComponent , WeldFinishedEvent > ( OnWeldFinished ) ;
2023-03-13 15:26:20 -04:00
SubscribeLocalEvent < LayerChangeOnWeldComponent , WeldableChangedEvent > ( OnWeldChanged ) ;
2022-05-09 08:51:52 +03:00
SubscribeLocalEvent < WeldableComponent , ExaminedEvent > ( OnExamine ) ;
}
private void OnExamine ( EntityUid uid , WeldableComponent component , ExaminedEvent args )
{
if ( component . IsWelded & & component . WeldedExamineMessage ! = null )
args . PushText ( Loc . GetString ( component . WeldedExamineMessage ) ) ;
}
private void OnInteractUsing ( EntityUid uid , WeldableComponent component , InteractUsingEvent args )
{
2023-08-10 03:33:03 -05:00
// If any construction graph edges has its conditions meet and requires welding, then this construction takes priority
if ( _construction . GetCurrentNode ( uid ) ? . Edges . Any ( x = > _construction . CheckConditions ( uid , x . Conditions )
& & x . Steps . Any ( y = > ( y as ToolConstructionGraphStep ) ? . Tool = = "Welding" ) ) = = true )
{
args . Handled = false ;
return ;
}
2022-05-09 08:51:52 +03:00
if ( args . Handled )
return ;
args . Handled = TryWeld ( uid , args . Used , args . User , component ) ;
}
private bool CanWeld ( EntityUid uid , EntityUid tool , EntityUid user , WeldableComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return false ;
// Basic checks
2023-04-03 13:13:48 +12:00
if ( ! component . Weldable )
2022-05-09 08:51:52 +03:00
return false ;
// Other component systems
var attempt = new WeldableAttemptEvent ( user , tool ) ;
2022-06-22 09:53:41 +10:00
RaiseLocalEvent ( uid , attempt , true ) ;
2022-05-09 08:51:52 +03:00
if ( attempt . Cancelled )
return false ;
return true ;
}
private bool TryWeld ( EntityUid uid , EntityUid tool , EntityUid user , WeldableComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return false ;
if ( ! CanWeld ( uid , tool , user , component ) )
return false ;
2023-06-28 01:46:48 +00:00
if ( ! _toolSystem . UseTool ( tool , user , uid , component . WeldingTime . Seconds , component . WeldingQuality , new WeldFinishedEvent ( ) ) )
2023-04-03 13:13:48 +12:00
return false ;
2022-05-09 08:51:52 +03:00
2023-01-02 22:39:48 -06:00
// Log attempt
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(user):user} is {(component.IsWelded ? " un " : " ")}welding {ToPrettyString(uid):target} at {Transform(uid).Coordinates:targetlocation}" ) ;
2022-05-09 08:51:52 +03:00
return true ;
}
private void OnWeldFinished ( EntityUid uid , WeldableComponent component , WeldFinishedEvent args )
{
2023-04-03 13:13:48 +12:00
if ( args . Cancelled | | args . Used = = null )
return ;
2022-05-09 08:51:52 +03:00
// Check if target is still valid
2023-04-03 13:13:48 +12:00
if ( ! CanWeld ( uid , args . Used . Value , args . User , component ) )
2022-05-09 08:51:52 +03:00
return ;
component . IsWelded = ! component . IsWelded ;
2022-06-22 09:53:41 +10:00
RaiseLocalEvent ( uid , new WeldableChangedEvent ( component . IsWelded ) , true ) ;
2022-05-09 08:51:52 +03:00
UpdateAppearance ( uid , component ) ;
2023-01-02 22:39:48 -06:00
// Log success
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(args.User):user} {(!component.IsWelded ? " un " : " ")}welded {ToPrettyString(uid):target}" ) ;
2022-05-09 08:51:52 +03:00
}
2023-03-13 15:26:20 -04:00
private void OnWeldChanged ( EntityUid uid , LayerChangeOnWeldComponent component , WeldableChangedEvent args )
{
if ( ! TryComp < FixturesComponent > ( uid , out var fixtures ) )
return ;
foreach ( var fixture in fixtures . Fixtures . Values )
{
switch ( args . IsWelded )
{
case true when fixture . CollisionLayer = = ( int ) component . UnWeldedLayer :
_physics . SetCollisionLayer ( uid , fixture , ( int ) component . WeldedLayer ) ;
break ;
case false when fixture . CollisionLayer = = ( int ) component . WeldedLayer :
_physics . SetCollisionLayer ( uid , fixture , ( int ) component . UnWeldedLayer ) ;
break ;
}
}
}
2022-05-09 08:51:52 +03:00
private void UpdateAppearance ( EntityUid uid , WeldableComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return ;
if ( ! TryComp ( uid , out AppearanceComponent ? appearance ) )
return ;
2023-02-02 17:34:53 +01:00
_appearance . SetData ( uid , WeldableVisuals . IsWelded , component . IsWelded , appearance ) ;
2022-05-09 08:51:52 +03:00
}
2022-07-21 17:30:00 -05:00
public void ForceWeldedState ( EntityUid uid , bool state , WeldableComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return ;
component . IsWelded = state ;
RaiseLocalEvent ( uid , new WeldableChangedEvent ( component . IsWelded ) ) ;
UpdateAppearance ( uid , component ) ;
}
2022-05-09 08:51:52 +03:00
public void SetWeldingTime ( EntityUid uid , TimeSpan time , WeldableComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return ;
component . WeldingTime = time ;
}
}
/// <summary>
/// Checks that entity can be weld/unweld.
/// Raised twice: before do_after and after to check that entity still valid.
/// </summary>
public sealed class WeldableAttemptEvent : CancellableEntityEventArgs
{
public readonly EntityUid User ;
public readonly EntityUid Tool ;
public WeldableAttemptEvent ( EntityUid user , EntityUid tool )
{
User = user ;
Tool = tool ;
}
}
/// <summary>
/// Raised when <see cref="WeldableComponent.IsWelded"/> has changed.
/// </summary>
public sealed class WeldableChangedEvent : EntityEventArgs
{
public readonly bool IsWelded ;
public WeldableChangedEvent ( bool isWelded )
{
IsWelded = isWelded ;
}
}