2022-06-29 22:55:59 +10:00
using Content.Server.Administration.Logs ;
2023-04-08 16:53:29 -07:00
using Content.Server.Body.Systems ;
2021-12-26 05:32:01 +03:00
using Content.Server.Kitchen.Components ;
using Content.Server.Popups ;
2022-06-29 22:55:59 +10:00
using Content.Shared.Database ;
2023-02-24 19:01:25 -05:00
using Content.Shared.DoAfter ;
2021-12-26 05:32:01 +03:00
using Content.Shared.DragDrop ;
2022-07-10 18:36:53 -07:00
using Content.Shared.IdentityManagement ;
2021-12-26 05:32:01 +03:00
using Content.Shared.Interaction ;
2022-05-12 05:05:16 -07:00
using Content.Shared.Interaction.Events ;
2023-02-14 00:29:34 +11:00
using Content.Shared.Kitchen ;
2023-04-08 16:53:29 -07:00
using Content.Shared.Kitchen.Components ;
2023-01-13 16:57:10 -08:00
using Content.Shared.Mobs.Components ;
using Content.Shared.Mobs.Systems ;
2023-04-08 16:53:29 -07:00
using Content.Shared.Nutrition.Components ;
2022-05-12 05:05:16 -07:00
using Content.Shared.Popups ;
2023-04-08 16:53:29 -07:00
using Content.Shared.Storage ;
2023-02-28 16:14:13 +03:00
using Robust.Server.GameObjects ;
2023-04-08 16:53:29 -07:00
using Robust.Shared.Player ;
using Robust.Shared.Random ;
using static Content . Shared . Kitchen . Components . KitchenSpikeComponent ;
2021-12-26 05:32:01 +03:00
namespace Content.Server.Kitchen.EntitySystems
{
2023-02-14 00:29:34 +11:00
public sealed class KitchenSpikeSystem : SharedKitchenSpikeSystem
2021-12-26 05:32:01 +03:00
{
[Dependency] private readonly PopupSystem _popupSystem = default ! ;
2023-04-03 13:13:48 +12:00
[Dependency] private readonly SharedDoAfterSystem _doAfter = default ! ;
2022-06-29 22:55:59 +10:00
[Dependency] private readonly IAdminLogManager _logger = default ! ;
2022-12-19 19:25:35 -08:00
[Dependency] private readonly MobStateSystem _mobStateSystem = default ! ;
2022-03-28 09:58:13 -07:00
[Dependency] private readonly IRobustRandom _random = default ! ;
2023-02-28 16:14:13 +03:00
[Dependency] private readonly TransformSystem _transform = default ! ;
[Dependency] private readonly BodySystem _bodySystem = default ! ;
2023-02-02 17:34:53 +01:00
[Dependency] private readonly SharedAppearanceSystem _appearance = default ! ;
2023-02-24 19:01:25 -05:00
[Dependency] private readonly SharedAudioSystem _audio = default ! ;
2023-08-28 11:20:31 +02:00
[Dependency] private readonly MetaDataSystem _metaData = default ! ;
2021-12-26 05:32:01 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < KitchenSpikeComponent , InteractUsingEvent > ( OnInteractUsing ) ;
SubscribeLocalEvent < KitchenSpikeComponent , InteractHandEvent > ( OnInteractHand ) ;
2023-02-14 00:29:34 +11:00
SubscribeLocalEvent < KitchenSpikeComponent , DragDropTargetEvent > ( OnDragDrop ) ;
2021-12-26 05:32:01 +03:00
//DoAfter
2023-04-03 13:13:48 +12:00
SubscribeLocalEvent < KitchenSpikeComponent , SpikeDoAfterEvent > ( OnDoAfter ) ;
2022-05-12 05:05:16 -07:00
SubscribeLocalEvent < KitchenSpikeComponent , SuicideEvent > ( OnSuicide ) ;
2023-02-14 00:29:34 +11:00
SubscribeLocalEvent < ButcherableComponent , CanDropDraggedEvent > ( OnButcherableCanDrop ) ;
}
private void OnButcherableCanDrop ( EntityUid uid , ButcherableComponent component , ref CanDropDraggedEvent args )
{
args . Handled = true ;
args . CanDrop | = component . Type ! = ButcheringType . Knife ;
2022-05-12 05:05:16 -07:00
}
private void OnSuicide ( EntityUid uid , KitchenSpikeComponent component , SuicideEvent args )
{
2023-02-24 19:01:25 -05:00
if ( args . Handled )
return ;
2022-05-12 05:05:16 -07:00
args . SetHandled ( SuicideKind . Piercing ) ;
var victim = args . Victim ;
var othersMessage = Loc . GetString ( "comp-kitchen-spike-suicide-other" , ( "victim" , victim ) ) ;
2023-02-24 19:01:25 -05:00
_popupSystem . PopupEntity ( othersMessage , victim ) ;
2022-05-12 05:05:16 -07:00
var selfMessage = Loc . GetString ( "comp-kitchen-spike-suicide-self" ) ;
2023-02-24 19:01:25 -05:00
_popupSystem . PopupEntity ( selfMessage , victim , victim ) ;
2021-12-26 05:32:01 +03:00
}
2023-02-24 19:01:25 -05:00
private void OnDoAfter ( EntityUid uid , KitchenSpikeComponent component , DoAfterEvent args )
2021-12-26 05:32:01 +03:00
{
2023-02-24 19:01:25 -05:00
if ( args . Args . Target = = null )
return ;
2021-12-26 05:32:01 +03:00
2023-02-24 19:01:25 -05:00
if ( TryComp < ButcherableComponent > ( args . Args . Target . Value , out var butcherable ) )
2021-12-26 05:32:01 +03:00
butcherable . BeingButchered = false ;
2023-02-28 19:51:42 -05:00
if ( args . Cancelled )
{
component . InUse = false ;
return ;
}
if ( args . Handled )
2023-02-24 19:01:25 -05:00
return ;
2021-12-26 05:32:01 +03:00
2023-02-24 19:01:25 -05:00
if ( Spikeable ( uid , args . Args . User , args . Args . Target . Value , component , butcherable ) )
Spike ( uid , args . Args . User , args . Args . Target . Value , component ) ;
2021-12-26 05:32:01 +03:00
2023-02-28 19:51:42 -05:00
component . InUse = false ;
2023-02-24 19:01:25 -05:00
args . Handled = true ;
2021-12-26 05:32:01 +03:00
}
2023-02-14 00:29:34 +11:00
private void OnDragDrop ( EntityUid uid , KitchenSpikeComponent component , ref DragDropTargetEvent args )
2021-12-26 05:32:01 +03:00
{
2023-02-14 00:29:34 +11:00
if ( args . Handled )
2021-12-26 05:32:01 +03:00
return ;
2022-03-20 07:25:18 +13:00
args . Handled = true ;
2021-12-26 05:32:01 +03:00
2022-03-20 07:25:18 +13:00
if ( Spikeable ( uid , args . User , args . Dragged , component ) )
TrySpike ( uid , args . User , args . Dragged , component ) ;
2021-12-26 05:32:01 +03:00
}
2023-02-24 19:01:25 -05:00
2021-12-26 05:32:01 +03:00
private void OnInteractHand ( EntityUid uid , KitchenSpikeComponent component , InteractHandEvent args )
{
if ( args . Handled )
return ;
2022-03-28 09:58:13 -07:00
if ( component . PrototypesToSpawn ? . Count > 0 ) {
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-knife-needed" ) , uid , args . User ) ;
2021-12-26 05:32:01 +03:00
args . Handled = true ;
}
}
private void OnInteractUsing ( EntityUid uid , KitchenSpikeComponent component , InteractUsingEvent args )
{
if ( args . Handled )
return ;
2022-02-16 00:23:23 -07:00
2021-12-26 05:32:01 +03:00
if ( TryGetPiece ( uid , args . User , args . Used ) )
args . Handled = true ;
}
private void Spike ( EntityUid uid , EntityUid userUid , EntityUid victimUid ,
2023-02-14 00:29:34 +11:00
KitchenSpikeComponent ? component = null , ButcherableComponent ? butcherable = null )
2021-12-26 05:32:01 +03:00
{
if ( ! Resolve ( uid , ref component ) | | ! Resolve ( victimUid , ref butcherable ) )
return ;
2022-06-29 22:55:59 +10:00
_logger . Add ( LogType . Gib , LogImpact . Extreme , $"{ToPrettyString(userUid):user} kitchen spiked {ToPrettyString(victimUid):target}" ) ;
2022-03-28 09:58:13 -07:00
// TODO VERY SUS
component . PrototypesToSpawn = EntitySpawnCollection . GetSpawns ( butcherable . SpawnedEntities , _random ) ;
2021-12-26 05:32:01 +03:00
// This feels not okay, but entity is getting deleted on "Spike", for now...
component . MeatSource1p = Loc . GetString ( "comp-kitchen-spike-remove-meat" , ( "victim" , victimUid ) ) ;
component . MeatSource0 = Loc . GetString ( "comp-kitchen-spike-remove-meat-last" , ( "victim" , victimUid ) ) ;
2022-03-28 09:58:13 -07:00
component . Victim = Name ( victimUid ) ;
2021-12-26 05:32:01 +03:00
UpdateAppearance ( uid , null , component ) ;
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-kill" , ( "user" , Identity . Entity ( userUid , EntityManager ) ) , ( "victim" , victimUid ) ) , uid , PopupType . LargeCaution ) ;
2021-12-26 05:32:01 +03:00
2023-02-28 16:14:13 +03:00
_transform . SetCoordinates ( victimUid , Transform ( uid ) . Coordinates ) ;
2021-12-26 05:32:01 +03:00
// THE WHAT?
// TODO: Need to be able to leave them on the spike to do DoT, see ss13.
2023-02-28 16:14:13 +03:00
var gibs = _bodySystem . GibBody ( victimUid ) ;
foreach ( var gib in gibs ) {
QueueDel ( gib ) ;
}
2021-12-26 05:32:01 +03:00
2023-02-24 19:01:25 -05:00
_audio . Play ( component . SpikeSound , Filter . Pvs ( uid ) , uid , true ) ;
2021-12-26 05:32:01 +03:00
}
private bool TryGetPiece ( EntityUid uid , EntityUid user , EntityUid used ,
2022-08-05 21:09:33 -04:00
KitchenSpikeComponent ? component = null , SharpComponent ? sharp = null )
2021-12-26 05:32:01 +03:00
{
2022-03-28 09:58:13 -07:00
if ( ! Resolve ( uid , ref component ) | | component . PrototypesToSpawn = = null | | component . PrototypesToSpawn . Count = = 0 )
2021-12-26 05:32:01 +03:00
return false ;
// Is using knife
2022-08-05 21:09:33 -04:00
if ( ! Resolve ( used , ref sharp , false ) )
2021-12-26 05:32:01 +03:00
{
return false ;
}
2022-03-28 09:58:13 -07:00
var item = _random . PickAndTake ( component . PrototypesToSpawn ) ;
2021-12-26 05:32:01 +03:00
2022-03-28 09:58:13 -07:00
var ent = Spawn ( item , Transform ( uid ) . Coordinates ) ;
2023-08-28 11:20:31 +02:00
_metaData . SetEntityName ( ent ,
Loc . GetString ( "comp-kitchen-spike-meat-name" , ( "name" , Name ( ent ) ) , ( "victim" , component . Victim ) ) ) ;
2021-12-26 05:32:01 +03:00
2022-03-28 09:58:13 -07:00
if ( component . PrototypesToSpawn . Count ! = 0 )
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( component . MeatSource1p , uid , user , PopupType . MediumCaution ) ;
2021-12-26 05:32:01 +03:00
else
{
UpdateAppearance ( uid , null , component ) ;
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( component . MeatSource0 , uid , user , PopupType . MediumCaution ) ;
2021-12-26 05:32:01 +03:00
}
return true ;
}
private void UpdateAppearance ( EntityUid uid , AppearanceComponent ? appearance = null , KitchenSpikeComponent ? component = null )
{
if ( ! Resolve ( uid , ref component , ref appearance , false ) )
return ;
2022-02-16 00:23:23 -07:00
2023-02-03 03:39:44 +01:00
_appearance . SetData ( uid , KitchenSpikeVisuals . Status , component . PrototypesToSpawn ? . Count > 0 ? KitchenSpikeStatus . Bloody : KitchenSpikeStatus . Empty , appearance ) ;
2021-12-26 05:32:01 +03:00
}
private bool Spikeable ( EntityUid uid , EntityUid userUid , EntityUid victimUid ,
2023-02-14 00:29:34 +11:00
KitchenSpikeComponent ? component = null , ButcherableComponent ? butcherable = null )
2021-12-26 05:32:01 +03:00
{
if ( ! Resolve ( uid , ref component ) )
return false ;
2022-03-28 09:58:13 -07:00
if ( component . PrototypesToSpawn ? . Count > 0 )
2021-12-26 05:32:01 +03:00
{
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-collect" , ( "this" , uid ) ) , uid , userUid ) ;
2021-12-26 05:32:01 +03:00
return false ;
}
2022-03-28 09:58:13 -07:00
if ( ! Resolve ( victimUid , ref butcherable , false ) )
2021-12-26 05:32:01 +03:00
{
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher" , ( "victim" , Identity . Entity ( victimUid , EntityManager ) ) , ( "this" , uid ) ) , victimUid , userUid ) ;
2021-12-26 05:32:01 +03:00
return false ;
}
2022-03-20 07:25:18 +13:00
switch ( butcherable . Type )
{
case ButcheringType . Spike :
return true ;
case ButcheringType . Knife :
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher-knife" , ( "victim" , Identity . Entity ( victimUid , EntityManager ) ) , ( "this" , uid ) ) , victimUid , userUid ) ;
2022-03-20 07:25:18 +13:00
return false ;
default :
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher" , ( "victim" , Identity . Entity ( victimUid , EntityManager ) ) , ( "this" , uid ) ) , victimUid , userUid ) ;
2022-03-20 07:25:18 +13:00
return false ;
}
2021-12-26 05:32:01 +03:00
}
public bool TrySpike ( EntityUid uid , EntityUid userUid , EntityUid victimUid , KitchenSpikeComponent ? component = null ,
2023-02-14 00:29:34 +11:00
ButcherableComponent ? butcherable = null , MobStateComponent ? mobState = null )
2021-12-26 05:32:01 +03:00
{
if ( ! Resolve ( uid , ref component ) | | component . InUse | |
! Resolve ( victimUid , ref butcherable ) | | butcherable . BeingButchered )
return false ;
// THE WHAT? (again)
// Prevent dead from being spiked TODO: Maybe remove when rounds can be played and DOT is implemented
if ( Resolve ( victimUid , ref mobState , false ) & &
2022-12-19 19:25:35 -08:00
_mobStateSystem . IsAlive ( victimUid , mobState ) )
2021-12-26 05:32:01 +03:00
{
2022-07-15 20:10:52 +12:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-not-dead" , ( "victim" , Identity . Entity ( victimUid , EntityManager ) ) ) ,
2022-12-19 10:41:47 +13:00
victimUid , userUid ) ;
2021-12-26 05:32:01 +03:00
return true ;
}
if ( userUid ! = victimUid )
{
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-begin-hook-victim" , ( "user" , Identity . Entity ( userUid , EntityManager ) ) , ( "this" , uid ) ) , victimUid , victimUid , PopupType . LargeCaution ) ;
2021-12-26 05:32:01 +03:00
}
// TODO: make it work when SuicideEvent is implemented
// else
// _popupSystem.PopupEntity(Loc.GetString("comp-kitchen-spike-begin-hook-self", ("this", uid)), victimUid, Filter.Pvs(uid)); // This is actually unreachable and should be in SuicideEvent
butcherable . BeingButchered = true ;
component . InUse = true ;
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , userUid , component . SpikeDelay + butcherable . ButcherDelay , new SpikeDoAfterEvent ( ) , uid , target : victimUid , used : uid )
2021-12-26 05:32:01 +03:00
{
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
BreakOnDamage = true ,
2023-02-24 19:01:25 -05:00
NeedHand = true
2021-12-26 05:32:01 +03:00
} ;
2023-04-03 13:13:48 +12:00
_doAfter . TryStartDoAfter ( doAfterArgs ) ;
2021-12-26 05:32:01 +03:00
return true ;
}
}
}