2022-06-29 22:55:59 +10:00
using Content.Server.Administration.Logs ;
2021-12-26 05:32:01 +03:00
using Content.Server.DoAfter ;
using Content.Server.Kitchen.Components ;
using Content.Server.Nutrition.Components ;
using Content.Server.Popups ;
2022-06-29 22:55:59 +10:00
using Content.Shared.Administration.Logs ;
using Content.Shared.Database ;
2021-12-26 05:32:01 +03:00
using Content.Shared.DragDrop ;
using Content.Shared.Interaction ;
using Content.Shared.MobState.Components ;
using Content.Shared.Nutrition.Components ;
using Robust.Shared.Audio ;
using Robust.Shared.Player ;
2022-03-28 09:58:13 -07:00
using Content.Shared.Storage ;
using Robust.Shared.Random ;
2021-12-26 05:32:01 +03:00
using static Content . Shared . Kitchen . Components . SharedKitchenSpikeComponent ;
2022-05-12 05:05:16 -07:00
using Content.Shared.Interaction.Events ;
using Content.Shared.Popups ;
2021-12-26 05:32:01 +03:00
namespace Content.Server.Kitchen.EntitySystems
{
2022-02-16 00:23:23 -07:00
internal sealed class KitchenSpikeSystem : EntitySystem
2021-12-26 05:32:01 +03:00
{
[Dependency] private readonly PopupSystem _popupSystem = default ! ;
[Dependency] private readonly DoAfterSystem _doAfter = default ! ;
2022-06-29 22:55:59 +10:00
[Dependency] private readonly IAdminLogManager _logger = default ! ;
2022-03-28 09:58:13 -07:00
[Dependency] private readonly IRobustRandom _random = default ! ;
2021-12-26 05:32:01 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < KitchenSpikeComponent , InteractUsingEvent > ( OnInteractUsing ) ;
SubscribeLocalEvent < KitchenSpikeComponent , InteractHandEvent > ( OnInteractHand ) ;
SubscribeLocalEvent < KitchenSpikeComponent , DragDropEvent > ( OnDragDrop ) ;
//DoAfter
SubscribeLocalEvent < KitchenSpikeComponent , SpikingFinishedEvent > ( OnSpikingFinished ) ;
SubscribeLocalEvent < KitchenSpikeComponent , SpikingFailEvent > ( OnSpikingFail ) ;
2022-05-12 05:05:16 -07:00
SubscribeLocalEvent < KitchenSpikeComponent , SuicideEvent > ( OnSuicide ) ;
}
private void OnSuicide ( EntityUid uid , KitchenSpikeComponent component , SuicideEvent args )
{
if ( args . Handled ) return ;
args . SetHandled ( SuicideKind . Piercing ) ;
var victim = args . Victim ;
var othersMessage = Loc . GetString ( "comp-kitchen-spike-suicide-other" , ( "victim" , victim ) ) ;
victim . PopupMessageOtherClients ( othersMessage ) ;
var selfMessage = Loc . GetString ( "comp-kitchen-spike-suicide-self" ) ;
victim . PopupMessage ( selfMessage ) ;
2021-12-26 05:32:01 +03:00
}
private void OnSpikingFail ( EntityUid uid , KitchenSpikeComponent component , SpikingFailEvent args )
{
component . InUse = false ;
if ( EntityManager . TryGetComponent < SharedButcherableComponent > ( args . VictimUid , out var butcherable ) )
butcherable . BeingButchered = false ;
}
private void OnSpikingFinished ( EntityUid uid , KitchenSpikeComponent component , SpikingFinishedEvent args )
{
component . InUse = false ;
if ( EntityManager . TryGetComponent < SharedButcherableComponent > ( args . VictimUid , out var butcherable ) )
butcherable . BeingButchered = false ;
if ( Spikeable ( uid , args . UserUid , args . VictimUid , component , butcherable ) )
{
Spike ( uid , args . UserUid , args . VictimUid , component ) ;
}
}
private void OnDragDrop ( EntityUid uid , KitchenSpikeComponent component , DragDropEvent args )
{
if ( args . Handled )
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 ) ;
2022-03-28 09:58:13 -07: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 ) {
2021-12-26 05:32:01 +03:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-knife-needed" ) , uid , Filter . Entities ( args . User ) ) ;
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 ,
KitchenSpikeComponent ? component = null , SharedButcherableComponent ? butcherable = null )
{
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-07-09 02:09:52 -07:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-kill" , ( "user" , userUid ) , ( "victim" , victimUid ) ) , uid ,
Filter . Pvs ( userUid ) , PopupType . Critical ) ;
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.
EntityManager . QueueDeleteEntity ( victimUid ) ;
2022-06-12 19:45:47 -04:00
SoundSystem . Play ( component . SpikeSound . GetSound ( ) , Filter . Pvs ( uid ) , uid ) ;
2021-12-26 05:32:01 +03:00
}
private bool TryGetPiece ( EntityUid uid , EntityUid user , EntityUid used ,
KitchenSpikeComponent ? component = null , UtensilComponent ? utensil = null )
{
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
if ( ! Resolve ( used , ref utensil , false ) | | ( utensil . Types & UtensilType . Knife ) = = 0 )
{
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 ) ;
MetaData ( ent ) . EntityName =
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 )
2021-12-26 05:32:01 +03:00
{
2022-07-09 02:09:52 -07:00
_popupSystem . PopupEntity ( component . MeatSource1p , uid , Filter . Entities ( user ) , PopupType . Medium ) ;
2021-12-26 05:32:01 +03:00
}
else
{
UpdateAppearance ( uid , null , component ) ;
2022-07-09 02:09:52 -07:00
_popupSystem . PopupEntity ( component . MeatSource0 , uid , Filter . Entities ( user ) , PopupType . Medium ) ;
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
2022-03-28 09:58:13 -07:00
appearance . SetData ( KitchenSpikeVisuals . Status , ( component . PrototypesToSpawn ? . Count > 0 ) ? KitchenSpikeStatus . Bloody : KitchenSpikeStatus . Empty ) ;
2021-12-26 05:32:01 +03:00
}
private bool Spikeable ( EntityUid uid , EntityUid userUid , EntityUid victimUid ,
KitchenSpikeComponent ? component = null , SharedButcherableComponent ? butcherable = null )
{
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
{
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-collect" , ( "this" , uid ) ) , uid , Filter . Entities ( userUid ) ) ;
return false ;
}
2022-03-28 09:58:13 -07:00
if ( ! Resolve ( victimUid , ref butcherable , false ) )
2021-12-26 05:32:01 +03:00
{
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher" , ( "victim" , victimUid ) , ( "this" , uid ) ) , victimUid , Filter . Entities ( userUid ) ) ;
return false ;
}
2022-03-20 07:25:18 +13:00
switch ( butcherable . Type )
{
case ButcheringType . Spike :
return true ;
case ButcheringType . Knife :
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher-knife" , ( "victim" , victimUid ) , ( "this" , uid ) ) , victimUid , Filter . Entities ( userUid ) ) ;
return false ;
default :
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-butcher" , ( "victim" , victimUid ) , ( "this" , uid ) ) , victimUid , Filter . Entities ( userUid ) ) ;
return false ;
}
2021-12-26 05:32:01 +03:00
}
public bool TrySpike ( EntityUid uid , EntityUid userUid , EntityUid victimUid , KitchenSpikeComponent ? component = null ,
SharedButcherableComponent ? butcherable = null , MobStateComponent ? mobState = null )
{
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 ) & &
! mobState . IsDead ( ) )
{
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-deny-not-dead" , ( "victim" , victimUid ) ) ,
victimUid , Filter . Entities ( userUid ) ) ;
return true ;
}
if ( userUid ! = victimUid )
{
2022-07-09 02:09:52 -07:00
_popupSystem . PopupEntity ( Loc . GetString ( "comp-kitchen-spike-begin-hook-victim" , ( "user" , userUid ) , ( "this" , uid ) ) , victimUid ,
Filter . Entities ( victimUid ) , PopupType . Large ) ;
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 ;
2022-02-18 15:57:42 -07:00
var doAfterArgs = new DoAfterEventArgs ( userUid , component . SpikeDelay + butcherable . ButcherDelay , default , uid )
2021-12-26 05:32:01 +03:00
{
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
BreakOnDamage = true ,
BreakOnStun = true ,
NeedHand = true ,
TargetFinishedEvent = new SpikingFinishedEvent ( userUid , victimUid ) ,
TargetCancelledEvent = new SpikingFailEvent ( victimUid )
} ;
_doAfter . DoAfter ( doAfterArgs ) ;
return true ;
}
2022-02-16 00:23:23 -07:00
private sealed class SpikingFinishedEvent : EntityEventArgs
2021-12-26 05:32:01 +03:00
{
public EntityUid VictimUid ;
public EntityUid UserUid ;
public SpikingFinishedEvent ( EntityUid userUid , EntityUid victimUid )
{
UserUid = userUid ;
VictimUid = victimUid ;
}
}
2022-02-16 00:23:23 -07:00
private sealed class SpikingFailEvent : EntityEventArgs
2021-12-26 05:32:01 +03:00
{
public EntityUid VictimUid ;
public SpikingFailEvent ( EntityUid victimUid )
{
VictimUid = victimUid ;
}
}
}
}