Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Content.Client.Smoking;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Polymorph.Components;
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
@@ -10,14 +11,19 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
private EntityQuery<AppearanceComponent> _appearanceQuery;
|
||||
private EntityQuery<SpriteComponent> _spriteQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
|
||||
_spriteQuery = GetEntityQuery<SpriteComponent>();
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, AfterAutoHandleStateEvent>(OnHandleState);
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<ChameleonDisguiseComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
@@ -25,9 +31,25 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
|
||||
CopyComp<SpriteComponent>(ent);
|
||||
CopyComp<GenericVisualizerComponent>(ent);
|
||||
CopyComp<SolutionContainerVisualsComponent>(ent);
|
||||
CopyComp<BurnStateVisualsComponent>(ent);
|
||||
|
||||
// reload appearance to hopefully prevent any invisible layers
|
||||
if (_appearanceQuery.TryComp(ent, out var appearance))
|
||||
_appearance.QueueUpdate(ent, appearance);
|
||||
}
|
||||
|
||||
private void OnStartup(Entity<ChameleonDisguisedComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
if (!_spriteQuery.TryComp(ent, out var sprite))
|
||||
return;
|
||||
|
||||
ent.Comp.WasVisible = sprite.Visible;
|
||||
sprite.Visible = false;
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ChameleonDisguisedComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_spriteQuery.TryComp(ent, out var sprite))
|
||||
sprite.Visible = ent.Comp.WasVisible;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
var entities = _entity.EntityQueryEnumerator<BodyComponent, SpriteComponent, TransformComponent>();
|
||||
while (entities.MoveNext(out var uid, out _, out var sprite, out var xform))
|
||||
{
|
||||
if (!CanSee(uid))
|
||||
if (!CanSee(uid, sprite))
|
||||
continue;
|
||||
|
||||
var entity = uid;
|
||||
@@ -114,7 +114,7 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
Angle eyeRot)
|
||||
{
|
||||
var (uid, sprite, xform) = ent;
|
||||
if (xform.MapID != map || HasOccluders(uid) || !CanSee(uid))
|
||||
if (xform.MapID != map || HasOccluders(uid) || !CanSee(uid, sprite))
|
||||
return;
|
||||
|
||||
var position = _transform.GetWorldPosition(xform);
|
||||
@@ -123,9 +123,9 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
sprite.Render(handle, eyeRot, rotation, position: position);
|
||||
}
|
||||
|
||||
private bool CanSee(EntityUid ent)
|
||||
private bool CanSee(EntityUid ent, SpriteComponent sprite)
|
||||
{
|
||||
return !_entity.HasComponent<ThermalBlockerComponent>(ent);
|
||||
return sprite.Visible && !_entity.HasComponent<ThermalBlockerComponent>(ent);
|
||||
}
|
||||
|
||||
private bool HasOccluders(EntityUid ent)
|
||||
|
||||
@@ -179,8 +179,10 @@ namespace Content.Server.Flash
|
||||
// They shouldn't have flash removed in between right?
|
||||
Flash(entity, user, source, duration, slowTo, displayPopup);
|
||||
|
||||
var distance = (mapPosition.Position - _transform.GetMapCoordinates(entity).Position).Length();
|
||||
|
||||
if (forceStun) // WD
|
||||
_flashSoundSuppressionSystem.Stun(entity, duration);
|
||||
_flashSoundSuppressionSystem.Stun(entity, duration, distance, range);
|
||||
}
|
||||
|
||||
_audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f));
|
||||
|
||||
@@ -1,99 +1,5 @@
|
||||
using Content.Server.Polymorph.Components;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Polymorph;
|
||||
using Content.Shared.Polymorph.Components;
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
using Content.Shared.StatusIcon.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
namespace Content.Server.Polymorph.Systems;
|
||||
|
||||
public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||
[Dependency] private readonly PolymorphSystem _polymorph = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, GotEquippedHandEvent>(OnEquippedHand);
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, DisguiseToggleNoRotEvent>(OnToggleNoRot);
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, DisguiseToggleAnchoredEvent>(OnToggleAnchored);
|
||||
}
|
||||
|
||||
private void OnEquippedHand(Entity<ChameleonDisguiseComponent> ent, ref GotEquippedHandEvent args)
|
||||
{
|
||||
if (!TryComp<PolymorphedEntityComponent>(ent, out var poly))
|
||||
return;
|
||||
|
||||
_polymorph.Revert((ent, poly));
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public override void Disguise(ChameleonProjectorComponent proj, EntityUid user, EntityUid entity)
|
||||
{
|
||||
if (_polymorph.PolymorphEntity(user, proj.Polymorph) is not {} disguise)
|
||||
return;
|
||||
|
||||
// make disguise look real (for simple things at least)
|
||||
var meta = MetaData(entity);
|
||||
_meta.SetEntityName(disguise, meta.EntityName);
|
||||
_meta.SetEntityDescription(disguise, meta.EntityDescription);
|
||||
|
||||
var comp = EnsureComp<ChameleonDisguiseComponent>(disguise);
|
||||
comp.SourceEntity = entity;
|
||||
comp.SourceProto = Prototype(entity)?.ID;
|
||||
Dirty(disguise, comp);
|
||||
|
||||
// no sechud trolling
|
||||
RemComp<StatusIconComponent>(disguise);
|
||||
|
||||
_appearance.CopyData(entity, disguise);
|
||||
|
||||
var mass = CompOrNull<PhysicsComponent>(entity)?.Mass ?? 0f;
|
||||
|
||||
// let the disguise die when its taken enough damage, which then transfers to the player
|
||||
// health is proportional to mass, and capped to not be insane
|
||||
if (TryComp<MobThresholdsComponent>(disguise, out var thresholds))
|
||||
{
|
||||
// if the player is of flesh and blood, cap max health to theirs
|
||||
// so that when reverting damage scales 1:1 and not round removing
|
||||
var playerMax = _mobThreshold.GetThresholdForState(user, MobState.Dead).Float();
|
||||
var max = playerMax == 0f ? proj.MaxHealth : Math.Max(proj.MaxHealth, playerMax);
|
||||
|
||||
var health = Math.Clamp(mass, proj.MinHealth, proj.MaxHealth);
|
||||
_mobThreshold.SetMobStateThreshold(disguise, health, MobState.Critical, thresholds);
|
||||
_mobThreshold.SetMobStateThreshold(disguise, max, MobState.Dead, thresholds);
|
||||
}
|
||||
|
||||
// add actions for controlling transform aspects
|
||||
_actions.AddAction(disguise, proj.NoRotAction);
|
||||
_actions.AddAction(disguise, proj.AnchorAction);
|
||||
}
|
||||
|
||||
private void OnToggleNoRot(Entity<ChameleonDisguiseComponent> ent, ref DisguiseToggleNoRotEvent args)
|
||||
{
|
||||
var xform = Transform(ent);
|
||||
xform.NoLocalRotation = !xform.NoLocalRotation;
|
||||
}
|
||||
|
||||
private void OnToggleAnchored(Entity<ChameleonDisguiseComponent> ent, ref DisguiseToggleAnchoredEvent args)
|
||||
{
|
||||
var uid = ent.Owner;
|
||||
var xform = Transform(uid);
|
||||
if (xform.Anchored)
|
||||
_xform.Unanchor(uid, xform);
|
||||
else
|
||||
_xform.AnchorEntity((uid, xform));
|
||||
}
|
||||
}
|
||||
public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -7,9 +8,22 @@ namespace Content.Shared.Polymorph.Components;
|
||||
/// Component added to disguise entities.
|
||||
/// Used by client to copy over appearance from the disguise's source entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedChameleonProjectorSystem))]
|
||||
[AutoGenerateComponentState(true)]
|
||||
public sealed partial class ChameleonDisguiseComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The user of this disguise.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid User;
|
||||
|
||||
/// <summary>
|
||||
/// The projector that created this disguise.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid Projector;
|
||||
|
||||
/// <summary>
|
||||
/// The disguise source entity for copying the sprite.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Polymorph.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Added to a player when they use a chameleon projector.
|
||||
/// Handles making them invisible and revealing when damaged enough or switching hands.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedChameleonProjectorSystem))]
|
||||
public sealed partial class ChameleonDisguisedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The disguise entity parented to the player.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid Disguise;
|
||||
|
||||
/// <summary>
|
||||
/// For client, whether the user's sprite was previously visible or not.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool WasVisible;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Polymorph;
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -25,22 +24,26 @@ public sealed partial class ChameleonProjectorComponent : Component
|
||||
public EntityWhitelist? Blacklist;
|
||||
|
||||
/// <summary>
|
||||
/// Polymorph configuration for the disguise entity.
|
||||
/// Disguise entity to spawn and use.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public PolymorphConfiguration Polymorph = new();
|
||||
public EntProtoId DisguiseProto = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Action for disabling your disguise's rotation.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId NoRotAction = "ActionDisguiseNoRot";
|
||||
[DataField]
|
||||
public EntityUid? NoRotActionEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Action for anchoring your disguise in place.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId AnchorAction = "ActionDisguiseAnchor";
|
||||
[DataField]
|
||||
public EntityUid? AnchorActionEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum health to give the disguise.
|
||||
@@ -54,6 +57,12 @@ public sealed partial class ChameleonProjectorComponent : Component
|
||||
[DataField]
|
||||
public float MaxHealth = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// Popup shown to the user when they try to disguise as an entity inside a container.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId ContainerPopup = "chameleon-projector-inside-container";
|
||||
|
||||
/// <summary>
|
||||
/// Popup shown to the user when they try to disguise as an invalid entity.
|
||||
/// </summary>
|
||||
@@ -65,4 +74,10 @@ public sealed partial class ChameleonProjectorComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId SuccessPopup = "chameleon-projector-success";
|
||||
|
||||
/// <summary>
|
||||
/// User currently disguised by this projector, if any
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid? Disguised;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,173 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.Coordinates;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Polymorph;
|
||||
using Content.Shared.Polymorph.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Shared.Polymorph.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Handles whitelist/blacklist checking.
|
||||
/// Actual polymorphing and deactivation is done serverside.
|
||||
/// Handles disguise validation, disguising and revealing.
|
||||
/// Most appearance copying is done clientside.
|
||||
/// </summary>
|
||||
public abstract class SharedChameleonProjectorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly ISerializationManager _serMan = default!;
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, InteractHandEvent>(OnDisguiseInteractHand, before: [typeof(SharedItemSystem)]);
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, DamageChangedEvent>(OnDisguiseDamaged);
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, ComponentShutdown>(OnDisguiseShutdown);
|
||||
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, AfterInteractEvent>(OnInteract);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, GetVerbsEvent<UtilityVerb>>(OnGetVerbs);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, DisguiseToggleNoRotEvent>(OnToggleNoRot);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, DisguiseToggleAnchoredEvent>(OnToggleAnchored);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, HandDeselectedEvent>(OnDeselected);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, GotUnequippedHandEvent>(OnUnequipped);
|
||||
SubscribeLocalEvent<ChameleonProjectorComponent, ComponentShutdown>(OnProjectorShutdown);
|
||||
}
|
||||
|
||||
#region Disguise entity
|
||||
|
||||
private void OnDisguiseInteractHand(Entity<ChameleonDisguiseComponent> ent, ref InteractHandEvent args)
|
||||
{
|
||||
TryReveal(ent.Comp.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDisguiseDamaged(Entity<ChameleonDisguiseComponent> ent, ref DamageChangedEvent args)
|
||||
{
|
||||
// anything that would damage both like an explosion gets doubled
|
||||
// feature? projector makes your atoms weaker or some bs
|
||||
if (args.DamageDelta is {} damage)
|
||||
_damageable.TryChangeDamage(ent.Comp.User, damage);
|
||||
}
|
||||
|
||||
private void OnDisguiseShutdown(Entity<ChameleonDisguiseComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
_actions.RemoveProvidedActions(ent.Comp.User, ent.Comp.Projector);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Projector
|
||||
|
||||
private void OnInteract(Entity<ChameleonProjectorComponent> ent, ref AfterInteractEvent args)
|
||||
{
|
||||
if (!args.CanReach || args.Target is not {} target)
|
||||
if (args.Handled || !args.CanReach || args.Target is not {} target)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
TryDisguise(ent, args.User, target);
|
||||
}
|
||||
|
||||
private void OnGetVerbs(Entity<ChameleonProjectorComponent> ent, ref GetVerbsEvent<UtilityVerb> args)
|
||||
{
|
||||
if (!args.CanAccess)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
args.Handled = true;
|
||||
var target = args.Target;
|
||||
args.Verbs.Add(new UtilityVerb()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryDisguise(ent, user, target);
|
||||
},
|
||||
Text = Loc.GetString("chameleon-projector-set-disguise")
|
||||
});
|
||||
}
|
||||
|
||||
public bool TryDisguise(Entity<ChameleonProjectorComponent> ent, EntityUid user, EntityUid target)
|
||||
{
|
||||
if (_container.IsEntityInContainer(target))
|
||||
{
|
||||
_popup.PopupClient(Loc.GetString(ent.Comp.ContainerPopup), target, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsInvalid(ent.Comp, target))
|
||||
{
|
||||
_popup.PopupClient(Loc.GetString(ent.Comp.InvalidPopup), target, user);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
_popup.PopupClient(Loc.GetString(ent.Comp.SuccessPopup), target, user);
|
||||
Disguise(ent.Comp, user, target);
|
||||
Disguise(ent, user, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnToggleNoRot(Entity<ChameleonProjectorComponent> ent, ref DisguiseToggleNoRotEvent args)
|
||||
{
|
||||
if (ent.Comp.Disguised is not {} uid)
|
||||
return;
|
||||
|
||||
var xform = Transform(uid);
|
||||
_xform.SetLocalRotationNoLerp(uid, 0, xform);
|
||||
xform.NoLocalRotation = !xform.NoLocalRotation;
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnToggleAnchored(Entity<ChameleonProjectorComponent> ent, ref DisguiseToggleAnchoredEvent args)
|
||||
{
|
||||
if (ent.Comp.Disguised is not {} uid)
|
||||
return;
|
||||
|
||||
var xform = Transform(uid);
|
||||
if (xform.Anchored)
|
||||
_xform.Unanchor(uid, xform);
|
||||
else
|
||||
_xform.AnchorEntity((uid, xform));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDeselected(Entity<ChameleonProjectorComponent> ent, ref HandDeselectedEvent args)
|
||||
{
|
||||
RevealProjector(ent);
|
||||
}
|
||||
|
||||
private void OnUnequipped(Entity<ChameleonProjectorComponent> ent, ref GotUnequippedHandEvent args)
|
||||
{
|
||||
RevealProjector(ent);
|
||||
}
|
||||
|
||||
private void OnProjectorShutdown(Entity<ChameleonProjectorComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
RevealProjector(ent);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region API
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if an entity cannot be used as a disguise.
|
||||
/// </summary>
|
||||
@@ -56,10 +180,81 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// On server, polymorphs the user into an entity and sets up the disguise.
|
||||
/// </summary>
|
||||
public virtual void Disguise(ChameleonProjectorComponent comp, EntityUid user, EntityUid entity)
|
||||
public void Disguise(Entity<ChameleonProjectorComponent> ent, EntityUid user, EntityUid entity)
|
||||
{
|
||||
var proj = ent.Comp;
|
||||
|
||||
// no spawning prediction sorry
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
// reveal first to allow quick switching
|
||||
TryReveal(user);
|
||||
|
||||
// add actions for controlling transform aspects
|
||||
_actions.AddAction(user, ref proj.NoRotActionEntity, proj.NoRotAction, container: ent);
|
||||
_actions.AddAction(user, ref proj.AnchorActionEntity, proj.AnchorAction, container: ent);
|
||||
|
||||
proj.Disguised = user;
|
||||
|
||||
var disguise = SpawnAttachedTo(proj.DisguiseProto, user.ToCoordinates());
|
||||
|
||||
var disguised = AddComp<ChameleonDisguisedComponent>(user);
|
||||
disguised.Disguise = disguise;
|
||||
Dirty(user, disguised);
|
||||
|
||||
// make disguise look real (for simple things at least)
|
||||
var meta = MetaData(entity);
|
||||
_meta.SetEntityName(disguise, meta.EntityName);
|
||||
_meta.SetEntityDescription(disguise, meta.EntityDescription);
|
||||
|
||||
var comp = EnsureComp<ChameleonDisguiseComponent>(disguise);
|
||||
comp.User = user;
|
||||
comp.Projector = ent;
|
||||
comp.SourceEntity = entity;
|
||||
comp.SourceProto = Prototype(entity)?.ID;
|
||||
Dirty(disguise, comp);
|
||||
|
||||
// item disguises can be picked up to be revealed, also makes sure their examine size is correct
|
||||
CopyComp<ItemComponent>((disguise, comp));
|
||||
|
||||
_appearance.CopyData(entity, disguise);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the disguise, if the user is disguised.
|
||||
/// </summary>
|
||||
public bool TryReveal(Entity<ChameleonDisguisedComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (TryComp<ChameleonDisguiseComponent>(ent.Comp.Disguise, out var disguise)
|
||||
&& TryComp<ChameleonProjectorComponent>(disguise.Projector, out var proj))
|
||||
{
|
||||
proj.Disguised = null;
|
||||
}
|
||||
|
||||
var xform = Transform(ent);
|
||||
xform.NoLocalRotation = false;
|
||||
_xform.Unanchor(ent, xform);
|
||||
|
||||
Del(ent.Comp.Disguise);
|
||||
RemComp<ChameleonDisguisedComponent>(ent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reveal a projector's user, if any.
|
||||
/// </summary>
|
||||
public void RevealProjector(Entity<ChameleonProjectorComponent> ent)
|
||||
{
|
||||
if (ent.Comp.Disguised is {} user)
|
||||
TryReveal(user);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Copy a component from the source entity/prototype to the disguise entity.
|
||||
/// </summary>
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace Content.Shared.Standing
|
||||
|
||||
// WD EDIT
|
||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanLieDown = false;
|
||||
public bool CanLieDown;
|
||||
|
||||
// WD EDIT
|
||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool AutoGetUp = false;
|
||||
public bool AutoGetUp = true;
|
||||
|
||||
/// <summary>
|
||||
/// List of fixtures that had their collision mask changed when the entity was downed.
|
||||
|
||||
@@ -5,5 +5,6 @@ namespace Content.Shared._White.BuffedFlashGrenade;
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class FlashSoundSuppressionComponent : Component
|
||||
{
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MaxRange = 3f;
|
||||
}
|
||||
|
||||
@@ -18,26 +18,37 @@ public sealed class FlashSoundSuppressionSystem : EntitySystem
|
||||
private void OnGetFlashbanged(Entity<FlashSoundSuppressionComponent> ent,
|
||||
ref InventoryRelayedEvent<GetFlashbangedEvent> args)
|
||||
{
|
||||
args.Args.Protected = true;
|
||||
args.Args.MaxRange = MathF.Min(args.Args.MaxRange, ent.Comp.MaxRange);
|
||||
}
|
||||
|
||||
public void Stun(EntityUid target, float duration)
|
||||
public void Stun(EntityUid target, float duration, float distance, float range)
|
||||
{
|
||||
if (HasComp<FlashSoundSuppressionComponent>(target))
|
||||
return;
|
||||
if (TryComp<FlashSoundSuppressionComponent>(target, out var suppression))
|
||||
range = MathF.Min(range, suppression.MaxRange);
|
||||
|
||||
var ev = new GetFlashbangedEvent();
|
||||
ev.MaxRange = range;
|
||||
RaiseLocalEvent(target, ev);
|
||||
if (ev.Protected)
|
||||
range = MathF.Min(range, ev.MaxRange);
|
||||
|
||||
if (range <= 0f)
|
||||
return;
|
||||
if (distance < 0f)
|
||||
distance = 0f;
|
||||
if (distance > range)
|
||||
return;
|
||||
|
||||
_stunSystem.TryParalyze(target, TimeSpan.FromSeconds(duration / 1000f), true);
|
||||
var stunTime = float.Lerp(duration, 0f, distance / range);
|
||||
if (stunTime <= 0f)
|
||||
return;
|
||||
|
||||
_stunSystem.TryParalyze(target, TimeSpan.FromSeconds(stunTime / 1000f), true);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GetFlashbangedEvent : EntityEventArgs, IInventoryRelayEvent
|
||||
{
|
||||
public bool Protected;
|
||||
public float MaxRange = 7f;
|
||||
|
||||
public SlotFlags TargetSlots => SlotFlags.EARS | SlotFlags.HEAD;
|
||||
}
|
||||
|
||||
@@ -6425,3 +6425,50 @@
|
||||
id: 408
|
||||
time: '2024-07-22T14:24:00.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/477
|
||||
- author: Aviu
|
||||
changes:
|
||||
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u043F\u043E\u043B\u043D\u043E\u0440\
|
||||
\u0430\u0437\u043C\u0435\u0440\u043D\u0430\u044F \u0433\u0430\u0440\u043D\u0438\
|
||||
\u0442\u0443\u0440\u0430 \u0438 \u0448\u043B\u0435\u043C\u044B \u0441\u043A\u0430\
|
||||
\u0444\u0430\u043D\u0434\u0440\u043E\u0432 \u0442\u043E\u043B\u044C\u043A\u043E\
|
||||
\ \u0447\u0430\u0441\u0442\u0438\u0447\u043D\u043E \u0437\u0430\u0449\u0438\u0449\
|
||||
\u0430\u044E\u0442 \u043E\u0442 \u0441\u0432\u0435\u0442\u043E\u0448\u0443\u043C\
|
||||
\u043E\u0432\u044B\u0445 \u0433\u0440\u0430\u043D\u0430\u0442, \u0432 \u043E\
|
||||
\u043F\u0440\u0435\u0434\u0435\u043B\u0451\u043D\u043D\u043E\u043C \u0440\u0430\
|
||||
\u0434\u0438\u0443\u0441\u0435."
|
||||
type: Tweak
|
||||
- message: "\u0421\u0442\u0430\u043D \u043E\u0442 \u0441\u0432\u0435\u0442\u043E\
|
||||
\u0448\u0443\u043C\u043E\u0432\u044B\u0445 \u0433\u0440\u0430\u043D\u0430\u0442\
|
||||
\ \u0442\u0435\u043F\u0435\u0440\u044C \u0441\u043A\u0435\u0439\u043B\u0438\u0442\
|
||||
\u0441\u044F \u043E\u0442 \u0440\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\
|
||||
\u044F."
|
||||
type: Tweak
|
||||
- message: "\u0413\u043E\u043B\u043E\u0432\u0430 \u0443\u043B\u044C\u044F \u0442\
|
||||
\u0435\u043F\u0435\u0440\u044C \u0447\u0430\u0441\u0442\u0438\u0447\u043D\u043E\
|
||||
\ \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043E\u0442 \u0441\u0432\
|
||||
\u0435\u0442\u043E\u0448\u0443\u043C\u043E\u0432\u044B\u0445 \u0433\u0440\u0430\
|
||||
\u043D\u0430\u0442."
|
||||
type: Add
|
||||
id: 409
|
||||
time: '2024-07-22T17:06:02.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/478
|
||||
- author: PointPNG
|
||||
changes:
|
||||
- message: "\u0424\u0438\u043A\u0441 \u0412\u0430\u043D\u0434\u0435\u0440\u0431\u043E\
|
||||
\u043A\u0441\u0430."
|
||||
type: Fix
|
||||
- message: "\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0412\u0430\
|
||||
\u0439\u0442\u041C\u0443\u0441\u0430."
|
||||
type: Add
|
||||
id: 410
|
||||
time: '2024-07-23T02:03:31.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/482
|
||||
- author: Aviu
|
||||
changes:
|
||||
- message: "\u0425\u0430\u043C\u0435\u043B\u0435\u043E\u043D \u043F\u0440\u043E\u0435\
|
||||
\u043A\u0442\u043E\u0440 \u0442\u0435\u043F\u0435\u0440\u044C \u0440\u0430\u0431\
|
||||
\u043E\u0442\u0430\u0435\u0442 \u043B\u0443\u0447\u0448\u0435."
|
||||
type: Fix
|
||||
id: 411
|
||||
time: '2024-07-23T15:34:13.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/484
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
chameleon-projector-inside-container = There's no room to scan that!
|
||||
chameleon-projector-invalid = You can't disguise as that!
|
||||
chameleon-projector-success = Projected new disguise.
|
||||
chameleon-projector-set-disguise = Set Disguise
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22599,6 +22599,21 @@ entities:
|
||||
parent: 2
|
||||
- proto: Bola
|
||||
entities:
|
||||
- uid: 15785
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -16.008087,52.70469
|
||||
parent: 2
|
||||
- uid: 15786
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -15.883086,52.60045
|
||||
parent: 2
|
||||
- uid: 15808
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -15.737252,52.746384
|
||||
parent: 2
|
||||
- uid: 15989
|
||||
components:
|
||||
- type: Transform
|
||||
@@ -74162,23 +74177,6 @@ entities:
|
||||
- type: Transform
|
||||
pos: 66.5,-59.5
|
||||
parent: 2
|
||||
- proto: Bola
|
||||
entities:
|
||||
- uid: 15785
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -15.931884,52.728363
|
||||
parent: 2
|
||||
- uid: 15786
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -15.885009,52.478363
|
||||
parent: 2
|
||||
- uid: 15808
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -15.619384,52.650238
|
||||
parent: 2
|
||||
- proto: d20Dice
|
||||
entities:
|
||||
- uid: 9515
|
||||
@@ -127001,6 +126999,11 @@ entities:
|
||||
- type: Transform
|
||||
pos: 10.5,-0.5
|
||||
parent: 2
|
||||
- uid: 16546
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 27.5,0.5
|
||||
parent: 2
|
||||
- uid: 16547
|
||||
components:
|
||||
- type: Transform
|
||||
@@ -129818,6 +129821,11 @@ entities:
|
||||
- type: Transform
|
||||
pos: 59.5,-2.5
|
||||
parent: 2
|
||||
- uid: 18913
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,-40.5
|
||||
parent: 2
|
||||
- proto: ProtolatheMachineCircuitboard
|
||||
entities:
|
||||
- uid: 16922
|
||||
@@ -146917,14 +146925,6 @@ entities:
|
||||
rot: 1.5707963267948966 rad
|
||||
pos: -59.5,5.5
|
||||
parent: 2
|
||||
- proto: SurvivalKnife
|
||||
entities:
|
||||
- uid: 19231
|
||||
components:
|
||||
- type: Transform
|
||||
parent: 19230
|
||||
- type: Physics
|
||||
canCollide: False
|
||||
- proto: SynthesizerInstrument
|
||||
entities:
|
||||
- uid: 16
|
||||
@@ -150693,22 +150693,12 @@ entities:
|
||||
parent: 2
|
||||
- proto: ToiletEmpty
|
||||
entities:
|
||||
- uid: 19230
|
||||
- uid: 16721
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
rot: 3.141592653589793 rad
|
||||
pos: -35.5,38.5
|
||||
parent: 2
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
stash: !type:ContainerSlot
|
||||
showEnts: False
|
||||
occludes: True
|
||||
ent: 19231
|
||||
disposals: !type:Container
|
||||
showEnts: False
|
||||
occludes: True
|
||||
ents: []
|
||||
- uid: 19840
|
||||
components:
|
||||
- type: Transform
|
||||
@@ -174139,6 +174129,12 @@ entities:
|
||||
parent: 2
|
||||
- proto: WindoorSecureArmoryLocked
|
||||
entities:
|
||||
- uid: 18569
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: -8.5,50.5
|
||||
parent: 2
|
||||
- uid: 23349
|
||||
components:
|
||||
- type: Transform
|
||||
@@ -174201,12 +174197,6 @@ entities:
|
||||
- type: Transform
|
||||
pos: 11.5,48.5
|
||||
parent: 2
|
||||
- uid: 23358
|
||||
components:
|
||||
- type: Transform
|
||||
rot: -1.5707963267948966 rad
|
||||
pos: -8.5,50.5
|
||||
parent: 2
|
||||
- uid: 23395
|
||||
components:
|
||||
- type: Transform
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
state: icon_alt
|
||||
- type: Clothing
|
||||
equippedPrefix: alt
|
||||
- type: FlashSoundSuppression # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadsetAlt
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
Piercing: 0.9
|
||||
Heat: 0.9
|
||||
- type: FlashImmunity # WD edit
|
||||
- type: FlashSoundSuppression # WD edit
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Brigmedic Hardsuit
|
||||
- type: entity
|
||||
@@ -214,7 +214,7 @@
|
||||
highPressureMultiplier: 0.6
|
||||
lowPressureMultiplier: 1000
|
||||
- type: FlashImmunity # WD edit
|
||||
- type: FlashSoundSuppression # WD edit
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Warden's Hardsuit
|
||||
- type: entity
|
||||
@@ -241,7 +241,7 @@
|
||||
Piercing: 0.9
|
||||
Heat: 0.9
|
||||
- type: FlashImmunity # WD edit
|
||||
- type: FlashSoundSuppression # WD edit
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Captain's Hardsuit
|
||||
- type: entity
|
||||
@@ -259,7 +259,7 @@
|
||||
highPressureMultiplier: 0.3
|
||||
lowPressureMultiplier: 1000
|
||||
- type: FlashImmunity # WD edit
|
||||
- type: FlashSoundSuppression # WD edit
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Inspector's Hardsuit
|
||||
- type: entity
|
||||
@@ -423,6 +423,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Blood-red Medic Hardsuit
|
||||
- type: entity
|
||||
@@ -450,6 +451,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Syndicate Elite Hardsuit
|
||||
- type: entity
|
||||
@@ -479,6 +481,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Syndicate Commander Hardsuit
|
||||
- type: entity
|
||||
@@ -506,6 +509,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Cybersun Juggernaut Hardsuit
|
||||
- type: entity
|
||||
@@ -531,6 +535,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Wizard Hardsuit
|
||||
- type: entity
|
||||
@@ -557,6 +562,9 @@
|
||||
Piercing: 0.9
|
||||
Heat: 0.9
|
||||
- type: WizardClothes
|
||||
- type: EyeProtection
|
||||
- type: FlashImmunity
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Organic Space Suit
|
||||
- type: entity
|
||||
@@ -632,6 +640,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#ERT Chaplain Hardsuit
|
||||
- type: entity
|
||||
@@ -672,6 +681,7 @@
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
|
||||
- type: FlashSoundSuppression
|
||||
#ERT Medical Hardsuit
|
||||
- type: entity
|
||||
parent: ClothingHeadHelmetHardsuitSyndieElite
|
||||
@@ -688,6 +698,7 @@
|
||||
color: "#adffec"
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#ERT Security Hardsuit
|
||||
- type: entity
|
||||
@@ -712,6 +723,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#ERT Janitor Hardsuit
|
||||
- type: entity
|
||||
@@ -729,6 +741,7 @@
|
||||
color: "#cbadff"
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#CBURN Hardsuit
|
||||
- type: entity
|
||||
@@ -770,6 +783,7 @@
|
||||
Heat: 0.9
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
|
||||
#Deathsquad Hardsuit
|
||||
- type: entity
|
||||
@@ -797,6 +811,8 @@
|
||||
Caustic: 0.95
|
||||
- type: EyeProtection # WD edit
|
||||
- type: FlashImmunity # WD
|
||||
- type: FlashSoundSuppression
|
||||
maxRange: 0
|
||||
- type: ShowHealthBars
|
||||
damageContainers:
|
||||
- Biological
|
||||
|
||||
@@ -15,15 +15,12 @@
|
||||
blacklist:
|
||||
components:
|
||||
- ChameleonDisguise # no becoming kleiner
|
||||
- InsideEntityStorage # no clark kent going in phone booth and becoming superman
|
||||
- MindContainer # no
|
||||
- Pda # PDAs currently make you invisible /!\
|
||||
polymorph:
|
||||
entity: ChameleonDisguise
|
||||
disguiseProto: ChameleonDisguise
|
||||
|
||||
- type: entity
|
||||
noSpawn: true
|
||||
parent: BaseMob
|
||||
id: ChameleonDisguise
|
||||
name: Urist McKleiner
|
||||
components:
|
||||
@@ -31,20 +28,11 @@
|
||||
- type: Sprite
|
||||
sprite: /Textures/Mobs/Species/Human/parts.rsi
|
||||
state: full
|
||||
# so people can attempt to pick it up
|
||||
- type: Item
|
||||
# so it can take damage
|
||||
# projector system sets health to be proportional to mass
|
||||
- type: Transform
|
||||
noRot: true # players rotation and anchor is used instead
|
||||
- type: InteractionOutline
|
||||
- type: Clickable
|
||||
- type: Damageable
|
||||
- type: MobState
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
1: Critical
|
||||
200: Dead
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 1 # precise movement for the perfect spot
|
||||
baseSprintSpeed: 5 # the jig is up
|
||||
- type: ChameleonDisguise
|
||||
|
||||
# actions
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
- type: DeleteOnChangelingRefund
|
||||
- type: FlashImmunity
|
||||
- type: EyeProtection
|
||||
- type: FlashSoundSuppression
|
||||
- type: HiveHead
|
||||
|
||||
- type: entity
|
||||
|
||||
Reference in New Issue
Block a user