2022-05-18 00:05:22 -04:00
using Content.Server.Actions ;
2022-06-12 01:53:13 -04:00
using Content.Server.Inventory ;
2022-05-18 00:05:22 -04:00
using Content.Server.Mind.Components ;
using Content.Server.Polymorph.Components ;
using Content.Server.Popups ;
using Content.Shared.Actions ;
using Content.Shared.Actions.ActionTypes ;
using Content.Shared.Damage ;
2022-06-12 01:53:13 -04:00
using Content.Shared.Hands.EntitySystems ;
2022-07-15 20:10:52 +12:00
using Content.Shared.IdentityManagement ;
2022-05-18 00:05:22 -04:00
using Content.Shared.MobState.Components ;
2022-06-12 01:53:13 -04:00
using Content.Shared.Polymorph ;
using Robust.Server.Containers ;
using Robust.Shared.Containers ;
2022-05-18 00:05:22 -04:00
using Robust.Shared.Player ;
2022-10-02 07:16:55 +13:00
using Robust.Shared.Prototypes ;
2022-05-18 00:05:22 -04:00
namespace Content.Server.Polymorph.Systems
{
public sealed class PolymorphedEntitySystem : EntitySystem
{
2022-10-02 07:16:55 +13:00
[Dependency] private readonly IPrototypeManager _proto = default ! ;
2022-05-18 00:05:22 -04:00
[Dependency] private readonly ActionsSystem _actions = default ! ;
[Dependency] private readonly DamageableSystem _damageable = default ! ;
[Dependency] private readonly PopupSystem _popup = default ! ;
2022-06-12 01:53:13 -04:00
[Dependency] private readonly ServerInventorySystem _inventory = default ! ;
[Dependency] private readonly SharedHandsSystem _sharedHands = default ! ;
[Dependency] private readonly ContainerSystem _container = default ! ;
2022-05-18 00:05:22 -04:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-10-02 07:16:55 +13:00
SubscribeLocalEvent < PolymorphedEntityComponent , ComponentStartup > ( OnInit ) ;
2022-05-18 00:05:22 -04:00
SubscribeLocalEvent < PolymorphedEntityComponent , RevertPolymorphActionEvent > ( OnRevertPolymorphActionEvent ) ;
}
private void OnRevertPolymorphActionEvent ( EntityUid uid , PolymorphedEntityComponent component , RevertPolymorphActionEvent args )
{
Revert ( uid ) ;
}
/// <summary>
/// Reverts a polymorphed entity back into its original form
/// </summary>
/// <param name="uid">The entityuid of the entity being reverted</param>
public void Revert ( EntityUid uid )
{
2022-06-12 01:53:13 -04:00
if ( Deleted ( uid ) )
return ;
2022-09-11 21:30:11 -07:00
2022-05-18 00:05:22 -04:00
if ( ! TryComp < PolymorphedEntityComponent > ( uid , out var component ) )
return ;
2022-06-17 03:22:09 -04:00
if ( Deleted ( component . Parent ) )
return ;
2022-10-02 07:16:55 +13:00
if ( ! _proto . TryIndex ( component . Prototype , out PolymorphPrototype ? proto ) )
{
Logger . Error ( $"{nameof(PolymorphedEntitySystem)} encountered an improperly initialized polymorph component while reverting. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}" ) ;
return ;
}
2022-06-12 01:53:13 -04:00
2022-05-18 00:05:22 -04:00
var uidXform = Transform ( uid ) ;
var parentXform = Transform ( component . Parent ) ;
parentXform . AttachParent ( uidXform . ParentUid ) ;
parentXform . Coordinates = uidXform . Coordinates ;
2022-06-12 01:53:13 -04:00
parentXform . LocalRotation = uidXform . LocalRotation ;
if ( _container . TryGetContainingContainer ( uid , out var cont ) )
cont . Insert ( component . Parent ) ;
2022-05-18 00:05:22 -04:00
2022-10-02 07:16:55 +13:00
if ( proto . TransferDamage & &
2022-06-12 01:53:13 -04:00
TryComp < DamageableComponent > ( component . Parent , out var damageParent ) & &
2022-05-18 00:05:22 -04:00
_damageable . GetScaledDamage ( uid , component . Parent , out var damage ) & &
damage ! = null )
{
_damageable . SetDamage ( damageParent , damage ) ;
}
2022-06-12 01:53:13 -04:00
if ( proto . Inventory = = PolymorphInventoryChange . Transfer )
{
_inventory . TransferEntityInventories ( uid , component . Parent ) ;
foreach ( var hand in _sharedHands . EnumerateHeld ( component . Parent ) )
{
hand . TryRemoveFromContainer ( ) ;
_sharedHands . TryPickupAnyHand ( component . Parent , hand ) ;
}
}
else if ( proto . Inventory = = PolymorphInventoryChange . Drop )
{
if ( _inventory . TryGetContainerSlotEnumerator ( uid , out var enumerator ) )
while ( enumerator . MoveNext ( out var slot ) )
slot . EmptyContainer ( ) ;
foreach ( var hand in _sharedHands . EnumerateHeld ( uid ) )
2022-10-02 07:16:55 +13:00
// This causes errors/bugs. Use hand related functions instead.
2022-06-12 01:53:13 -04:00
hand . TryRemoveFromContainer ( ) ;
}
2022-05-18 00:05:22 -04:00
if ( TryComp < MindComponent > ( uid , out var mind ) & & mind . Mind ! = null )
{
mind . Mind . TransferTo ( component . Parent ) ;
}
2022-07-15 20:10:52 +12:00
_popup . PopupEntity ( Loc . GetString ( "polymorph-revert-popup-generic" ,
( "parent" , Identity . Entity ( uid , EntityManager ) ) ,
( "child" , Identity . Entity ( component . Parent , EntityManager ) ) ) ,
component . Parent ,
Filter . Pvs ( component . Parent ) ) ;
2022-05-18 00:05:22 -04:00
QueueDel ( uid ) ;
}
2022-10-02 07:16:55 +13:00
public void OnInit ( EntityUid uid , PolymorphedEntityComponent component , ComponentStartup args )
2022-05-18 00:05:22 -04:00
{
2022-10-02 07:16:55 +13:00
if ( ! _proto . TryIndex ( component . Prototype , out PolymorphPrototype ? proto ) )
{
// warning instead of error because of the all-comps one entity test.
Logger . Warning ( $"{nameof(PolymorphedEntitySystem)} encountered an improperly set up polymorph component while initializing. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}" ) ;
RemCompDeferred ( uid , component ) ;
return ;
}
if ( proto . Forced )
2022-05-18 00:05:22 -04:00
return ;
var act = new InstantAction ( )
{
Event = new RevertPolymorphActionEvent ( ) ,
EntityIcon = component . Parent ,
2022-09-04 17:21:14 -07:00
DisplayName = Loc . GetString ( "polymorph-revert-action-name" ) ,
2022-05-18 00:05:22 -04:00
Description = Loc . GetString ( "polymorph-revert-action-description" ) ,
2022-10-02 07:16:55 +13:00
UseDelay = TimeSpan . FromSeconds ( proto . Delay ) ,
2022-05-18 00:05:22 -04:00
} ;
2022-09-11 21:30:11 -07:00
2022-05-18 00:05:22 -04:00
_actions . AddAction ( uid , act , null ) ;
}
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
2022-10-02 07:16:55 +13:00
foreach ( var comp in EntityQuery < PolymorphedEntityComponent > ( ) )
2022-05-18 00:05:22 -04:00
{
2022-10-02 07:16:55 +13:00
comp . Time + = frameTime ;
if ( ! _proto . TryIndex ( comp . Prototype , out PolymorphPrototype ? proto ) )
{
Logger . Error ( $"{nameof(PolymorphedEntitySystem)} encountered an improperly initialized polymorph component while updating. Entity {ToPrettyString(comp.Owner)}. Prototype: {comp.Prototype}" ) ;
RemCompDeferred ( comp . Owner , comp ) ;
continue ;
}
2022-05-18 00:05:22 -04:00
2022-10-02 07:16:55 +13:00
if ( proto . Duration ! = null & & comp . Time > = proto . Duration )
Revert ( comp . Owner ) ;
2022-05-18 00:05:22 -04:00
2022-10-02 07:16:55 +13:00
if ( ! TryComp < MobStateComponent > ( comp . Owner , out var mob ) )
2022-05-18 00:05:22 -04:00
continue ;
2022-10-02 07:16:55 +13:00
if ( ( proto . RevertOnDeath & & mob . IsDead ( ) ) | |
( proto . RevertOnCrit & & mob . IsCritical ( ) ) )
Revert ( comp . Owner ) ;
2022-05-18 00:05:22 -04:00
}
}
}
public sealed class RevertPolymorphActionEvent : InstantActionEvent { } ;
}