Cleanups PolymorphSystem/Components/Prototypes (#23721)
* Cleanups PolymorphSystem * forgot this * Nah * Fix test --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -32,7 +32,7 @@ public sealed class AddPolymorphActionCommand : IConsoleCommand
|
|||||||
|
|
||||||
var polySystem = _entityManager.EntitySysManager.GetEntitySystem<PolymorphSystem>();
|
var polySystem = _entityManager.EntitySysManager.GetEntitySystem<PolymorphSystem>();
|
||||||
|
|
||||||
_entityManager.EnsureComponent<PolymorphableComponent>(entityUid.Value);
|
var polymorphable = _entityManager.EnsureComponent<PolymorphableComponent>(entityUid.Value);
|
||||||
polySystem.CreatePolymorphAction(args[1], entityUid.Value);
|
polySystem.CreatePolymorphAction(args[1], (entityUid.Value, polymorphable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public sealed partial class Polymorph : ReagentEffect
|
|||||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||||
=> Loc.GetString("reagent-effect-guidebook-make-polymorph",
|
=> Loc.GetString("reagent-effect-guidebook-make-polymorph",
|
||||||
("chance", Probability), ("entityname",
|
("chance", Probability), ("entityname",
|
||||||
prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Entity).Name));
|
prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Configuration.Entity).Name));
|
||||||
|
|
||||||
public override void Effect(ReagentEffectArgs args)
|
public override void Effect(ReagentEffectArgs args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
|
using Content.Server.Polymorph.Systems;
|
||||||
using Content.Shared.Polymorph;
|
using Content.Shared.Polymorph;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Components;
|
namespace Content.Server.Polymorph.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
|
[Access(typeof(PolymorphSystem))]
|
||||||
public sealed partial class PolymorphOnCollideComponent : Component
|
public sealed partial class PolymorphOnCollideComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("polymorph", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
|
[DataField(required: true)]
|
||||||
public string Polymorph = default!;
|
public ProtoId<PolymorphPrototype> Polymorph;
|
||||||
|
|
||||||
[DataField("whitelist", required: true)]
|
[DataField(required: true)]
|
||||||
public EntityWhitelist Whitelist = default!;
|
public EntityWhitelist Whitelist = default!;
|
||||||
|
|
||||||
[DataField("blacklist")]
|
[DataField]
|
||||||
public EntityWhitelist? Blacklist;
|
public EntityWhitelist? Blacklist;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg");
|
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
|
using Content.Server.Polymorph.Systems;
|
||||||
using Content.Shared.Polymorph;
|
using Content.Shared.Polymorph;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Components
|
namespace Content.Server.Polymorph.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[Access(typeof(PolymorphSystem))]
|
||||||
|
public sealed partial class PolymorphableComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
/// <summary>
|
||||||
public sealed partial class PolymorphableComponent : Component
|
/// A list of all the polymorphs that the entity has.
|
||||||
{
|
/// Used to manage them and remove them if needed.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// A list of all the polymorphs that the entity has.
|
public Dictionary<ProtoId<PolymorphPrototype>, EntityUid>? PolymorphActions = null;
|
||||||
/// Used to manage them and remove them if needed.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public Dictionary<string, EntityUid>? PolymorphActions = null;
|
/// Timestamp for when the most recent polymorph ended.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public TimeSpan? LastPolymorphEnd = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timestamp for when the most recent polymorph ended.
|
/// The polymorphs that the entity starts out being able to do.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField]
|
||||||
public TimeSpan? LastPolymorphEnd = null;
|
public List<ProtoId<PolymorphPrototype>>? InnatePolymorphs;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The polymorphs that the entity starts out being able to do.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("innatePolymorphs", customTypeSerializer : typeof(PrototypeIdListSerializer<PolymorphPrototype>))]
|
|
||||||
public List<string>? InnatePolymorphs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
|
using Content.Server.Polymorph.Systems;
|
||||||
using Content.Shared.Polymorph;
|
using Content.Shared.Polymorph;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Components
|
namespace Content.Server.Polymorph.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[Access(typeof(PolymorphSystem))]
|
||||||
|
public sealed partial class PolymorphedEntityComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
/// <summary>
|
||||||
public sealed partial class PolymorphedEntityComponent : Component
|
/// The polymorph prototype, used to track various information
|
||||||
{
|
/// about the polymorph
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// The polymorph prototype, used to track various information
|
[DataField(required: true)]
|
||||||
/// about the polymorph
|
public PolymorphConfiguration Configuration = new();
|
||||||
/// </summary>
|
|
||||||
[DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
|
|
||||||
public string Prototype = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The original entity that the player will revert back into
|
/// The original entity that the player will revert back into
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("parent", required: true)]
|
[DataField(required: true)]
|
||||||
public EntityUid Parent;
|
public EntityUid Parent;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of time that has passed since the entity was created
|
/// The amount of time that has passed since the entity was created
|
||||||
/// used for tracking the duration
|
/// used for tracking the duration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("time")]
|
[DataField]
|
||||||
public float Time;
|
public float Time;
|
||||||
|
|
||||||
[DataField] public EntityUid? Action;
|
[DataField]
|
||||||
}
|
public EntityUid? Action;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
using Content.Server.Polymorph.Components;
|
using Content.Server.Polymorph.Components;
|
||||||
|
using Content.Shared.Polymorph;
|
||||||
using Content.Shared.Projectiles;
|
using Content.Shared.Projectiles;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Systems;
|
namespace Content.Server.Polymorph.Systems;
|
||||||
|
|
||||||
public partial class PolymorphSystem
|
public partial class PolymorphSystem
|
||||||
{
|
{
|
||||||
// Need to do this so we don't get a collection enumeration error in physics by polymorphing
|
/// <summary>
|
||||||
// an entity we're colliding with
|
/// Need to do this so we don't get a collection enumeration error in physics by polymorphing
|
||||||
|
/// an entity we're colliding with
|
||||||
|
/// </summary>
|
||||||
private Queue<PolymorphQueuedData> _queuedPolymorphUpdates = new();
|
private Queue<PolymorphQueuedData> _queuedPolymorphUpdates = new();
|
||||||
|
|
||||||
|
private void InitializeCollide()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateCollide()
|
public void UpdateCollide()
|
||||||
{
|
{
|
||||||
while (_queuedPolymorphUpdates.TryDequeue(out var data))
|
while (_queuedPolymorphUpdates.TryDequeue(out var data))
|
||||||
@@ -20,25 +29,18 @@ public partial class PolymorphSystem
|
|||||||
|
|
||||||
var ent = PolymorphEntity(data.Ent, data.Polymorph);
|
var ent = PolymorphEntity(data.Ent, data.Polymorph);
|
||||||
if (ent != null)
|
if (ent != null)
|
||||||
{
|
|
||||||
_audio.PlayPvs(data.Sound, ent.Value);
|
_audio.PlayPvs(data.Sound, ent.Value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeCollide()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPolymorphCollide(EntityUid uid, PolymorphOnCollideComponent component, ref StartCollideEvent args)
|
private void OnPolymorphCollide(EntityUid uid, PolymorphOnCollideComponent component, ref StartCollideEvent args)
|
||||||
{
|
{
|
||||||
if (args.OurFixtureId != SharedProjectileSystem.ProjectileFixture)
|
if (args.OurFixtureId != SharedProjectileSystem.ProjectileFixture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var other = args.OtherEntity;
|
var other = args.OtherEntity;
|
||||||
if (!component.Whitelist.IsValid(other)
|
if (!component.Whitelist.IsValid(other, EntityManager)
|
||||||
|| component.Blacklist != null && component.Blacklist.IsValid(other))
|
|| component.Blacklist != null && component.Blacklist.IsValid(other, EntityManager))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_queuedPolymorphUpdates.Enqueue(new (other, component.Sound, component.Polymorph));
|
_queuedPolymorphUpdates.Enqueue(new (other, component.Sound, component.Polymorph));
|
||||||
@@ -49,9 +51,9 @@ public struct PolymorphQueuedData
|
|||||||
{
|
{
|
||||||
public EntityUid Ent;
|
public EntityUid Ent;
|
||||||
public SoundSpecifier Sound;
|
public SoundSpecifier Sound;
|
||||||
public string Polymorph;
|
public ProtoId<PolymorphPrototype> Polymorph;
|
||||||
|
|
||||||
public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, string polymorph)
|
public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, ProtoId<PolymorphPrototype> polymorph)
|
||||||
{
|
{
|
||||||
Ent = ent;
|
Ent = ent;
|
||||||
Sound = sound;
|
Sound = sound;
|
||||||
|
|||||||
@@ -1,39 +1,38 @@
|
|||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Systems
|
namespace Content.Server.Polymorph.Systems;
|
||||||
|
|
||||||
|
public sealed partial class PolymorphSystem
|
||||||
{
|
{
|
||||||
public sealed partial class PolymorphSystem
|
public EntityUid? PausedMap { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to subscribe to the round restart event
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeMap()
|
||||||
{
|
{
|
||||||
public EntityUid? PausedMap { get; private set; }
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnRoundRestart(RoundRestartCleanupEvent _)
|
||||||
/// Used to subscribe to the round restart event
|
{
|
||||||
/// </summary>
|
if (PausedMap == null || !Exists(PausedMap))
|
||||||
private void InitializeMap()
|
return;
|
||||||
{
|
|
||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRoundRestart(RoundRestartCleanupEvent _)
|
Del(PausedMap.Value);
|
||||||
{
|
}
|
||||||
if (PausedMap == null || !Exists(PausedMap))
|
|
||||||
return;
|
|
||||||
|
|
||||||
EntityManager.DeleteEntity(PausedMap.Value);
|
/// <summary>
|
||||||
}
|
/// Used internally to ensure a paused map that is
|
||||||
|
/// stores polymorphed entities.
|
||||||
|
/// </summary>
|
||||||
|
private void EnsurePausedMap()
|
||||||
|
{
|
||||||
|
if (PausedMap != null && Exists(PausedMap))
|
||||||
|
return;
|
||||||
|
|
||||||
/// <summary>
|
var newmap = _mapManager.CreateMap();
|
||||||
/// Used internally to ensure a paused map that is
|
_mapManager.SetMapPaused(newmap, true);
|
||||||
/// stores polymorphed entities.
|
PausedMap = _mapManager.GetMapEntityId(newmap);
|
||||||
/// </summary>
|
|
||||||
private void EnsurePausesdMap()
|
|
||||||
{
|
|
||||||
if (PausedMap != null && Exists(PausedMap))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var newmap = _mapManager.CreateMap();
|
|
||||||
_mapManager.SetMapPaused(newmap, true);
|
|
||||||
PausedMap = _mapManager.GetMapEntityId(newmap);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ using Content.Shared.Mobs.Components;
|
|||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Polymorph;
|
using Content.Shared.Polymorph;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Server.Audio;
|
using Robust.Server.Audio;
|
||||||
using Robust.Server.Containers;
|
using Robust.Server.Containers;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -24,410 +23,359 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Systems
|
namespace Content.Server.Polymorph.Systems;
|
||||||
|
|
||||||
|
public sealed partial class PolymorphSystem : EntitySystem
|
||||||
{
|
{
|
||||||
public sealed partial class PolymorphSystem : EntitySystem
|
[Dependency] private readonly IComponentFactory _compFact = default!;
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||||
|
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||||
|
[Dependency] private readonly AudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
|
||||||
|
[Dependency] private readonly ContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||||
|
[Dependency] private readonly ServerInventorySystem _inventory = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly TransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
||||||
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||||
|
|
||||||
|
private const string RevertPolymorphId = "ActionRevertPolymorph";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IComponentFactory _compFact = default!;
|
SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnComponentStartup);
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
SubscribeLocalEvent<PolymorphedEntityComponent, MapInitEvent>(OnMapInit);
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
||||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
|
||||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
|
||||||
[Dependency] private readonly AudioSystem _audio = default!;
|
|
||||||
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
|
|
||||||
[Dependency] private readonly ContainerSystem _container = default!;
|
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
||||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
|
||||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
|
||||||
[Dependency] private readonly ServerInventorySystem _inventory = default!;
|
|
||||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
|
||||||
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
|
||||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
|
||||||
|
SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
|
||||||
|
|
||||||
private const string RevertPolymorphId = "ActionRevertPolymorph";
|
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
|
||||||
|
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
|
||||||
|
SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
|
||||||
|
|
||||||
public override void Initialize()
|
InitializeCollide();
|
||||||
|
InitializeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<PolymorphedEntityComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var comp))
|
||||||
{
|
{
|
||||||
base.Initialize();
|
comp.Time += frameTime;
|
||||||
|
|
||||||
SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup);
|
if (comp.Configuration.Duration != null && comp.Time >= comp.Configuration.Duration)
|
||||||
SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
|
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, MapInitEvent>(OnMapInit);
|
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
|
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
|
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
|
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
|
|
||||||
|
|
||||||
InitializeCollide();
|
|
||||||
InitializeMap();
|
|
||||||
|
|
||||||
_sawmill = Logger.GetSawmill("polymorph");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStartup(EntityUid uid, PolymorphableComponent component, ComponentStartup args)
|
|
||||||
{
|
|
||||||
if (component.InnatePolymorphs != null)
|
|
||||||
{
|
{
|
||||||
foreach (var morph in component.InnatePolymorphs)
|
Revert((uid, comp));
|
||||||
{
|
continue;
|
||||||
CreatePolymorphAction(morph, uid);
|
}
|
||||||
}
|
|
||||||
|
if (!TryComp<MobStateComponent>(uid, out var mob))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (comp.Configuration.RevertOnDeath && _mobState.IsDead(uid, mob) ||
|
||||||
|
comp.Configuration.RevertOnCrit && _mobState.IsIncapacitated(uid, mob))
|
||||||
|
{
|
||||||
|
Revert((uid, comp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPolymorphActionEvent(EntityUid uid, PolymorphableComponent component, PolymorphActionEvent args)
|
UpdateCollide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentStartup(Entity<PolymorphableComponent> ent, ref ComponentStartup args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.InnatePolymorphs != null)
|
||||||
{
|
{
|
||||||
PolymorphEntity(uid, args.Prototype);
|
foreach (var morph in ent.Comp.InnatePolymorphs)
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRevertPolymorphActionEvent(EntityUid uid, PolymorphedEntityComponent component, RevertPolymorphActionEvent args)
|
|
||||||
{
|
|
||||||
Revert(uid, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, PolymorphedEntityComponent component, MapInitEvent args)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
|
||||||
{
|
{
|
||||||
// warning instead of error because of the all-comps one entity test.
|
CreatePolymorphAction(morph, ent);
|
||||||
_sawmill.Warning($"{nameof(PolymorphSystem)} encountered an improperly set up polymorph component while initializing. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
|
||||||
RemCompDeferred(uid, component);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto.Forced)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_actions.AddAction(uid, ref component.Action, out var action, RevertPolymorphId))
|
|
||||||
{
|
|
||||||
action.EntityIcon = component.Parent;
|
|
||||||
action.UseDelay = TimeSpan.FromSeconds(proto.Delay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBeforeFullyEaten(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullyEatenEvent args)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error($"Invalid polymorph prototype {comp.Prototype}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.RevertOnEat)
|
|
||||||
{
|
|
||||||
args.Cancel();
|
|
||||||
Revert(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// It is possible to be polymorphed into an entity that can't "die", but is instead
|
|
||||||
/// destroyed. This handler ensures that destruction is treated like death.
|
|
||||||
/// </summary>
|
|
||||||
private void OnDestruction(EntityUid uid, PolymorphedEntityComponent comp, DestructionEventArgs args)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error($"Invalid polymorph prototype {comp.Prototype}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.RevertOnDeath)
|
|
||||||
{
|
|
||||||
Revert(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBeforeFullySliced(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullySlicedEvent args)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error("Invalid polymorph prototype {comp.Prototype}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.RevertOnEat)
|
|
||||||
{
|
|
||||||
args.Cancel();
|
|
||||||
Revert(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Polymorphs the target entity into the specific polymorph prototype
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">The entity that will be transformed</param>
|
|
||||||
/// <param name="id">The id of the polymorph prototype</param>
|
|
||||||
public EntityUid? PolymorphEntity(EntityUid target, string id)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(id, out var proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error("Invalid polymorph prototype {id}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PolymorphEntity(target, proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Polymorphs the target entity into the specific polymorph prototype
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">The entity that will be transformed</param>
|
|
||||||
/// <param name="proto">The polymorph prototype</param>
|
|
||||||
public EntityUid? PolymorphEntity(EntityUid uid, PolymorphPrototype proto)
|
|
||||||
{
|
|
||||||
// if it's already morphed, don't allow it again with this condition active.
|
|
||||||
if (!proto.AllowRepeatedMorphs && HasComp<PolymorphedEntityComponent>(uid))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// If this polymorph has a cooldown, check if that amount of time has passed since the
|
|
||||||
// last polymorph ended.
|
|
||||||
if (TryComp<PolymorphableComponent>(uid, out var polymorphableComponent) &&
|
|
||||||
polymorphableComponent.LastPolymorphEnd != null &&
|
|
||||||
_gameTiming.CurTime < polymorphableComponent.LastPolymorphEnd + proto.Cooldown)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// mostly just for vehicles
|
|
||||||
_buckle.TryUnbuckle(uid, uid, true);
|
|
||||||
|
|
||||||
var targetTransformComp = Transform(uid);
|
|
||||||
|
|
||||||
var child = Spawn(proto.Entity, targetTransformComp.Coordinates);
|
|
||||||
MakeSentientCommand.MakeSentient(child, EntityManager);
|
|
||||||
|
|
||||||
var comp = _compFact.GetComponent<PolymorphedEntityComponent>();
|
|
||||||
comp.Parent = uid;
|
|
||||||
comp.Prototype = proto.ID;
|
|
||||||
AddComp(child, comp);
|
|
||||||
|
|
||||||
var childXform = Transform(child);
|
|
||||||
childXform.LocalRotation = targetTransformComp.LocalRotation;
|
|
||||||
|
|
||||||
if (_container.TryGetContainingContainer(uid, out var cont))
|
|
||||||
_container.Insert(child, cont);
|
|
||||||
|
|
||||||
//Transfers all damage from the original to the new one
|
|
||||||
if (proto.TransferDamage &&
|
|
||||||
TryComp<DamageableComponent>(child, out var damageParent) &&
|
|
||||||
_mobThreshold.GetScaledDamage(uid, child, out var damage) &&
|
|
||||||
damage != null)
|
|
||||||
{
|
|
||||||
_damageable.SetDamage(child, damageParent, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.Inventory == PolymorphInventoryChange.Transfer)
|
|
||||||
{
|
|
||||||
_inventory.TransferEntityInventories(uid, child);
|
|
||||||
foreach (var hand in _hands.EnumerateHeld(uid))
|
|
||||||
{
|
|
||||||
_hands.TryDrop(uid, hand, checkActionBlocker: false);
|
|
||||||
_hands.TryPickupAnyHand(child, hand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (proto.Inventory == PolymorphInventoryChange.Drop)
|
|
||||||
{
|
|
||||||
if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
|
|
||||||
{
|
|
||||||
while (enumerator.MoveNext(out var slot))
|
|
||||||
{
|
|
||||||
_inventory.TryUnequip(uid, slot.ID, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var held in _hands.EnumerateHeld(uid))
|
|
||||||
{
|
|
||||||
_hands.TryDrop(uid, held);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.TransferName && TryComp<MetaDataComponent>(uid, out var targetMeta))
|
|
||||||
_metaData.SetEntityName(child, targetMeta.EntityName);
|
|
||||||
|
|
||||||
if (proto.TransferHumanoidAppearance)
|
|
||||||
{
|
|
||||||
_humanoid.CloneAppearance(uid, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
|
||||||
_mindSystem.TransferTo(mindId, child, mind: mind);
|
|
||||||
|
|
||||||
//Ensures a map to banish the entity to
|
|
||||||
EnsurePausesdMap();
|
|
||||||
if (PausedMap != null)
|
|
||||||
_transform.SetParent(uid, targetTransformComp, PausedMap.Value);
|
|
||||||
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reverts a polymorphed entity back into its original form
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">The entityuid of the entity being reverted</param>
|
|
||||||
/// <param name="component"></param>
|
|
||||||
public EntityUid? Revert(EntityUid uid, PolymorphedEntityComponent? component = null)
|
|
||||||
{
|
|
||||||
if (Deleted(uid))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!Resolve(uid, ref component))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var parent = component.Parent;
|
|
||||||
if (Deleted(parent))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while reverting. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var uidXform = Transform(uid);
|
|
||||||
var parentXform = Transform(parent);
|
|
||||||
|
|
||||||
_transform.SetParent(parent, parentXform, uidXform.ParentUid);
|
|
||||||
parentXform.Coordinates = uidXform.Coordinates;
|
|
||||||
parentXform.LocalRotation = uidXform.LocalRotation;
|
|
||||||
|
|
||||||
if (proto.TransferDamage &&
|
|
||||||
TryComp<DamageableComponent>(parent, out var damageParent) &&
|
|
||||||
_mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
|
|
||||||
damage != null)
|
|
||||||
{
|
|
||||||
_damageable.SetDamage(parent, damageParent, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.Inventory == PolymorphInventoryChange.Transfer)
|
|
||||||
{
|
|
||||||
_inventory.TransferEntityInventories(uid, parent);
|
|
||||||
foreach (var held in _hands.EnumerateHeld(uid))
|
|
||||||
{
|
|
||||||
_hands.TryDrop(uid, held);
|
|
||||||
_hands.TryPickupAnyHand(parent, held, checkActionBlocker: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (proto.Inventory == PolymorphInventoryChange.Drop)
|
|
||||||
{
|
|
||||||
if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
|
|
||||||
{
|
|
||||||
while (enumerator.MoveNext(out var slot))
|
|
||||||
{
|
|
||||||
_inventory.TryUnequip(uid, slot.ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var held in _hands.EnumerateHeld(uid))
|
|
||||||
{
|
|
||||||
_hands.TryDrop(uid, held);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
|
||||||
_mindSystem.TransferTo(mindId, parent, mind: mind);
|
|
||||||
|
|
||||||
if (TryComp<PolymorphableComponent>(parent, out var polymorphableComponent))
|
|
||||||
polymorphableComponent.LastPolymorphEnd = _gameTiming.CurTime;
|
|
||||||
|
|
||||||
// if an item polymorph was picked up, put it back down after reverting
|
|
||||||
Transform(parent).AttachToGridOrMap();
|
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
|
|
||||||
("parent", Identity.Entity(uid, EntityManager)),
|
|
||||||
("child", Identity.Entity(parent, EntityManager))),
|
|
||||||
parent);
|
|
||||||
QueueDel(uid);
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a sidebar action for an entity to be able to polymorph at will
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The string of the id of the polymorph action</param>
|
|
||||||
/// <param name="target">The entity that will be gaining the action</param>
|
|
||||||
public void CreatePolymorphAction(string id, EntityUid target)
|
|
||||||
{
|
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(id, out var polyproto))
|
|
||||||
{
|
|
||||||
_sawmill.Error("Invalid polymorph prototype");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryComp<PolymorphableComponent>(target, out var polycomp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
polycomp.PolymorphActions ??= new Dictionary<string, EntityUid>();
|
|
||||||
if (polycomp.PolymorphActions.ContainsKey(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var entproto = _proto.Index<EntityPrototype>(polyproto.Entity);
|
|
||||||
|
|
||||||
EntityUid? actionId = default!;
|
|
||||||
if (!_actions.AddAction(target, ref actionId, RevertPolymorphId, target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
polycomp.PolymorphActions.Add(id, actionId.Value);
|
|
||||||
_metaData.SetEntityName(actionId.Value, Loc.GetString("polymorph-self-action-name", ("target", entproto.Name)));
|
|
||||||
_metaData.SetEntityDescription(actionId.Value, Loc.GetString("polymorph-self-action-description", ("target", entproto.Name)));
|
|
||||||
|
|
||||||
if (!_actions.TryGetActionData(actionId, out var baseAction))
|
|
||||||
return;
|
|
||||||
|
|
||||||
baseAction.Icon = new SpriteSpecifier.EntityPrototype(polyproto.Entity);
|
|
||||||
if (baseAction is InstantActionComponent action)
|
|
||||||
action.Event = new PolymorphActionEvent { Prototype = polyproto };
|
|
||||||
}
|
|
||||||
|
|
||||||
[PublicAPI]
|
|
||||||
public void RemovePolymorphAction(string id, EntityUid target, PolymorphableComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(target, ref component, false))
|
|
||||||
return;
|
|
||||||
if (component.PolymorphActions == null)
|
|
||||||
return;
|
|
||||||
if (component.PolymorphActions.TryGetValue(id, out var val))
|
|
||||||
_actions.RemoveAction(target, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<PolymorphedEntityComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var comp))
|
|
||||||
{
|
|
||||||
comp.Time += frameTime;
|
|
||||||
|
|
||||||
if (!_proto.TryIndex(comp.Prototype, out PolymorphPrototype? proto))
|
|
||||||
{
|
|
||||||
_sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while updating. Entity {ToPrettyString(uid)}. Prototype: {comp.Prototype}");
|
|
||||||
RemCompDeferred(uid, comp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.Duration != null && comp.Time >= proto.Duration)
|
|
||||||
{
|
|
||||||
Revert(uid, comp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryComp<MobStateComponent>(uid, out var mob))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (proto.RevertOnDeath && _mobState.IsDead(uid, mob) ||
|
|
||||||
proto.RevertOnCrit && _mobState.IsIncapacitated(uid, mob))
|
|
||||||
{
|
|
||||||
Revert(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCollide();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(Entity<PolymorphedEntityComponent> ent, ref MapInitEvent args)
|
||||||
|
{
|
||||||
|
var (uid, component) = ent;
|
||||||
|
if (component.Configuration.Forced)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_actions.AddAction(uid, ref component.Action, out var action, RevertPolymorphId))
|
||||||
|
{
|
||||||
|
action.EntityIcon = component.Parent;
|
||||||
|
action.UseDelay = TimeSpan.FromSeconds(component.Configuration.Delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPolymorphActionEvent(Entity<PolymorphableComponent> ent, ref PolymorphActionEvent args)
|
||||||
|
{
|
||||||
|
PolymorphEntity(ent, args.Prototype.Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRevertPolymorphActionEvent(Entity<PolymorphedEntityComponent> ent,
|
||||||
|
ref RevertPolymorphActionEvent args)
|
||||||
|
{
|
||||||
|
Revert((ent, ent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBeforeFullyEaten(Entity<PolymorphedEntityComponent> ent, ref BeforeFullyEatenEvent args)
|
||||||
|
{
|
||||||
|
var (_, comp) = ent;
|
||||||
|
if (comp.Configuration.RevertOnEat)
|
||||||
|
{
|
||||||
|
args.Cancel();
|
||||||
|
Revert((ent, ent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBeforeFullySliced(Entity<PolymorphedEntityComponent> ent, ref BeforeFullySlicedEvent args)
|
||||||
|
{
|
||||||
|
var (_, comp) = ent;
|
||||||
|
if (comp.Configuration.RevertOnEat)
|
||||||
|
{
|
||||||
|
args.Cancel();
|
||||||
|
Revert((ent, ent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// It is possible to be polymorphed into an entity that can't "die", but is instead
|
||||||
|
/// destroyed. This handler ensures that destruction is treated like death.
|
||||||
|
/// </summary>
|
||||||
|
private void OnDestruction(Entity<PolymorphedEntityComponent> ent, ref DestructionEventArgs args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.Configuration.RevertOnDeath)
|
||||||
|
{
|
||||||
|
Revert((ent, ent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Polymorphs the target entity into the specific polymorph prototype
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">The entity that will be transformed</param>
|
||||||
|
/// <param name="protoId">The id of the polymorph prototype</param>
|
||||||
|
public EntityUid? PolymorphEntity(EntityUid uid, ProtoId<PolymorphPrototype> protoId)
|
||||||
|
{
|
||||||
|
var config = _proto.Index(protoId).Configuration;
|
||||||
|
return PolymorphEntity(uid, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Polymorphs the target entity into another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">The entity that will be transformed</param>
|
||||||
|
/// <param name="configuration">Polymorph data</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public EntityUid? PolymorphEntity(EntityUid uid, PolymorphConfiguration configuration)
|
||||||
|
{
|
||||||
|
// if it's already morphed, don't allow it again with this condition active.
|
||||||
|
if (!configuration.AllowRepeatedMorphs && HasComp<PolymorphedEntityComponent>(uid))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// If this polymorph has a cooldown, check if that amount of time has passed since the
|
||||||
|
// last polymorph ended.
|
||||||
|
if (TryComp<PolymorphableComponent>(uid, out var polymorphableComponent) &&
|
||||||
|
polymorphableComponent.LastPolymorphEnd != null &&
|
||||||
|
_gameTiming.CurTime < polymorphableComponent.LastPolymorphEnd + configuration.Cooldown)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// mostly just for vehicles
|
||||||
|
_buckle.TryUnbuckle(uid, uid, true);
|
||||||
|
|
||||||
|
var targetTransformComp = Transform(uid);
|
||||||
|
|
||||||
|
var child = Spawn(configuration.Entity, targetTransformComp.Coordinates);
|
||||||
|
|
||||||
|
MakeSentientCommand.MakeSentient(child, EntityManager);
|
||||||
|
|
||||||
|
var polymorphedComp = _compFact.GetComponent<PolymorphedEntityComponent>();
|
||||||
|
polymorphedComp.Parent = uid;
|
||||||
|
polymorphedComp.Configuration = configuration;
|
||||||
|
AddComp(child, polymorphedComp);
|
||||||
|
|
||||||
|
var childXform = Transform(child);
|
||||||
|
_transform.SetLocalRotation(child, targetTransformComp.LocalRotation, childXform);
|
||||||
|
|
||||||
|
if (_container.TryGetContainingContainer(uid, out var cont))
|
||||||
|
_container.Insert(child, cont);
|
||||||
|
|
||||||
|
//Transfers all damage from the original to the new one
|
||||||
|
if (configuration.TransferDamage &&
|
||||||
|
TryComp<DamageableComponent>(child, out var damageParent) &&
|
||||||
|
_mobThreshold.GetScaledDamage(uid, child, out var damage) &&
|
||||||
|
damage != null)
|
||||||
|
{
|
||||||
|
_damageable.SetDamage(child, damageParent, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.Inventory == PolymorphInventoryChange.Transfer)
|
||||||
|
{
|
||||||
|
_inventory.TransferEntityInventories(uid, child);
|
||||||
|
foreach (var hand in _hands.EnumerateHeld(uid))
|
||||||
|
{
|
||||||
|
_hands.TryDrop(uid, hand, checkActionBlocker: false);
|
||||||
|
_hands.TryPickupAnyHand(child, hand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (configuration.Inventory == PolymorphInventoryChange.Drop)
|
||||||
|
{
|
||||||
|
if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
|
||||||
|
{
|
||||||
|
while (enumerator.MoveNext(out var slot))
|
||||||
|
{
|
||||||
|
_inventory.TryUnequip(uid, slot.ID, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var held in _hands.EnumerateHeld(uid))
|
||||||
|
{
|
||||||
|
_hands.TryDrop(uid, held);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.TransferName && TryComp<MetaDataComponent>(uid, out var targetMeta))
|
||||||
|
_metaData.SetEntityName(child, targetMeta.EntityName);
|
||||||
|
|
||||||
|
if (configuration.TransferHumanoidAppearance)
|
||||||
|
{
|
||||||
|
_humanoid.CloneAppearance(uid, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
||||||
|
_mindSystem.TransferTo(mindId, child, mind: mind);
|
||||||
|
|
||||||
|
//Ensures a map to banish the entity to
|
||||||
|
EnsurePausedMap();
|
||||||
|
if (PausedMap != null)
|
||||||
|
_transform.SetParent(uid, targetTransformComp, PausedMap.Value);
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverts a polymorphed entity back into its original form
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">The entityuid of the entity being reverted</param>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
public EntityUid? Revert(Entity<PolymorphedEntityComponent?> ent)
|
||||||
|
{
|
||||||
|
var (uid, component) = ent;
|
||||||
|
if (!Resolve(ent, ref component))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (Deleted(uid))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var parent = component.Parent;
|
||||||
|
if (Deleted(parent))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var uidXform = Transform(uid);
|
||||||
|
var parentXform = Transform(parent);
|
||||||
|
|
||||||
|
_transform.SetParent(parent, parentXform, uidXform.ParentUid);
|
||||||
|
_transform.SetCoordinates(parent, parentXform, uidXform.Coordinates, uidXform.LocalRotation);
|
||||||
|
|
||||||
|
if (component.Configuration.TransferDamage &&
|
||||||
|
TryComp<DamageableComponent>(parent, out var damageParent) &&
|
||||||
|
_mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
|
||||||
|
damage != null)
|
||||||
|
{
|
||||||
|
_damageable.SetDamage(parent, damageParent, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Configuration.Inventory == PolymorphInventoryChange.Transfer)
|
||||||
|
{
|
||||||
|
_inventory.TransferEntityInventories(uid, parent);
|
||||||
|
foreach (var held in _hands.EnumerateHeld(uid))
|
||||||
|
{
|
||||||
|
_hands.TryDrop(uid, held);
|
||||||
|
_hands.TryPickupAnyHand(parent, held, checkActionBlocker: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (component.Configuration.Inventory == PolymorphInventoryChange.Drop)
|
||||||
|
{
|
||||||
|
if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
|
||||||
|
{
|
||||||
|
while (enumerator.MoveNext(out var slot))
|
||||||
|
{
|
||||||
|
_inventory.TryUnequip(uid, slot.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var held in _hands.EnumerateHeld(uid))
|
||||||
|
{
|
||||||
|
_hands.TryDrop(uid, held);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
||||||
|
_mindSystem.TransferTo(mindId, parent, mind: mind);
|
||||||
|
|
||||||
|
if (TryComp<PolymorphableComponent>(parent, out var polymorphableComponent))
|
||||||
|
polymorphableComponent.LastPolymorphEnd = _gameTiming.CurTime;
|
||||||
|
|
||||||
|
// if an item polymorph was picked up, put it back down after reverting
|
||||||
|
_transform.AttachToGridOrMap(parent, parentXform);
|
||||||
|
|
||||||
|
_popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
|
||||||
|
("parent", Identity.Entity(uid, EntityManager)),
|
||||||
|
("child", Identity.Entity(parent, EntityManager))),
|
||||||
|
parent);
|
||||||
|
QueueDel(uid);
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a sidebar action for an entity to be able to polymorph at will
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The string of the id of the polymorph action</param>
|
||||||
|
/// <param name="target">The entity that will be gaining the action</param>
|
||||||
|
public void CreatePolymorphAction(ProtoId<PolymorphPrototype> id, Entity<PolymorphableComponent> target)
|
||||||
|
{
|
||||||
|
target.Comp.PolymorphActions ??= new();
|
||||||
|
if (target.Comp.PolymorphActions.ContainsKey(id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var polyProto = _proto.Index(id);
|
||||||
|
var entProto = _proto.Index(polyProto.Configuration.Entity);
|
||||||
|
|
||||||
|
EntityUid? actionId = default!;
|
||||||
|
if (!_actions.AddAction(target, ref actionId, RevertPolymorphId, target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
target.Comp.PolymorphActions.Add(id, actionId.Value);
|
||||||
|
|
||||||
|
var metaDataCache = MetaData(actionId.Value);
|
||||||
|
_metaData.SetEntityName(actionId.Value, Loc.GetString("polymorph-self-action-name", ("target", entProto.Name)), metaDataCache);
|
||||||
|
_metaData.SetEntityDescription(actionId.Value, Loc.GetString("polymorph-self-action-description", ("target", entProto.Name)), metaDataCache);
|
||||||
|
|
||||||
|
if (!_actions.TryGetActionData(actionId, out var baseAction))
|
||||||
|
return;
|
||||||
|
|
||||||
|
baseAction.Icon = new SpriteSpecifier.EntityPrototype(polyProto.Configuration.Entity);
|
||||||
|
if (baseAction is InstantActionComponent action)
|
||||||
|
action.Event = new PolymorphActionEvent(prototype: polyProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePolymorphAction(ProtoId<PolymorphPrototype> id, Entity<PolymorphableComponent> target)
|
||||||
|
{
|
||||||
|
if (target.Comp.PolymorphActions == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (target.Comp.PolymorphActions.TryGetValue(id, out var val))
|
||||||
|
_actions.RemoveAction(target, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed class PolymorphCommand : ToolshedCommand
|
|||||||
{
|
{
|
||||||
_system ??= GetSys<PolymorphSystem>();
|
_system ??= GetSys<PolymorphSystem>();
|
||||||
|
|
||||||
return _system.PolymorphEntity(input, prototype.Value);
|
return _system.PolymorphEntity(input, prototype.Value.Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandImplementation]
|
[CommandImplementation]
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Server.Polymorph.Systems;
|
using Content.Server.Polymorph.Systems;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Polymorph;
|
|
||||||
using Robust.Shared.Toolshed;
|
using Robust.Shared.Toolshed;
|
||||||
using Robust.Shared.Toolshed.TypeParsers;
|
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Toolshed;
|
namespace Content.Server.Polymorph.Toolshed;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Content.Shared.Polymorph;
|
using Content.Shared.Polymorph;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -8,7 +9,8 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
|||||||
/// Artifact polymorphs surrounding entities when triggered.
|
/// Artifact polymorphs surrounding entities when triggered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class PolyArtifactComponent : Component
|
[Access(typeof(PolyOthersArtifactSystem))]
|
||||||
|
public sealed partial class PolyOthersArtifactComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The polymorph effect to trigger.
|
/// The polymorph effect to trigger.
|
||||||
@@ -7,7 +7,7 @@ using Robust.Shared.Audio.Systems;
|
|||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
||||||
|
|
||||||
public sealed class PolyArtifactSystem : EntitySystem
|
public sealed class PolyOthersArtifactSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mob = default!;
|
[Dependency] private readonly MobStateSystem _mob = default!;
|
||||||
@@ -19,25 +19,25 @@ public sealed class PolyArtifactSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<PolyArtifactComponent, ArtifactActivatedEvent>(OnActivate);
|
SubscribeLocalEvent<PolyOthersArtifactComponent, ArtifactActivatedEvent>(OnActivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provided target is alive and is not a zombie, polymorphs the target.
|
/// Provided target is alive and is not a zombie, polymorphs the target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnActivate(EntityUid uid, PolyArtifactComponent component, ArtifactActivatedEvent args)
|
private void OnActivate(Entity<PolyOthersArtifactComponent> ent, ref ArtifactActivatedEvent args)
|
||||||
{
|
{
|
||||||
var xform = Transform(uid);
|
var xform = Transform(ent);
|
||||||
var humanoids = new HashSet<Entity<HumanoidAppearanceComponent>>();
|
var humanoids = new HashSet<Entity<HumanoidAppearanceComponent>>();
|
||||||
_lookup.GetEntitiesInRange(xform.Coordinates, component.Range, humanoids);
|
_lookup.GetEntitiesInRange(xform.Coordinates, ent.Comp.Range, humanoids);
|
||||||
|
|
||||||
foreach (var comp in humanoids)
|
foreach (var comp in humanoids)
|
||||||
{
|
{
|
||||||
var target = comp.Owner;
|
var target = comp.Owner;
|
||||||
if (_mob.IsAlive(target))
|
if (_mob.IsAlive(target))
|
||||||
{
|
{
|
||||||
_poly.PolymorphEntity(target, component.PolymorphPrototypeName);
|
_poly.PolymorphEntity(target, ent.Comp.PolymorphPrototypeName);
|
||||||
_audio.PlayPvs(component.PolySound, uid);
|
_audio.PlayPvs(ent.Comp.PolySound, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,11 @@ public sealed partial class PolymorphActionEvent : InstantActionEvent
|
|||||||
/// the specific polymorph.
|
/// the specific polymorph.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PolymorphPrototype Prototype = default!;
|
public PolymorphPrototype Prototype = default!;
|
||||||
|
|
||||||
|
public PolymorphActionEvent(PolymorphPrototype prototype) : this()
|
||||||
|
{
|
||||||
|
Prototype = prototype;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed partial class RevertPolymorphActionEvent : InstantActionEvent
|
public sealed partial class RevertPolymorphActionEvent : InstantActionEvent
|
||||||
|
|||||||
@@ -1,116 +1,125 @@
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
|
||||||
|
|
||||||
namespace Content.Shared.Polymorph
|
namespace Content.Shared.Polymorph;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Polymorphs generally describe any type of transformation that can be applied to an entity.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed partial class PolymorphPrototype : IPrototype, IInheritingPrototype
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; private set; } = default!;
|
||||||
|
|
||||||
|
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<PolymorphPrototype>))]
|
||||||
|
public string[]? Parents { get; private set; }
|
||||||
|
|
||||||
|
[NeverPushInheritance]
|
||||||
|
[AbstractDataField]
|
||||||
|
public bool Abstract { get; private set; }
|
||||||
|
|
||||||
|
[DataField(required: true, serverOnly: true)]
|
||||||
|
public PolymorphConfiguration Configuration = new();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines information about the polymorph
|
||||||
|
/// </summary>
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed partial record PolymorphConfiguration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Polymorphs generally describe any type of transformation that can be applied to an entity.
|
/// What entity the polymorph will turn the target into
|
||||||
|
/// must be in here because it makes no sense if it isn't
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Prototype("polymorph")]
|
[DataField(required: true, serverOnly: true)]
|
||||||
[DataDefinition]
|
public EntProtoId Entity;
|
||||||
public sealed partial class PolymorphPrototype : IPrototype, IInheritingPrototype
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
[IdDataField]
|
|
||||||
public string ID { get; private set; } = default!;
|
|
||||||
|
|
||||||
[DataField("name")]
|
/// <summary>
|
||||||
public string Name { get; private set; } = string.Empty;
|
/// The delay between the polymorph's uses in seconds
|
||||||
|
/// Slightly weird as of right now.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(serverOnly: true)]
|
||||||
|
public int Delay = 60;
|
||||||
|
|
||||||
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<PolymorphPrototype>))]
|
/// <summary>
|
||||||
public string[]? Parents { get; private set; }
|
/// The duration of the transformation in seconds
|
||||||
|
/// can be null if there is not one
|
||||||
|
/// </summary>
|
||||||
|
[DataField(serverOnly: true)]
|
||||||
|
public int? Duration;
|
||||||
|
|
||||||
[NeverPushInheritance]
|
/// <summary>
|
||||||
[AbstractDataFieldAttribute]
|
/// whether or not the target can transform as will
|
||||||
public bool Abstract { get; private set; }
|
/// set to true for things like polymorph spells and curses
|
||||||
|
/// </summary>
|
||||||
|
[DataField(serverOnly: true)]
|
||||||
|
public bool Forced;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What entity the polymorph will turn the target into
|
/// Whether or not the entity transfers its damage between forms.
|
||||||
/// must be in here because it makes no sense if it isn't
|
/// </summary>
|
||||||
/// </summary>
|
[DataField(serverOnly: true)]
|
||||||
[DataField("entity", required: true, serverOnly: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
public bool TransferDamage = true;
|
||||||
public string Entity = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The delay between the polymorph's uses in seconds
|
/// Whether or not the entity transfers its name between forms.
|
||||||
/// Slightly weird as of right now.
|
/// </summary>
|
||||||
/// </summary>
|
[DataField(serverOnly: true)]
|
||||||
[DataField("delay", serverOnly: true)]
|
public bool TransferName;
|
||||||
public int Delay = 60;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The duration of the transformation in seconds
|
/// Whether or not the entity transfers its hair, skin color, hair color, etc.
|
||||||
/// can be null if there is not one
|
/// </summary>
|
||||||
/// </summary>
|
[DataField(serverOnly: true)]
|
||||||
[DataField("duration", serverOnly: true)]
|
public bool TransferHumanoidAppearance;
|
||||||
public int? Duration = null;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// whether or not the target can transform as will
|
/// Whether or not the entity transfers its inventory and equipment between forms.
|
||||||
/// set to true for things like polymorph spells and curses
|
/// </summary>
|
||||||
/// </summary>
|
[DataField(serverOnly: true)]
|
||||||
[DataField("forced", serverOnly: true)]
|
public PolymorphInventoryChange Inventory = PolymorphInventoryChange.None;
|
||||||
public bool Forced = false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the entity transfers its damage between forms.
|
/// Whether or not the polymorph reverts when the entity goes into crit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("transferDamage", serverOnly: true)]
|
[DataField(serverOnly: true)]
|
||||||
public bool TransferDamage = true;
|
public bool RevertOnCrit = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the entity transfers its name between forms.
|
/// Whether or not the polymorph reverts when the entity dies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("transferName", serverOnly: true)]
|
[DataField(serverOnly: true)]
|
||||||
public bool TransferName = false;
|
public bool RevertOnDeath = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the entity transfers its hair, skin color, hair color, etc.
|
/// Whether or not the polymorph reverts when the entity is eaten or fully sliced.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("transferHumanoidAppearance", serverOnly: true)]
|
[DataField(serverOnly: true)]
|
||||||
public bool TransferHumanoidAppearance = false;
|
public bool RevertOnEat;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the entity transfers its inventory and equipment between forms.
|
/// Whether or not an already polymorphed entity is able to be polymorphed again
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("inventory", serverOnly: true)]
|
[DataField(serverOnly: true)]
|
||||||
public PolymorphInventoryChange Inventory = PolymorphInventoryChange.None;
|
public bool AllowRepeatedMorphs;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the polymorph reverts when the entity goes into crit.
|
/// The amount of time that should pass after this polymorph has ended, before a new one
|
||||||
/// </summary>
|
/// can occur.
|
||||||
[DataField("revertOnCrit", serverOnly: true)]
|
/// </summary>
|
||||||
public bool RevertOnCrit = true;
|
[DataField(serverOnly: true)]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
/// <summary>
|
public TimeSpan Cooldown = TimeSpan.Zero;
|
||||||
/// Whether or not the polymorph reverts when the entity dies.
|
}
|
||||||
/// </summary>
|
|
||||||
[DataField("revertOnDeath", serverOnly: true)]
|
public enum PolymorphInventoryChange : byte
|
||||||
public bool RevertOnDeath = true;
|
{
|
||||||
|
None,
|
||||||
/// <summary>
|
Drop,
|
||||||
/// Whether or not the polymorph reverts when the entity is eaten or fully sliced.
|
Transfer,
|
||||||
/// </summary>
|
|
||||||
[DataField("revertOnEat", serverOnly: true)]
|
|
||||||
public bool RevertOnEat = false;
|
|
||||||
|
|
||||||
[DataField("allowRepeatedMorphs", serverOnly: true)]
|
|
||||||
public bool AllowRepeatedMorphs = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of time that should pass after this polymorph has ended, before a new one
|
|
||||||
/// can occur.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("cooldown", serverOnly: true)]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public TimeSpan Cooldown = TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PolymorphInventoryChange : byte
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Drop,
|
|
||||||
Transfer,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,49 @@
|
|||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminLizardSmite
|
id: AdminLizardSmite
|
||||||
entity: MobReptilian
|
configuration:
|
||||||
forced: true
|
entity: MobReptilian
|
||||||
transferName: true
|
forced: true
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: Transfer
|
transferHumanoidAppearance: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Transfer
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminMonkeySmite
|
id: AdminMonkeySmite
|
||||||
entity: MobMonkey
|
configuration:
|
||||||
forced: true
|
entity: MobMonkey
|
||||||
inventory: Drop
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Drop
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminBreadSmite
|
id: AdminBreadSmite
|
||||||
entity: FoodBreadPlain
|
configuration:
|
||||||
forced: true
|
entity: FoodBreadPlain
|
||||||
inventory: Drop
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Drop
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminInstrumentSmite
|
id: AdminInstrumentSmite
|
||||||
entity: SuperSynthesizerInstrument
|
configuration:
|
||||||
forced: true
|
entity: SuperSynthesizerInstrument
|
||||||
inventory: Drop
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Drop
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminMouseSmite
|
id: AdminMouseSmite
|
||||||
entity: MobMouse
|
configuration:
|
||||||
forced: true
|
entity: MobMouse
|
||||||
inventory: Drop
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Drop
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AdminDisposalsSmite
|
id: AdminDisposalsSmite
|
||||||
entity: DisposalUnit
|
configuration:
|
||||||
forced: true
|
entity: DisposalUnit
|
||||||
inventory: Drop
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
inventory: Drop
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
|||||||
@@ -1,150 +1,166 @@
|
|||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: Mouse
|
id: Mouse
|
||||||
entity: MobMouse
|
configuration:
|
||||||
forced: true
|
entity: MobMouse
|
||||||
duration: 30
|
forced: true
|
||||||
|
duration: 30
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: Chicken
|
id: Chicken
|
||||||
entity: MobChicken
|
configuration:
|
||||||
forced: true
|
entity: MobChicken
|
||||||
inventory: Drop
|
forced: true
|
||||||
|
inventory: Drop
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: Monkey
|
id: Monkey
|
||||||
entity: MobMonkey
|
configuration:
|
||||||
forced: true
|
entity: MobMonkey
|
||||||
inventory: Drop
|
forced: true
|
||||||
revertOnCrit: true
|
inventory: Drop
|
||||||
revertOnDeath: true
|
revertOnCrit: true
|
||||||
|
revertOnDeath: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: WizardForcedCarp
|
id: WizardForcedCarp
|
||||||
entity: MobCarpMagic
|
configuration:
|
||||||
forced: true
|
entity: MobCarpMagic
|
||||||
inventory: None
|
forced: true
|
||||||
transferName: true
|
inventory: None
|
||||||
transferDamage: true
|
transferName: true
|
||||||
revertOnCrit: false
|
transferDamage: true
|
||||||
revertOnDeath: true
|
revertOnCrit: false
|
||||||
|
revertOnDeath: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: WizardForcedSkeleton
|
id: WizardForcedSkeleton
|
||||||
entity: MobSkeletonPerson
|
configuration:
|
||||||
forced: true
|
entity: MobSkeletonPerson
|
||||||
inventory: Drop
|
forced: true
|
||||||
transferName: true
|
inventory: Drop
|
||||||
transferDamage: true
|
transferName: true
|
||||||
revertOnCrit: false
|
transferDamage: true
|
||||||
revertOnDeath: false
|
revertOnCrit: false
|
||||||
|
revertOnDeath: false
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: WizardForcedMonkey
|
id: WizardForcedMonkey
|
||||||
entity: MobMonkey
|
configuration:
|
||||||
forced: true
|
entity: MobMonkey
|
||||||
inventory: None
|
forced: true
|
||||||
transferName: true
|
inventory: None
|
||||||
transferDamage: true
|
transferName: true
|
||||||
revertOnCrit: false
|
transferDamage: true
|
||||||
revertOnDeath: true
|
revertOnCrit: false
|
||||||
|
revertOnDeath: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: WizardWallDoor
|
id: WizardWallDoor
|
||||||
entity: WoodDoor
|
configuration:
|
||||||
forced: true
|
entity: WoodDoor
|
||||||
inventory: None
|
forced: true
|
||||||
transferName: false
|
inventory: None
|
||||||
transferDamage: false
|
transferName: false
|
||||||
revertOnCrit: false
|
transferDamage: false
|
||||||
revertOnDeath: false
|
revertOnCrit: false
|
||||||
|
revertOnDeath: false
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: WizardForcedCluwne
|
id: WizardForcedCluwne
|
||||||
entity: MobCluwne
|
configuration:
|
||||||
forced: true
|
entity: MobCluwne
|
||||||
transferName: true
|
forced: true
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: Transfer
|
transferHumanoidAppearance: true
|
||||||
revertOnDeath: true
|
inventory: Transfer
|
||||||
|
revertOnDeath: true
|
||||||
|
|
||||||
# this is a test for transferring some visual appearance stuff
|
# this is a test for transferring some visual appearance stuff
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: TestHumanMorph
|
id: TestHumanMorph
|
||||||
entity: MobHuman
|
configuration:
|
||||||
transferName: true
|
entity: MobHuman
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: Transfer
|
transferHumanoidAppearance: true
|
||||||
|
inventory: Transfer
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: AMIVMorph
|
id: AMIVMorph
|
||||||
entity: MobMonkey
|
configuration:
|
||||||
forced: true
|
entity: MobMonkey
|
||||||
inventory: Transfer
|
forced: true
|
||||||
transferName: true
|
inventory: Transfer
|
||||||
revertOnCrit: false
|
transferName: true
|
||||||
revertOnDeath: false
|
revertOnCrit: false
|
||||||
|
revertOnDeath: false
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: BreadMorph
|
id: BreadMorph
|
||||||
entity: FoodBreadPlain
|
configuration:
|
||||||
forced: true
|
entity: FoodBreadPlain
|
||||||
inventory: None
|
forced: true
|
||||||
transferName: false
|
inventory: None
|
||||||
transferDamage: true
|
transferName: false
|
||||||
revertOnCrit: false
|
transferDamage: true
|
||||||
revertOnDeath: true
|
revertOnCrit: false
|
||||||
revertOnEat: true
|
revertOnDeath: true
|
||||||
|
revertOnEat: true
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: TreeMorph
|
id: TreeMorph
|
||||||
entity: FloraTree01
|
configuration:
|
||||||
forced: true
|
entity: FloraTree01
|
||||||
transferName: true
|
forced: true
|
||||||
revertOnDeath: true
|
transferName: true
|
||||||
inventory: Drop
|
revertOnDeath: true
|
||||||
cooldown: 160
|
inventory: Drop
|
||||||
|
cooldown: 160
|
||||||
|
|
||||||
# this is the monkey polymorph for artifact.
|
# this is the monkey polymorph for artifact.
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: ArtifactMonkey
|
id: ArtifactMonkey
|
||||||
entity: MobMonkey
|
configuration:
|
||||||
forced: true
|
entity: MobMonkey
|
||||||
transferName: true
|
forced: true
|
||||||
allowRepeatedMorphs: true
|
transferName: true
|
||||||
inventory: Transfer
|
allowRepeatedMorphs: true
|
||||||
revertOnCrit: true
|
inventory: Transfer
|
||||||
revertOnDeath: true
|
revertOnCrit: true
|
||||||
duration: 20
|
revertOnDeath: true
|
||||||
|
duration: 20
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: ArtifactCluwne
|
id: ArtifactCluwne
|
||||||
entity: MobCluwne
|
configuration:
|
||||||
forced: true
|
entity: MobCluwne
|
||||||
transferName: true
|
forced: true
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: None
|
transferHumanoidAppearance: true
|
||||||
revertOnDeath: true
|
inventory: None
|
||||||
revertOnCrit: true
|
revertOnDeath: true
|
||||||
duration: 30
|
revertOnCrit: true
|
||||||
|
duration: 30
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: ArtifactLizard
|
id: ArtifactLizard
|
||||||
entity: MobLizard
|
configuration:
|
||||||
forced: true
|
entity: MobLizard
|
||||||
transferName: true
|
forced: true
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: None
|
transferHumanoidAppearance: true
|
||||||
revertOnDeath: true
|
inventory: None
|
||||||
revertOnCrit: true
|
revertOnDeath: true
|
||||||
duration: 20
|
revertOnCrit: true
|
||||||
|
duration: 20
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: ArtifactLuminous
|
id: ArtifactLuminous
|
||||||
entity: MobLuminousPerson
|
configuration:
|
||||||
forced: true
|
entity: MobLuminousPerson
|
||||||
transferName: true
|
forced: true
|
||||||
transferHumanoidAppearance: true
|
transferName: true
|
||||||
inventory: None
|
transferHumanoidAppearance: true
|
||||||
revertOnDeath: true
|
inventory: None
|
||||||
revertOnCrit: true
|
revertOnDeath: true
|
||||||
duration: 20
|
revertOnCrit: true
|
||||||
|
duration: 20
|
||||||
|
|||||||
@@ -515,14 +515,14 @@
|
|||||||
targetDepth: 2
|
targetDepth: 2
|
||||||
effectHint: artifact-effect-hint-polymorph
|
effectHint: artifact-effect-hint-polymorph
|
||||||
components:
|
components:
|
||||||
- type: PolyArtifact
|
- type: PolyOthersArtifact
|
||||||
|
|
||||||
- type: artifactEffect
|
- type: artifactEffect
|
||||||
id: EffectPolyLizard
|
id: EffectPolyLizard
|
||||||
targetDepth: 2
|
targetDepth: 2
|
||||||
effectHint: artifact-effect-hint-polymorph
|
effectHint: artifact-effect-hint-polymorph
|
||||||
components:
|
components:
|
||||||
- type: PolyArtifact
|
- type: PolyOthersArtifact
|
||||||
polymorphPrototypeName: ArtifactLizard
|
polymorphPrototypeName: ArtifactLizard
|
||||||
|
|
||||||
- type: artifactEffect
|
- type: artifactEffect
|
||||||
@@ -530,7 +530,7 @@
|
|||||||
targetDepth: 3
|
targetDepth: 3
|
||||||
effectHint: artifact-effect-hint-polymorph
|
effectHint: artifact-effect-hint-polymorph
|
||||||
components:
|
components:
|
||||||
- type: PolyArtifact
|
- type: PolyOthersArtifact
|
||||||
polymorphPrototypeName: ArtifactLuminous
|
polymorphPrototypeName: ArtifactLuminous
|
||||||
|
|
||||||
- type: artifactEffect
|
- type: artifactEffect
|
||||||
|
|||||||
Reference in New Issue
Block a user