Id[entity] 2.0 (real) (#9612)
* starter API * network ID cards * Port more stuff from old identity * Re-implement identity representation + name updating * move * proper name returning for `IdentityName` * move everything important to server, give in to temptation * shared / server / client split sadly. move ensure to shared and spawn to server * identity update queueing + identityblocker * fixes * and just like that it's usable for admins * huge identity pass * pass dos * jesus christ * figs :D * fuck u * fix bad merge. Co-authored-by: Moony <moonheart08@users.noreply.github.com>
This commit is contained in:
7
Content.Client/Access/IdCardSystem.cs
Normal file
7
Content.Client/Access/IdCardSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
|
||||
namespace Content.Client.Access;
|
||||
|
||||
public sealed class IdCardSystem : SharedIdCardSystem
|
||||
{
|
||||
}
|
||||
@@ -170,9 +170,12 @@ namespace Content.Client.Administration.UI
|
||||
if (pl.Antag)
|
||||
sb.Append(new Rune(0x1F5E1)); // 🗡
|
||||
|
||||
sb.AppendFormat("\"{0}\"", pl.CharacterName)
|
||||
.Append(' ')
|
||||
.Append(pl.Username);
|
||||
sb.AppendFormat("\"{0}\"", pl.CharacterName);
|
||||
|
||||
if (pl.IdentityName != pl.CharacterName && pl.IdentityName != string.Empty)
|
||||
sb.Append(' ').AppendFormat("[{0}]", pl.IdentityName);
|
||||
|
||||
sb.Append(' ').Append(pl.Username);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ namespace Content.Client.Administration.UI.CustomControls
|
||||
foreach (var info in _adminSystem.PlayerList)
|
||||
{
|
||||
var displayName = $"{info.CharacterName} ({info.Username})";
|
||||
if (info.IdentityName != info.CharacterName)
|
||||
displayName += $" [{info.IdentityName}]";
|
||||
if (!string.IsNullOrEmpty(FilterLineEdit.Text) &&
|
||||
!displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
|
||||
{
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab
|
||||
{
|
||||
var entry = new PlayerTabEntry(player.Username,
|
||||
player.CharacterName,
|
||||
player.IdentityName,
|
||||
player.StartingJob,
|
||||
player.Antag ? "YES" : "NO",
|
||||
new StyleBoxFlat(useAltColor ? _altColor : _defaultColor),
|
||||
|
||||
@@ -10,7 +10,7 @@ public sealed partial class PlayerTabEntry : ContainerButton
|
||||
{
|
||||
public EntityUid? PlayerUid;
|
||||
|
||||
public PlayerTabEntry(string username, string character, string job, string antagonist, StyleBox styleBox, bool connected)
|
||||
public PlayerTabEntry(string username, string character, string identity, string job, string antagonist, StyleBox styleBox, bool connected)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
@@ -19,6 +19,8 @@ public sealed partial class PlayerTabEntry : ContainerButton
|
||||
UsernameLabel.StyleClasses.Add("Disabled");
|
||||
JobLabel.Text = job;
|
||||
CharacterLabel.Text = character;
|
||||
if (identity != character)
|
||||
CharacterLabel.Text += $" [{identity}]";
|
||||
AntagonistLabel.Text = antagonist;
|
||||
BackgroundColorPanel.PanelOverride = styleBox;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Client.Cargo.UI;
|
||||
using Content.Shared.Cargo.BUI;
|
||||
using Content.Shared.Cargo.Events;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -55,7 +56,7 @@ namespace Content.Client.Cargo.BUI
|
||||
string orderRequester;
|
||||
|
||||
if (entityManager.TryGetComponent<MetaDataComponent>(localPlayer, out var metadata))
|
||||
orderRequester = metadata.EntityName;
|
||||
orderRequester = Identity.Name(localPlayer.Value, entityManager);
|
||||
else
|
||||
orderRequester = string.Empty;
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -11,6 +15,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
public const string StyleClassEntityMenuCountText = "contextMenuCount";
|
||||
|
||||
[Dependency] private IEntityManager _entityManager = default!;
|
||||
[Dependency] private IPlayerManager _playerManager = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The entity that can be accessed by interacting with this element.
|
||||
@@ -74,10 +79,12 @@ namespace Content.Client.ContextMenu.UI
|
||||
|
||||
EntityIcon.Sprite = _entityManager.GetComponentOrNull<ISpriteComponent>(entity);
|
||||
|
||||
if (UserInterfaceManager.DebugMonitors.Visible)
|
||||
var admin = IoCManager.Resolve<IClientAdminManager>();
|
||||
|
||||
if (admin.HasFlag(AdminFlags.Admin | AdminFlags.Debug))
|
||||
Text = _entityManager.ToPrettyString(entity.Value);
|
||||
else
|
||||
Text = _entityManager.GetComponent<MetaDataComponent>(entity.Value).EntityName;
|
||||
Text = Identity.Name(entity.Value, _entityManager, _playerManager.LocalPlayer!.ControlledEntity!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -21,7 +22,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
{
|
||||
if (GroupingContextMenuType == 0)
|
||||
{
|
||||
var newEntities = entities.GroupBy(e => _entityManager.GetComponent<MetaDataComponent>(e).EntityName + (_entityManager.GetComponent<MetaDataComponent>(e).EntityPrototype?.ID ?? string.Empty)).ToList();
|
||||
var newEntities = entities.GroupBy(e => Identity.Name(e, _entityManager) + (_entityManager.GetComponent<MetaDataComponent>(e).EntityPrototype?.ID ?? string.Empty)).ToList();
|
||||
return newEntities.Select(grp => grp.ToList()).ToList();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using Content.Client.Verbs;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
@@ -192,7 +193,7 @@ namespace Content.Client.Examine
|
||||
|
||||
hBox.AddChild(new Label
|
||||
{
|
||||
Text = EntityManager.GetComponent<MetaDataComponent>(target).EntityName,
|
||||
Text = Identity.Name(target, EntityManager, player),
|
||||
HorizontalExpand = true,
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using Content.Shared.Disease.Components;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Damage;
|
||||
|
||||
using Content.Shared.IdentityManagement;
|
||||
using static Content.Shared.MedicalScanner.SharedHealthAnalyzerComponent;
|
||||
|
||||
namespace Content.Client.HealthAnalyzer.UI
|
||||
@@ -28,8 +28,9 @@ namespace Content.Client.HealthAnalyzer.UI
|
||||
if (msg.TargetEntity != null && entities.TryGetComponent<DamageableComponent>(msg.TargetEntity, out var damageable))
|
||||
{
|
||||
string entityName = "Unknown";
|
||||
if (msg.TargetEntity != null && entities.TryGetComponent<MetaDataComponent>(msg.TargetEntity.Value, out var metaData))
|
||||
entityName = metaData.EntityName;
|
||||
if (msg.TargetEntity != null &&
|
||||
entities.TryGetComponent<MetaDataComponent>(msg.TargetEntity.Value, out var metaData))
|
||||
entityName = Identity.Name(msg.TargetEntity.Value, entities);
|
||||
|
||||
IReadOnlyDictionary<string, FixedPoint2> DamagePerGroup = damageable.DamagePerGroup;
|
||||
IReadOnlyDictionary<string, FixedPoint2> DamagePerType = damageable.Damage.DamageDict;
|
||||
|
||||
7
Content.Client/IdentityManagement/IdentitySystem.cs
Normal file
7
Content.Client/IdentityManagement/IdentitySystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.IdentityManagement;
|
||||
|
||||
namespace Content.Client.IdentityManagement;
|
||||
|
||||
public class IdentitySystem : SharedIdentitySystem
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Strip;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Strip.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -28,7 +29,8 @@ namespace Content.Client.Inventory
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_strippingMenu = new StrippingMenu($"{Loc.GetString("strippable-bound-user-interface-stripping-menu-title",("ownerName", IoCManager.Resolve<IEntityManager>().GetComponent<MetaDataComponent>(Owner.Owner).EntityName))}");
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
_strippingMenu = new StrippingMenu($"{Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner.Owner, entMan)))}");
|
||||
|
||||
_strippingMenu.OnClose += Close;
|
||||
_strippingMenu.OpenCentered();
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Client.Items.Components;
|
||||
using Content.Client.Resources;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -159,11 +160,12 @@ namespace Content.Client.Items.UI
|
||||
if (_entityManager.TryGetComponent(_entity, out HandVirtualItemComponent? virtualItem)
|
||||
&& _entityManager.EntityExists(virtualItem.BlockingEntity))
|
||||
{
|
||||
_itemNameLabel.Text = _entityManager.GetComponent<MetaDataComponent>(virtualItem.BlockingEntity).EntityName;
|
||||
// Uses identity because we can be blocked by pulling someone
|
||||
_itemNameLabel.Text = Identity.Name(virtualItem.BlockingEntity, _entityManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
_itemNameLabel.Text = _entityManager.GetComponent<MetaDataComponent>(_entity.Value).EntityName;
|
||||
_itemNameLabel.Text = Identity.Name(_entity.Value, _entityManager);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ namespace Content.Server.Access.Systems
|
||||
jobTitle = jobTitle[..SharedIdCardConsoleComponent.MaxJobTitleLength];
|
||||
|
||||
id.JobTitle = jobTitle;
|
||||
Dirty(id);
|
||||
UpdateEntityName(uid, id);
|
||||
return true;
|
||||
}
|
||||
@@ -96,6 +97,7 @@ namespace Content.Server.Access.Systems
|
||||
fullName = fullName[..SharedIdCardConsoleComponent.MaxFullNameLength];
|
||||
|
||||
id.FullName = fullName;
|
||||
Dirty(id);
|
||||
UpdateEntityName(uid, id);
|
||||
return true;
|
||||
}
|
||||
@@ -129,50 +131,5 @@ namespace Content.Server.Access.Systems
|
||||
("jobSuffix", jobSuffix));
|
||||
EntityManager.GetComponent<MetaDataComponent>(id.Owner).EntityName = val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to find an ID card on an entity. This will look in the entity itself, in the entity's hands, and
|
||||
/// in the entity's inventory.
|
||||
/// </summary>
|
||||
public bool TryFindIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
// check held item?
|
||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||
TryGetIdCard(heldItem, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check entity itself
|
||||
if (TryGetIdCard(uid, out idCard))
|
||||
return true;
|
||||
|
||||
// check inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to get an id card component from an entity, either by getting it directly from the entity, or by
|
||||
/// getting the contained id from a <see cref="PDAComponent"/>.
|
||||
/// </summary>
|
||||
public bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out idCard))
|
||||
return true;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, out PDAComponent? pda) && pda.ContainedID != null)
|
||||
{
|
||||
idCard = pda.ContainedID;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.IdentityManagement;
|
||||
using Content.Server.Players;
|
||||
using Content.Server.Roles;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Administration.Events;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
@@ -25,6 +27,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
_adminManager.OnPermsChanged += OnAdminPermsChanged;
|
||||
SubscribeLocalEvent<IdentityChangedEvent>(OnIdentityChanged);
|
||||
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<RoleAddedEvent>(OnRoleEvent);
|
||||
@@ -46,6 +49,14 @@ namespace Content.Server.Administration.Systems
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIdentityChanged(IdentityChangedEvent ev)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(ev.CharacterEntity, out var actor))
|
||||
return;
|
||||
|
||||
UpdatePlayerList(actor.PlayerSession);
|
||||
}
|
||||
|
||||
private void OnRoleEvent(RoleEvent ev)
|
||||
{
|
||||
if (!ev.Role.Antagonist || ev.Role.Mind.Session == null)
|
||||
@@ -106,9 +117,13 @@ namespace Content.Server.Administration.Systems
|
||||
{
|
||||
var name = session.Name;
|
||||
var username = string.Empty;
|
||||
var identityName = string.Empty;
|
||||
|
||||
if (session.AttachedEntity != null)
|
||||
{
|
||||
username = EntityManager.GetComponent<MetaDataComponent>(session.AttachedEntity.Value).EntityName;
|
||||
identityName = Identity.Name(session.AttachedEntity.Value, EntityManager);
|
||||
}
|
||||
|
||||
var mind = session.ContentData()?.Mind;
|
||||
|
||||
@@ -119,7 +134,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
var connected = session.Status is SessionStatus.Connected or SessionStatus.InGame;
|
||||
|
||||
return new PlayerInfo(name, username, startingRole, antag, session.AttachedEntity.GetValueOrDefault(), session.UserId,
|
||||
return new PlayerInfo(name, username, identityName, startingRole, antag, session.AttachedEntity.GetValueOrDefault(), session.UserId,
|
||||
connected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -110,7 +111,7 @@ namespace Content.Server.Animals.Systems
|
||||
var split = _solutionContainerSystem.SplitSolution(uid, solution, quantity);
|
||||
_solutionContainerSystem.TryAddSolution(ev.ContainerUid, targetSolution, split);
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", ev.ContainerUid)), uid,
|
||||
_popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", Identity.Entity(ev.ContainerUid, EntityManager))), uid,
|
||||
Filter.Entities(ev.UserUid), PopupType.Medium);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Server.Cooldown;
|
||||
using Content.Server.Bible.Components;
|
||||
using Content.Server.MobState;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -121,10 +122,10 @@ namespace Content.Server.Bible
|
||||
{
|
||||
if (_random.Prob(component.FailChance))
|
||||
{
|
||||
var othersFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-others", ("user", args.User),("target", args.Target),("bible", uid));
|
||||
var othersFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-others", ("user", Identity.Entity(args.User, EntityManager)),("target", Identity.Entity(args.Target.Value, EntityManager)),("bible", uid));
|
||||
_popupSystem.PopupEntity(othersFailMessage, args.User, Filter.PvsExcept(args.User), PopupType.SmallCaution);
|
||||
|
||||
var selfFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-self", ("target", args.Target),("bible", uid));
|
||||
var selfFailMessage = Loc.GetString(component.LocPrefix + "-heal-fail-self", ("target", Identity.Entity(args.Target.Value, EntityManager)),("bible", uid));
|
||||
_popupSystem.PopupEntity(selfFailMessage, args.User, Filter.Entities(args.User), PopupType.MediumCaution);
|
||||
|
||||
SoundSystem.Play("/Audio/Effects/hit_kick.ogg", Filter.Pvs(args.Target.Value), args.User);
|
||||
@@ -133,10 +134,10 @@ namespace Content.Server.Bible
|
||||
}
|
||||
}
|
||||
|
||||
var othersMessage = Loc.GetString(component.LocPrefix + "-heal-success-others", ("user", args.User),("target", args.Target),("bible", uid));
|
||||
var othersMessage = Loc.GetString(component.LocPrefix + "-heal-success-others", ("user", Identity.Entity(args.User, EntityManager)),("target", Identity.Entity(args.Target.Value, EntityManager)),("bible", uid));
|
||||
_popupSystem.PopupEntity(othersMessage, args.User, Filter.PvsExcept(args.User), PopupType.Medium);
|
||||
|
||||
var selfMessage = Loc.GetString(component.LocPrefix + "-heal-success-self", ("target", args.Target),("bible", uid));
|
||||
var selfMessage = Loc.GetString(component.LocPrefix + "-heal-success-self", ("target", Identity.Entity(args.Target.Value, EntityManager)),("bible", uid));
|
||||
_popupSystem.PopupEntity(selfMessage, args.User, Filter.Entities(args.User), PopupType.Large);
|
||||
|
||||
SoundSystem.Play(component.HealSoundPath.GetSound(), Filter.Pvs(args.Target.Value), args.User);
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -174,18 +175,18 @@ public sealed class BloodstreamSystem : EntitySystem
|
||||
if (component.BleedAmount > 10)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", uid)));
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", Identity.Entity(uid, EntityManager))));
|
||||
}
|
||||
else if (component.BleedAmount > 0)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", uid)));
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", Identity.Entity(uid, EntityManager))));
|
||||
}
|
||||
|
||||
if (GetBloodLevelPercentage(uid, component) < component.BloodlossThreshold)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", uid)));
|
||||
args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", Identity.Entity(uid, EntityManager))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Server.Popups;
|
||||
using Content.Server.Preferences.Managers;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.CharacterAppearance.Systems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Species;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -176,7 +177,7 @@ namespace Content.Server.Body.Systems
|
||||
EntityManager.DeleteEntity(entity);
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("reassemble-success", ("user", mob)), mob, Filter.Entities(mob));
|
||||
_popupSystem.PopupEntity(Loc.GetString("reassemble-success", ("user", Identity.Entity(mob, EntityManager))), mob, Filter.Entities(mob));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.Examine;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Shared.Player;
|
||||
@@ -241,7 +242,7 @@ namespace Content.Server.Botany.Systems
|
||||
("owner", uid),
|
||||
("usingItem", args.Used)), Filter.Entities(args.User), PopupType.Medium);
|
||||
_popupSystem.PopupEntity(Loc.GetString("plant-holder-component-compost-others-message",
|
||||
("user", args.User),
|
||||
("user", Identity.Entity(args.User, EntityManager)),
|
||||
("usingItem", args.Used),
|
||||
("owner", uid)), uid, Filter.PvsExcept(args.User));
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Weapon.Melee;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Sound;
|
||||
@@ -66,7 +67,7 @@ namespace Content.Server.Chemistry.Components
|
||||
if (!solutionsSys.TryGetInjectableSolution(target.Value, out var targetSolution))
|
||||
{
|
||||
user.PopupMessage(user,
|
||||
Loc.GetString("hypospray-cant-inject", ("target", target)));
|
||||
Loc.GetString("hypospray-cant-inject", ("target", Identity.Entity(target.Value, _entMan))));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState.Components;
|
||||
@@ -63,7 +64,7 @@ public sealed partial class ChemistrySystem
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-cannot-transfer-message",
|
||||
("target", target)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(target, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
}
|
||||
}
|
||||
else if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw)
|
||||
@@ -82,7 +83,7 @@ public sealed partial class ChemistrySystem
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-cannot-draw-message",
|
||||
("target", target)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(target, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +195,7 @@ public sealed partial class ChemistrySystem
|
||||
if (user != target)
|
||||
{
|
||||
// Create a pop-up for the target
|
||||
var userName = MetaData(user).EntityName;
|
||||
var userName = Identity.Name(user, EntityManager);
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-injecting-target",
|
||||
("user", userName)), user, Filter.Entities(target));
|
||||
|
||||
@@ -256,7 +257,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", targetBloodstream.Owner)),
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(targetBloodstream.Owner, EntityManager))),
|
||||
component.Owner, Filter.Entities(user));
|
||||
return;
|
||||
}
|
||||
@@ -270,7 +271,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-inject-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetBloodstream.Owner)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(targetBloodstream.Owner, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
|
||||
Dirty(component);
|
||||
AfterInject(component);
|
||||
@@ -289,7 +290,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-target-already-full-message", ("target", targetEntity)),
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-target-already-full-message", ("target", Identity.Entity(targetEntity, EntityManager))),
|
||||
component.Owner, Filter.Entities(user));
|
||||
return;
|
||||
}
|
||||
@@ -310,7 +311,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-transfer-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetEntity)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(targetEntity, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
|
||||
Dirty(component);
|
||||
AfterInject(component);
|
||||
@@ -349,7 +350,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", targetEntity)),
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", Identity.Entity(targetEntity, EntityManager))),
|
||||
component.Owner, Filter.Entities(user));
|
||||
return;
|
||||
}
|
||||
@@ -371,7 +372,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-draw-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetEntity)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(targetEntity, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
|
||||
Dirty(component);
|
||||
AfterDraw(component);
|
||||
@@ -395,7 +396,7 @@ public sealed partial class ChemistrySystem
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("injector-component-draw-success-message",
|
||||
("amount", drawAmount),
|
||||
("target", target)), component.Owner, Filter.Entities(user));
|
||||
("target", Identity.Entity(target, EntityManager))), component.Owner, Filter.Entities(user));
|
||||
|
||||
Dirty(component);
|
||||
AfterDraw(component);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Climbing;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Popups;
|
||||
@@ -138,7 +139,7 @@ public sealed class ClimbSystem : SharedClimbSystem
|
||||
return;
|
||||
if (user == uid)
|
||||
{
|
||||
var othersMessage = Loc.GetString("comp-climbable-user-climbs-other", ("user", uid),
|
||||
var othersMessage = Loc.GetString("comp-climbable-user-climbs-other", ("user", Identity.Entity(uid, EntityManager)),
|
||||
("climbable", climbable));
|
||||
uid.PopupMessageOtherClients(othersMessage);
|
||||
|
||||
@@ -147,11 +148,11 @@ public sealed class ClimbSystem : SharedClimbSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
var othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other", ("user", user),
|
||||
("moved-user", uid), ("climbable", climbable));
|
||||
var othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other", ("user", Identity.Entity(user, EntityManager)),
|
||||
("moved-user", Identity.Entity(uid, EntityManager)), ("climbable", climbable));
|
||||
user.PopupMessageOtherClients(othersMessage);
|
||||
|
||||
var selfMessage = Loc.GetString("comp-climbable-user-climbs-force", ("moved-user", uid),
|
||||
var selfMessage = Loc.GetString("comp-climbable-user-climbs-force", ("moved-user", Identity.Entity(uid, EntityManager)),
|
||||
("climbable", climbable));
|
||||
user.PopupMessage(selfMessage);
|
||||
}
|
||||
@@ -428,4 +429,4 @@ public sealed class StartClimbEvent : EntityEventArgs
|
||||
{
|
||||
Climbable = climbable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Audio;
|
||||
using Content.Shared.CombatMode;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Stunnable;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -81,14 +82,12 @@ namespace Content.Server.CombatMode
|
||||
{
|
||||
SoundSystem.Play(component.DisarmFailSound.GetSound(), Filter.Pvs(args.Performer), args.Performer, AudioHelpers.WithVariation(0.025f));
|
||||
|
||||
var targetName = Name(args.Target);
|
||||
|
||||
var msgOther = Loc.GetString(
|
||||
"disarm-action-popup-message-other-clients",
|
||||
("performerName", Name(args.Performer)),
|
||||
("targetName", targetName));
|
||||
("performerName", Identity.Entity(args.Performer, EntityManager)),
|
||||
("targetName", Identity.Entity(args.Target, EntityManager)));
|
||||
|
||||
var msgUser = Loc.GetString("disarm-action-popup-message-cursor", ("targetName", targetName ));
|
||||
var msgUser = Loc.GetString("disarm-action-popup-message-cursor", ("targetName", Identity.Entity(args.Target, EntityManager)));
|
||||
|
||||
_popupSystem.PopupEntity(msgOther, args.Performer, filterOther);
|
||||
_popupSystem.PopupEntity(msgUser, args.Performer, Filter.Entities(args.Performer));
|
||||
|
||||
@@ -17,6 +17,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
|
||||
namespace Content.Server.Disease
|
||||
{
|
||||
@@ -120,7 +121,7 @@ namespace Content.Server.Disease
|
||||
EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
|
||||
blocker.Enabled)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("swab-mask-blocked", ("target", args.Target), ("mask", maskUid)), args.User, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(Loc.GetString("swab-mask-blocked", ("target", Identity.Entity(args.Target.Value, EntityManager)), ("mask", maskUid)), args.User, Filter.Entities(args.User));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,7 +321,7 @@ namespace Content.Server.Disease
|
||||
return;
|
||||
|
||||
args.Swab.Used = true;
|
||||
_popupSystem.PopupEntity(Loc.GetString("swab-swabbed", ("target", args.Target)), args.Target.Value, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(Loc.GetString("swab-swabbed", ("target", Identity.Entity(args.Target.Value, EntityManager))), args.Target.Value, Filter.Entities(args.User));
|
||||
|
||||
if (args.Swab.Disease != null || args.Carrier.Diseases.Count == 0)
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
@@ -65,7 +66,7 @@ namespace Content.Server.Emag
|
||||
RaiseLocalEvent(args.Target.Value, emaggedEvent, false);
|
||||
if (emaggedEvent.Handled)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("emag-success", ("target", args.Target)), args.User,
|
||||
_popupSystem.PopupEntity(Loc.GetString("emag-success", ("target", Identity.Entity(args.Target.Value, EntityManager))), args.User,
|
||||
Filter.Entities(args.User), PopupType.Medium);
|
||||
_adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(args.User):player} emagged {ToPrettyString(args.Target.Value):target}");
|
||||
component.Charges--;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Stunnable;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Flash;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
@@ -130,7 +131,7 @@ namespace Content.Server.Flash
|
||||
if (displayPopup && user != null && target != user && EntityManager.EntityExists(user.Value))
|
||||
{
|
||||
user.Value.PopupMessage(target, Loc.GetString("flash-component-user-blinds-you",
|
||||
("user", user.Value)));
|
||||
("user", Identity.Entity(user.Value, EntityManager))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Forensics
|
||||
@@ -59,7 +60,7 @@ namespace Content.Server.Forensics
|
||||
|
||||
if (_inventory.TryGetSlotEntity(args.Target.Value, "gloves", out var gloves))
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-gloves", ("target", args.Target.Value)), args.Target.Value, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-gloves", ("target", Identity.Entity(args.Target.Value, EntityManager))), args.Target.Value, Filter.Entities(args.User));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,8 +68,8 @@ namespace Content.Server.Forensics
|
||||
{
|
||||
if (args.User != args.Target)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-start-scan-user", ("target", args.Target.Value)), args.Target.Value, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-start-scan-target", ("user", args.User)), args.Target.Value, Filter.Entities(args.Target.Value));
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-start-scan-user", ("target", Identity.Entity(args.Target.Value, EntityManager))), args.Target.Value, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(Loc.GetString("forensic-pad-start-scan-target", ("user", Identity.Entity(args.User, EntityManager))), args.Target.Value, Filter.Entities(args.Target.Value));
|
||||
}
|
||||
StartScan(args.User, args.Target.Value, component, fingerprint.Fingerprint);
|
||||
return;
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Physics.Pull;
|
||||
@@ -92,10 +93,10 @@ namespace Content.Server.Hands.Systems
|
||||
if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false))
|
||||
return;
|
||||
|
||||
var targetName = Name(args.Target);
|
||||
|
||||
var msgOther = Loc.GetString("hands-component-disarm-success-others-message", ("disarmer", Name(args.Source)), ("disarmed", targetName));
|
||||
var msgUser = Loc.GetString("hands-component-disarm-success-message", ("disarmed", targetName));
|
||||
var targEnt = Identity.Entity(args.Target, EntityManager);
|
||||
var msgOther = Loc.GetString("hands-component-disarm-success-others-message",
|
||||
("disarmer", Identity.Entity(args.Source, EntityManager)), ("disarmed", targEnt));
|
||||
var msgUser = Loc.GetString("hands-component-disarm-success-message", ("disarmed", targEnt));
|
||||
|
||||
var filter = Filter.Pvs(args.Source).RemoveWhereAttachedEntity(e => e == args.Source);
|
||||
_popupSystem.PopupEntity(msgOther, args.Source, filter);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -60,7 +61,7 @@ public sealed class HealthExaminableSystem : EntitySystem
|
||||
foreach (var threshold in component.Thresholds)
|
||||
{
|
||||
var str = $"health-examinable-{component.LocPrefix}-{type}-{threshold}";
|
||||
var tempLocStr = Loc.GetString($"health-examinable-{component.LocPrefix}-{type}-{threshold}", ("target", uid));
|
||||
var tempLocStr = Loc.GetString($"health-examinable-{component.LocPrefix}-{type}-{threshold}", ("target", Identity.Entity(uid, EntityManager)));
|
||||
|
||||
// i.e., this string doesn't exist, because theres nothing for that threshold
|
||||
if (tempLocStr == str)
|
||||
|
||||
163
Content.Server/IdentityManagement/IdentitySystem.cs
Normal file
163
Content.Server/IdentityManagement/IdentitySystem.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using Content.Server.Access.Systems;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Shared.CharacterAppearance.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.IdentityManagement.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects.Components.Localization;
|
||||
|
||||
namespace Content.Server.IdentityManagement;
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for updating the identity of an entity on init or clothing equip/unequip.
|
||||
/// </summary>
|
||||
public class IdentitySystem : SharedIdentitySystem
|
||||
{
|
||||
[Dependency] private readonly IdCardSystem _idCard = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||
|
||||
private Queue<EntityUid> _queuedIdentityUpdates = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<IdentityComponent, DidEquipEvent>((uid, _, _) => QueueIdentityUpdate(uid));
|
||||
SubscribeLocalEvent<IdentityComponent, DidEquipHandEvent>((uid, _, _) => QueueIdentityUpdate(uid));
|
||||
SubscribeLocalEvent<IdentityComponent, DidUnequipEvent>((uid, _, _) => QueueIdentityUpdate(uid));
|
||||
SubscribeLocalEvent<IdentityComponent, DidUnequipHandEvent>((uid, _, _) => QueueIdentityUpdate(uid));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
while (_queuedIdentityUpdates.TryDequeue(out var ent))
|
||||
{
|
||||
if (!TryComp<IdentityComponent>(ent, out var identity))
|
||||
continue;
|
||||
|
||||
UpdateIdentityInfo(ent, identity);
|
||||
}
|
||||
}
|
||||
|
||||
// This is where the magic happens
|
||||
protected override void OnComponentInit(EntityUid uid, IdentityComponent component, ComponentInit args)
|
||||
{
|
||||
base.OnComponentInit(uid, component, args);
|
||||
|
||||
var ident = Spawn(null, Transform(uid).Coordinates);
|
||||
|
||||
QueueIdentityUpdate(uid);
|
||||
component.IdentityEntitySlot.Insert(ident);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues an identity update to the start of the next tick.
|
||||
/// </summary>
|
||||
public void QueueIdentityUpdate(EntityUid uid)
|
||||
{
|
||||
_queuedIdentityUpdates.Enqueue(uid);
|
||||
}
|
||||
|
||||
#region Private API
|
||||
|
||||
/// <summary>
|
||||
/// Updates the metadata name for the id(entity) from the current state of the character.
|
||||
/// </summary>
|
||||
private void UpdateIdentityInfo(EntityUid uid, IdentityComponent identity)
|
||||
{
|
||||
if (identity.IdentityEntitySlot.ContainedEntity is not { } ident)
|
||||
return;
|
||||
|
||||
var representation = GetIdentityRepresentation(uid);
|
||||
var name = GetIdentityName(uid, representation);
|
||||
|
||||
// Clone the old entity's grammar to the identity entity, for loc purposes.
|
||||
if (TryComp<GrammarComponent>(uid, out var grammar))
|
||||
{
|
||||
var identityGrammar = EnsureComp<GrammarComponent>(ident);
|
||||
identityGrammar.Attributes.Clear();
|
||||
|
||||
foreach (var (k, v) in grammar.Attributes)
|
||||
{
|
||||
identityGrammar.Attributes.Add(k, v);
|
||||
}
|
||||
|
||||
// If presumed name is null and we're using that, we set proper noun to be false ("the old woman")
|
||||
if (name != representation.TrueName && representation.PresumedName == null)
|
||||
identityGrammar.ProperNoun = false;
|
||||
}
|
||||
|
||||
if (name == Name(ident))
|
||||
return;
|
||||
|
||||
MetaData(ident).EntityName = name;
|
||||
|
||||
_adminLog.Add(LogType.Identity, LogImpact.Medium, $"{ToPrettyString(uid)} changed identity to {name}");
|
||||
RaiseLocalEvent(new IdentityChangedEvent(uid, ident));
|
||||
}
|
||||
|
||||
private string GetIdentityName(EntityUid target, IdentityRepresentation representation)
|
||||
{
|
||||
var ev = new SeeIdentityAttemptEvent();
|
||||
|
||||
RaiseLocalEvent(target, ev);
|
||||
return representation.ToStringKnown(!ev.Cancelled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an 'identity representation' of an entity, with their true name being the entity name
|
||||
/// and their 'presumed name' and 'presumed job' being the name/job on their ID card, if they have one.
|
||||
/// </summary>
|
||||
private IdentityRepresentation GetIdentityRepresentation(EntityUid target,
|
||||
InventoryComponent? inventory=null,
|
||||
HumanoidAppearanceComponent? appearance=null)
|
||||
{
|
||||
int age = HumanoidCharacterProfile.MinimumAge;
|
||||
Gender gender = Gender.Neuter;
|
||||
|
||||
// Always use their actual age and gender, since that can't really be changed by an ID.
|
||||
if (Resolve(target, ref appearance, false))
|
||||
{
|
||||
gender = appearance.Gender;
|
||||
age = appearance.Age;
|
||||
}
|
||||
|
||||
var trueName = Name(target);
|
||||
if (!Resolve(target, ref inventory, false))
|
||||
return new(trueName, age, gender, string.Empty);
|
||||
|
||||
string? presumedJob = null;
|
||||
string? presumedName = null;
|
||||
|
||||
// Get their name and job from their ID for their presumed name.
|
||||
if (_idCard.TryFindIdCard(target, out var id))
|
||||
{
|
||||
presumedName = id.FullName;
|
||||
presumedJob = id.JobTitle?.ToLowerInvariant();
|
||||
}
|
||||
|
||||
// If it didn't find a job, that's fine.
|
||||
return new(trueName, age, gender, presumedName, presumedJob);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public sealed class IdentityChangedEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid CharacterEntity;
|
||||
public EntityUid IdentityEntity;
|
||||
|
||||
public IdentityChangedEvent(EntityUid characterEntity, EntityUid identityEntity)
|
||||
{
|
||||
CharacterEntity = characterEntity;
|
||||
IdentityEntity = identityEntity;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Interaction.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -42,7 +43,7 @@ public sealed class InteractionPopupSystem : EntitySystem
|
||||
if (_random.Prob(component.SuccessChance))
|
||||
{
|
||||
if (component.InteractSuccessString != null)
|
||||
msg = Loc.GetString(component.InteractSuccessString, ("target", uid)); // Success message (localized).
|
||||
msg = Loc.GetString(component.InteractSuccessString, ("target", Identity.Entity(uid, EntityManager))); // Success message (localized).
|
||||
|
||||
if (component.InteractSuccessSound != null)
|
||||
sfx = component.InteractSuccessSound.GetSound();
|
||||
@@ -50,7 +51,7 @@ public sealed class InteractionPopupSystem : EntitySystem
|
||||
else
|
||||
{
|
||||
if (component.InteractFailureString != null)
|
||||
msg = Loc.GetString(component.InteractFailureString, ("target", uid)); // Failure message (localized).
|
||||
msg = Loc.GetString(component.InteractFailureString, ("target", Identity.Entity(uid, EntityManager))); // Failure message (localized).
|
||||
|
||||
if (component.InteractFailureSound != null)
|
||||
sfx = component.InteractFailureSound.GetSound();
|
||||
@@ -58,7 +59,8 @@ public sealed class InteractionPopupSystem : EntitySystem
|
||||
|
||||
if (component.MessagePerceivedByOthers != null)
|
||||
{
|
||||
string msgOthers = Loc.GetString(component.MessagePerceivedByOthers,("user", args.User), ("target", uid));
|
||||
string msgOthers = Loc.GetString(component.MessagePerceivedByOthers,
|
||||
("user", Identity.Entity(args.User, EntityManager)), ("target", Identity.Entity(uid, EntityManager)));
|
||||
_popupSystem.PopupEntity(msg, uid, Filter.Entities(args.User));
|
||||
_popupSystem.PopupEntity(msgOthers, uid, Filter.Pvs(uid, 2F, EntityManager).RemoveWhereAttachedEntity(puid => puid == args.User));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Popups;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
@@ -123,7 +124,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
|
||||
UpdateAppearance(uid, null, component);
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("comp-kitchen-spike-kill", ("user", userUid), ("victim", victimUid)), uid,
|
||||
_popupSystem.PopupEntity(Loc.GetString("comp-kitchen-spike-kill", ("user", Identity.Entity(userUid, EntityManager)), ("victim", victimUid)), uid,
|
||||
Filter.Pvs(userUid), PopupType.LargeCaution);
|
||||
|
||||
// THE WHAT?
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Medical.Components;
|
||||
using Content.Server.Disease;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -83,7 +84,7 @@ namespace Content.Server.Medical
|
||||
args.User, Filter.Entities(args.User));
|
||||
return;
|
||||
}
|
||||
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-other", ("target", args.Target), ("disease", args.Component.Disease)),
|
||||
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-other", ("target", Identity.Entity(args.Target.Value, EntityManager)), ("disease", args.Component.Disease)),
|
||||
args.User, Filter.Entities(args.User));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState.Components;
|
||||
@@ -249,8 +250,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
if (forceDrink)
|
||||
{
|
||||
EntityManager.TryGetComponent(user, out MetaDataComponent? meta);
|
||||
var userName = meta?.EntityName ?? string.Empty;
|
||||
var userName = Identity.Name(user, EntityManager);
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("drink-component-force-feed", ("user", userName)),
|
||||
user, Filter.Entities(target));
|
||||
@@ -334,11 +334,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
if (forceDrink)
|
||||
{
|
||||
EntityManager.TryGetComponent(uid, out MetaDataComponent? targetMeta);
|
||||
var targetName = targetMeta?.EntityName ?? string.Empty;
|
||||
|
||||
EntityManager.TryGetComponent(args.User, out MetaDataComponent? userMeta);
|
||||
var userName = userMeta?.EntityName ?? string.Empty;
|
||||
var targetName = Identity.Name(uid, EntityManager);
|
||||
var userName = Identity.Name(args.User, EntityManager);
|
||||
|
||||
_popupSystem.PopupEntity(
|
||||
Loc.GetString("drink-component-force-feed-success", ("user", userName)), uid, Filter.Entities(uid));
|
||||
|
||||
@@ -19,6 +19,7 @@ using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
@@ -114,9 +115,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
if (forceFeed)
|
||||
{
|
||||
EntityManager.TryGetComponent(user, out MetaDataComponent? meta);
|
||||
var userName = meta?.EntityName ?? string.Empty;
|
||||
|
||||
var userName = Identity.Name(user, EntityManager);
|
||||
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
|
||||
user, Filter.Entities(target));
|
||||
|
||||
@@ -180,12 +179,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
if (forceFeed)
|
||||
{
|
||||
EntityManager.TryGetComponent(uid, out MetaDataComponent? targetMeta);
|
||||
var targetName = targetMeta?.EntityName ?? string.Empty;
|
||||
|
||||
EntityManager.TryGetComponent(args.User, out MetaDataComponent? userMeta);
|
||||
var userName = userMeta?.EntityName ?? string.Empty;
|
||||
|
||||
var targetName = Identity.Name(uid, EntityManager);
|
||||
var userName = Identity.Name(args.User, EntityManager);
|
||||
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName)),
|
||||
uid, Filter.Entities(uid));
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Interaction;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Server.GameObjects;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
using static Content.Shared.Paper.SharedPaperComponent;
|
||||
@@ -89,9 +90,9 @@ namespace Content.Server.Paper
|
||||
if (TryComp<StampComponent>(args.Used, out var stampComp) && TryStamp(uid, stampComp.StampedName, stampComp.StampState, paperComp))
|
||||
{
|
||||
// successfully stamped, play popup
|
||||
var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other", ("user", args.User),("target", args.Target),("stamp", args.Used));
|
||||
var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other", ("user", Identity.Entity(args.User, EntityManager)),("target", Identity.Entity(args.Target, EntityManager)),("stamp", args.Used));
|
||||
_popupSystem.PopupEntity(stampPaperOtherMessage, args.User, Filter.Pvs(args.User, entityManager: EntityManager).RemoveWhereAttachedEntity(puid => puid == args.User));
|
||||
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self", ("target", args.Target),("stamp", args.Used));
|
||||
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self", ("target", Identity.Entity(args.Target, EntityManager)),("stamp", args.Used));
|
||||
_popupSystem.PopupEntity(stampPaperSelfMessage, args.User, Filter.Entities(args.User));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Ghost.Components;
|
||||
using Content.Server.Players;
|
||||
using Content.Server.Pointing.Components;
|
||||
using Content.Server.Visible;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
@@ -155,11 +156,11 @@ namespace Content.Server.Pointing.EntitySystems
|
||||
string selfMessage;
|
||||
string viewerMessage;
|
||||
string? viewerPointedAtMessage = null;
|
||||
var playerName = Name(player);
|
||||
var playerName = Identity.Entity(player, EntityManager);
|
||||
|
||||
if (Exists(pointed))
|
||||
{
|
||||
var pointedName = Name(pointed);
|
||||
var pointedName = Identity.Entity(pointed, EntityManager);
|
||||
|
||||
selfMessage = player == pointed
|
||||
? Loc.GetString("pointing-system-point-at-self")
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.CharacterAppearance.Systems;
|
||||
using Content.Server.DetailExaminable;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.IdentityManagement;
|
||||
using Content.Server.PDA;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.Station.Components;
|
||||
@@ -38,6 +39,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly PDASystem _pdaSystem = default!;
|
||||
[Dependency] private readonly AccessSystem _accessSystem = default!;
|
||||
[Dependency] private readonly IdentitySystem _identity = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
@@ -99,6 +101,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
var jobEntity = EntityManager.SpawnEntity(job.JobEntity, coordinates);
|
||||
MakeSentientCommand.MakeSentient(jobEntity, EntityManager);
|
||||
DoJobSpecials(job, jobEntity);
|
||||
_identity.QueueIdentityUpdate(jobEntity);
|
||||
return jobEntity;
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
}
|
||||
|
||||
DoJobSpecials(job, entity);
|
||||
|
||||
_identity.QueueIdentityUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ public sealed class StorageFillVisualizerSystem : EntitySystem
|
||||
if (!Resolve(uid, ref storage, ref appearance, ref component, false))
|
||||
return;
|
||||
|
||||
if (component.MaxFillLevels < 1)
|
||||
return;
|
||||
|
||||
var level = ContentHelpers.RoundToEqualLevels(storage.StorageUsed, storage.StorageCapacityMax, component.MaxFillLevels);
|
||||
appearance.SetData(StorageFillVisuals.FillLevel, level);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Inventory;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Inventory.Events;
|
||||
@@ -306,7 +307,7 @@ namespace Content.Server.Strip
|
||||
{
|
||||
if (userHands.ActiveHandEntity != null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", user), ("item", userHands.ActiveHandEntity)), component.Owner,
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", Identity.Entity(user, EntityManager)), ("item", userHands.ActiveHandEntity)), component.Owner,
|
||||
Filter.Entities(component.Owner), PopupType.Large);
|
||||
}
|
||||
}
|
||||
@@ -369,7 +370,7 @@ namespace Content.Server.Strip
|
||||
{
|
||||
if (handSlot.HeldEntity != null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", user), ("item", handSlot.HeldEntity)), component.Owner,
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", Identity.Entity(user, EntityManager)), ("item", handSlot.HeldEntity)), component.Owner,
|
||||
Filter.Entities(component.Owner), PopupType.Large);
|
||||
}
|
||||
}
|
||||
@@ -437,7 +438,7 @@ namespace Content.Server.Strip
|
||||
else
|
||||
{
|
||||
if (_inventorySystem.TryGetSlotEntity(component.Owner, slot, out var slotItem))
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", user), ("item", slotItem)), component.Owner,
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", slotItem)), component.Owner,
|
||||
Filter.Entities(component.Owner), PopupType.Large);
|
||||
}
|
||||
}
|
||||
@@ -501,7 +502,7 @@ namespace Content.Server.Strip
|
||||
{
|
||||
if (handSlot.HeldEntity != null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", user), ("item", handSlot.HeldEntity)), component.Owner, Filter.Entities(component.Owner));
|
||||
_popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", handSlot.HeldEntity)), component.Owner, Filter.Entities(component.Owner));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.CombatMode;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Stunnable;
|
||||
@@ -38,9 +39,11 @@ namespace Content.Server.Stunnable
|
||||
var knock = EntityManager.GetComponent<KnockedDownComponent>(uid);
|
||||
SoundSystem.Play(knock.StunAttemptSound.GetSound(), Filter.Pvs(source), source, AudioHelpers.WithVariation(0.025f));
|
||||
|
||||
var targetEnt = Identity.Entity(target, EntityManager);
|
||||
var sourceEnt = Identity.Entity(source, EntityManager);
|
||||
// TODO: Use PopupSystem
|
||||
source.PopupMessageOtherClients(Loc.GetString("stunned-component-disarm-success-others", ("source", Name(source)), ("target", Name(target))));
|
||||
source.PopupMessageCursor(Loc.GetString("stunned-component-disarm-success", ("target", Name(target))));
|
||||
source.PopupMessageOtherClients(Loc.GetString("stunned-component-disarm-success-others", ("source", sourceEnt), ("target", targetEnt)));
|
||||
source.PopupMessageCursor(Loc.GetString("stunned-component-disarm-success", ("target", targetEnt)));
|
||||
|
||||
_adminLogger.Add(LogType.DisarmedKnockdown, LogImpact.Medium, $"{ToPrettyString(args.Source):user} knocked down {ToPrettyString(args.Target):target}");
|
||||
|
||||
|
||||
@@ -73,4 +73,5 @@ public enum LogType
|
||||
// haha so funny
|
||||
Emag = 69,
|
||||
Gib = 70,
|
||||
Identity = 71
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Access.Components
|
||||
{
|
||||
// TODO BUI NETWORKING if ever clients can open their own BUI's (id card console, pda), then this data should be
|
||||
// networked.
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(SharedIdCardSystem), typeof(SharedPDASystem), typeof(SharedAgentIdCardSystem))]
|
||||
public sealed class IdCardComponent : Component
|
||||
{
|
||||
@@ -20,4 +20,17 @@ namespace Content.Shared.Access.Components
|
||||
[DataField("jobTitle")]
|
||||
public string? JobTitle;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class IdCardComponentState : ComponentState
|
||||
{
|
||||
public string? FullName;
|
||||
public string? JobTitle;
|
||||
|
||||
public IdCardComponentState(string? fullName, string? jobTitle)
|
||||
{
|
||||
FullName = fullName;
|
||||
JobTitle = jobTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,80 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Access.Systems;
|
||||
|
||||
public abstract class SharedIdCardSystem : EntitySystem
|
||||
{
|
||||
// this class just exists to make friends. Will you be its friend?
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<IdCardComponent, ComponentGetState>(OnComponentGetState);
|
||||
SubscribeLocalEvent<IdCardComponent, ComponentHandleState>(OnComponentHandleState);
|
||||
}
|
||||
|
||||
private void OnComponentGetState(EntityUid uid, IdCardComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new IdCardComponentState(component.FullName, component.JobTitle);
|
||||
}
|
||||
|
||||
private void OnComponentHandleState(EntityUid uid, IdCardComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is IdCardComponentState state)
|
||||
{
|
||||
component.FullName = state.FullName;
|
||||
component.JobTitle = state.JobTitle;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to find an ID card on an entity. This will look in the entity itself, in the entity's hands, and
|
||||
/// in the entity's inventory.
|
||||
/// </summary>
|
||||
public bool TryFindIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
// check held item?
|
||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||
TryGetIdCard(heldItem, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check entity itself
|
||||
if (TryGetIdCard(uid, out idCard))
|
||||
return true;
|
||||
|
||||
// check inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to get an id card component from an entity, either by getting it directly from the entity, or by
|
||||
/// getting the contained id from a <see cref="PDAComponent"/>.
|
||||
/// </summary>
|
||||
public bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out idCard))
|
||||
return true;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, out PDAComponent? pda) && pda.ContainedID != null)
|
||||
{
|
||||
idCard = pda.ContainedID;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared.Administration
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public record PlayerInfo(string Username, string CharacterName, string StartingJob, bool Antag, EntityUid EntityUid, NetUserId SessionId, bool Connected);
|
||||
public record PlayerInfo(string Username, string CharacterName, string IdentityName, string StartingJob, bool Antag, EntityUid EntityUid, NetUserId SessionId, bool Connected);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Shared.Actions.ActionTypes;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Toggleable;
|
||||
@@ -105,8 +106,9 @@ public sealed class BlockingSystem : EntitySystem
|
||||
|
||||
var shieldName = Name(item);
|
||||
|
||||
var blockerName = Identity.Entity(user, EntityManager);
|
||||
var msgUser = Loc.GetString("action-popup-blocking-user", ("shield", shieldName));
|
||||
var msgOther = Loc.GetString("action-popup-blocking-other", ("blockerName", Name(user)), ("shield", shieldName));
|
||||
var msgOther = Loc.GetString("action-popup-blocking-other", ("blockerName", blockerName), ("shield", shieldName));
|
||||
|
||||
if (component.BlockingToggleAction != null)
|
||||
{
|
||||
@@ -154,8 +156,9 @@ public sealed class BlockingSystem : EntitySystem
|
||||
|
||||
var shieldName = Name(item);
|
||||
|
||||
var blockerName = Identity.Entity(user, EntityManager);
|
||||
var msgUser = Loc.GetString("action-popup-blocking-disabling-user", ("shield", shieldName));
|
||||
var msgOther = Loc.GetString("action-popup-blocking-disabling-other", ("blockerName", Name(user)), ("shield", shieldName));
|
||||
var msgOther = Loc.GetString("action-popup-blocking-disabling-other", ("blockerName", blockerName), ("shield", shieldName));
|
||||
|
||||
//If the component blocking toggle isn't null, grab the users SharedBlockingUserComponent and PhysicsComponent
|
||||
//then toggle the action to false, unanchor the user, remove the hard fixture
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.CharacterAppearance.Systems;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Species;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -23,6 +24,9 @@ namespace Content.Shared.CharacterAppearance.Components
|
||||
[ViewVariables]
|
||||
public string Species { get; set; } = SpeciesManager.DefaultSpecies;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int Age { get; set; } = HumanoidCharacterProfile.MinimumAge;
|
||||
|
||||
[DataField("categoriesHair")]
|
||||
[ViewVariables]
|
||||
public SpriteAccessoryCategories CategoriesHair { get; set; } = SpriteAccessoryCategories.HumanHair;
|
||||
@@ -55,16 +59,19 @@ namespace Content.Shared.CharacterAppearance.Components
|
||||
public Sex Sex { get; }
|
||||
public Gender Gender { get; }
|
||||
public string Species { get; }
|
||||
public int Age { get; }
|
||||
|
||||
public HumanoidAppearanceComponentState(HumanoidCharacterAppearance appearance,
|
||||
Sex sex,
|
||||
Gender gender,
|
||||
string species)
|
||||
string species,
|
||||
int age)
|
||||
{
|
||||
Appearance = appearance;
|
||||
Sex = sex;
|
||||
Gender = gender;
|
||||
Species = species;
|
||||
Age = age;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
public void UpdateFromProfile(EntityUid uid, ICharacterProfile profile, HumanoidAppearanceComponent? appearance=null)
|
||||
{
|
||||
var humanoid = (HumanoidCharacterProfile) profile;
|
||||
UpdateAppearance(uid, humanoid.Appearance, humanoid.Sex, humanoid.Gender, humanoid.Species, appearance);
|
||||
UpdateAppearance(uid, humanoid.Appearance, humanoid.Sex, humanoid.Gender, humanoid.Species, humanoid.Age, appearance);
|
||||
}
|
||||
|
||||
// The magic mirror otherwise wouldn't work. (it directly modifies the component server-side)
|
||||
@@ -29,7 +29,7 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
component.Dirty();
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, HumanoidCharacterAppearance appearance, Sex sex, Gender gender, string species, HumanoidAppearanceComponent? component = null)
|
||||
private void UpdateAppearance(EntityUid uid, HumanoidCharacterAppearance appearance, Sex sex, Gender gender, string species, int age, HumanoidAppearanceComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component)) return;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
component.Sex = sex;
|
||||
component.Gender = gender;
|
||||
component.Species = species;
|
||||
component.Age = age;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, out GrammarComponent? g))
|
||||
g.Gender = gender;
|
||||
@@ -59,7 +60,7 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
|
||||
private void OnAppearanceGetState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new HumanoidAppearanceComponentState(component.Appearance, component.Sex, component.Gender, component.Species);
|
||||
args.State = new HumanoidAppearanceComponentState(component.Appearance, component.Sex, component.Gender, component.Species, component.Age);
|
||||
}
|
||||
|
||||
private void OnAppearanceHandleState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentHandleState args)
|
||||
@@ -67,7 +68,7 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
if (args.Current is not HumanoidAppearanceComponentState state)
|
||||
return;
|
||||
|
||||
UpdateAppearance(uid, state.Appearance, state.Sex, state.Gender, state.Species);
|
||||
UpdateAppearance(uid, state.Appearance, state.Sex, state.Gender, state.Species, state.Age);
|
||||
}
|
||||
|
||||
// Scaffolding until Body is moved to ECS.
|
||||
@@ -106,7 +107,6 @@ namespace Content.Shared.CharacterAppearance.Systems
|
||||
Uid = uid;
|
||||
Args = args;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Map;
|
||||
@@ -166,7 +167,7 @@ public abstract partial class SharedHandsSystem : EntitySystem
|
||||
if (HasComp<HandVirtualItemComponent>(inhand))
|
||||
continue;
|
||||
|
||||
args.PushText(Loc.GetString("comp-hands-examine", ("user", handsComp.Owner), ("item", inhand)));
|
||||
args.PushText(Loc.GetString("comp-hands-examine", ("user", Identity.Entity(handsComp.Owner, EntityManager)), ("item", inhand)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.IdentityManagement.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class IdentityBlockerComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity and relayed to inventory to determine if its identity should be knowable.
|
||||
/// </summary>
|
||||
public sealed class SeeIdentityAttemptEvent : CancellableEntityEventArgs, IInventoryRelayEvent
|
||||
{
|
||||
// i.e. masks or helmets.
|
||||
public SlotFlags TargetSlots => SlotFlags.MASK | SlotFlags.HEAD;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Content.Shared.IdentityManagement.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the identity entity (whose name is the users 'identity', etc)
|
||||
/// for a given entity, and marks that it can have an identity at all.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a <see cref="ContainerSlot"/> and not just a datum entity because we do sort of care that it gets deleted and sent with the user.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class IdentityComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public ContainerSlot IdentityEntitySlot = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A data structure representing the 'identity' of an entity as presented to
|
||||
/// other players.
|
||||
/// </summary>
|
||||
public sealed class IdentityRepresentation
|
||||
{
|
||||
public string TrueName;
|
||||
public int TrueAge;
|
||||
public Gender TrueGender;
|
||||
|
||||
public string? PresumedName;
|
||||
public string? PresumedJob;
|
||||
|
||||
public IdentityRepresentation(string trueName, int trueAge, Gender trueGender, string? presumedName=null, string? presumedJob=null)
|
||||
{
|
||||
TrueName = trueName;
|
||||
TrueAge = trueAge;
|
||||
TrueGender = trueGender;
|
||||
|
||||
PresumedJob = presumedJob;
|
||||
PresumedName = presumedName;
|
||||
}
|
||||
|
||||
public string ToStringKnown(bool trueName)
|
||||
{
|
||||
return trueName
|
||||
? TrueName
|
||||
: PresumedName ?? ToStringUnknown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representing their identity where it is 'unknown' by a viewer.
|
||||
/// Used for cases where the viewer is not necessarily able to accurately assess
|
||||
/// the identity of the person being viewed.
|
||||
/// </summary>
|
||||
public string ToStringUnknown()
|
||||
{
|
||||
var ageString = TrueAge switch
|
||||
{
|
||||
<= 30 => Loc.GetString("identity-age-young"),
|
||||
> 30 and <= 60 => Loc.GetString("identity-age-middle-aged"),
|
||||
> 60 => Loc.GetString("identity-age-old")
|
||||
};
|
||||
|
||||
var genderString = TrueGender switch
|
||||
{
|
||||
Gender.Female => Loc.GetString("identity-gender-feminine"),
|
||||
Gender.Male => Loc.GetString("identity-gender-masculine"),
|
||||
Gender.Epicene or Gender.Neuter or _ => Loc.GetString("identity-gender-person")
|
||||
};
|
||||
|
||||
// i.e. 'young assistant man' or 'old cargo technician person' or 'middle-aged captain'
|
||||
return PresumedJob is null
|
||||
? $"{ageString} {genderString}"
|
||||
: $"{ageString} {PresumedJob} {genderString}";
|
||||
}
|
||||
}
|
||||
60
Content.Shared/IdentityManagement/Identity.cs
Normal file
60
Content.Shared/IdentityManagement/Identity.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.IdentityManagement.Components;
|
||||
|
||||
namespace Content.Shared.IdentityManagement;
|
||||
|
||||
/// <summary>
|
||||
/// Static content API for getting the identity entities/names for a given entity.
|
||||
/// This should almost always be used in favor of metadata name, if the entity in question is a human player that
|
||||
/// can have identity.
|
||||
/// </summary>
|
||||
public static class Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the name that should be used for this entity for identity purposes.
|
||||
/// </summary>
|
||||
public static string Name(EntityUid uid, IEntityManager ent, EntityUid? viewer=null)
|
||||
{
|
||||
var uidName = ent.GetComponent<MetaDataComponent>(uid).EntityName;
|
||||
|
||||
if (!ent.TryGetComponent<IdentityComponent>(uid, out var identity))
|
||||
return uidName;
|
||||
|
||||
var ident = identity.IdentityEntitySlot.ContainedEntity;
|
||||
if (ident is null)
|
||||
return uidName;
|
||||
|
||||
var identName = ent.GetComponent<MetaDataComponent>(ident.Value).EntityName;
|
||||
if (viewer == null || !CanSeeThroughIdentity(uid, viewer.Value, ent))
|
||||
{
|
||||
return identName;
|
||||
}
|
||||
if (uidName == identName)
|
||||
{
|
||||
return uidName;
|
||||
}
|
||||
|
||||
return uidName + $" ({identName})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the entity that should be used for identity purposes, for example to pass into localization.
|
||||
/// This is an extension method because of its simplicity, and if it was any harder to call it might not
|
||||
/// be used enough for loc.
|
||||
/// </summary>
|
||||
public static EntityUid Entity(EntityUid uid, IEntityManager ent)
|
||||
{
|
||||
if (!ent.TryGetComponent<IdentityComponent>(uid, out var identity))
|
||||
return uid;
|
||||
|
||||
return identity.IdentityEntitySlot.ContainedEntity ?? uid;
|
||||
}
|
||||
|
||||
public static bool CanSeeThroughIdentity(EntityUid uid, EntityUid viewer, IEntityManager ent)
|
||||
{
|
||||
// Would check for uid == viewer here but I think it's better for you to see yourself
|
||||
// how everyone else will see you, otherwise people will probably get confused and think they aren't disguised
|
||||
return ent.HasComponent<SharedGhostComponent>(viewer);
|
||||
}
|
||||
|
||||
}
|
||||
28
Content.Shared/IdentityManagement/SharedIdentitySystem.cs
Normal file
28
Content.Shared/IdentityManagement/SharedIdentitySystem.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.IdentityManagement.Components;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Shared.IdentityManagement;
|
||||
|
||||
public abstract class SharedIdentitySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
private static string SlotName = "identity";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<IdentityComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<IdentityBlockerComponent, SeeIdentityAttemptEvent>(OnSeeIdentity);
|
||||
}
|
||||
|
||||
private void OnSeeIdentity(EntityUid uid, IdentityBlockerComponent component, SeeIdentityAttemptEvent args)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
protected virtual void OnComponentInit(EntityUid uid, IdentityComponent component, ComponentInit args)
|
||||
{
|
||||
component.IdentityEntitySlot = _container.EnsureContainer<ContainerSlot>(uid, SlotName);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Electrocution;
|
||||
using Content.Shared.Explosion;
|
||||
using Content.Shared.IdentityManagement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Slippery;
|
||||
using Content.Shared.Strip.Components;
|
||||
@@ -17,6 +18,7 @@ public partial class InventorySystem
|
||||
SubscribeLocalEvent<InventoryComponent, RefreshMovementSpeedModifiersEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, BeforeStripEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, SeeIdentityAttemptEvent>(RelayInventoryEvent);
|
||||
}
|
||||
|
||||
protected void RelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, T args) where T : EntityEventArgs, IInventoryRelayEvent
|
||||
|
||||
@@ -4,7 +4,7 @@ action-description-blocking = Raise or lower your shield.
|
||||
action-popup-blocking-user = You raise your {$shield}!
|
||||
action-popup-blocking-disabling-user = You lower your {$shield}!
|
||||
|
||||
action-popup-blocking-other = {$blockerName} raises their {$shield}!
|
||||
action-popup-blocking-disabling-other = {$blockerName} lowers their {$shield}!
|
||||
action-popup-blocking-other = {CAPITALIZE(THE($blockerName))} raises {POSS-ADJ($blockerName)} {$shield}!
|
||||
action-popup-blocking-disabling-other = {CAPITALIZE(THE($blockerName))} lowers {POSS-ADJ($blockerName)} {$shield}!
|
||||
|
||||
action-popup-blocking-user-cant-block = The gravity here prevents you from blocking.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
disarm-action-free-hand = You need to use a free hand to disarm!
|
||||
|
||||
disarm-action-popup-message-other-clients = {$performerName} fails to disarm {$targetName}!
|
||||
disarm-action-popup-message-cursor = You fail to disarm {$targetName}!
|
||||
disarm-action-popup-message-other-clients = {CAPITALIZE(THE($performerName))} fails to disarm {THE($targetName)}!
|
||||
disarm-action-popup-message-cursor = You fail to disarm {THE($targetName)}!
|
||||
|
||||
action-name-disarm = [color=red]Disarm[/color]
|
||||
action-description-disarm = Attempt to [color=red]disarm[/color] someone.
|
||||
|
||||
@@ -21,4 +21,4 @@ injector-component-target-is-empty-message = {$target} is empty!
|
||||
## mob-inject doafter messages
|
||||
|
||||
injector-component-injecting-user = You start inserting the needle.
|
||||
injector-component-injecting-target = {$user} is trying to stick a needle into you!
|
||||
injector-component-injecting-target = {CAPITALIZE(THE($user))} is trying to stick a needle into you!
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
pointing-system-try-point-cannot-reach = You can't reach there!
|
||||
pointing-system-point-at-self = You point at yourself.
|
||||
pointing-system-point-at-other = You point at {$other}.
|
||||
pointing-system-point-at-self-others = {$otherName} points at {$other}.
|
||||
pointing-system-point-at-other-others = {$otherName} points at {$other}.
|
||||
pointing-system-point-at-other = You point at {THE($other)}.
|
||||
pointing-system-point-at-self-others = {CAPITALIZE(THE($otherName))} points at {THE($other)}.
|
||||
pointing-system-point-at-other-others = {CAPITALIZE(THE($otherName))} points at {THE($other)}.
|
||||
pointing-system-point-at-you-other = {$otherName} points at you.
|
||||
pointing-system-point-at-tile = You point at the {$tileName}.
|
||||
pointing-system-other-point-at-tile = {$otherName} points at the {$tileName}.
|
||||
pointing-system-other-point-at-tile = {CAPITALIZE(THE($otherName))} points at the {$tileName}.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
hands-component-disarm-success-others-message = {$disarmer} disarms {$disarmed}!
|
||||
hands-component-disarm-success-message = You disarm {$disarmed}!
|
||||
hands-component-shove-success-others-message = {$shover} shoves {$shoved}!
|
||||
hands-component-shove-success-message = You shove {$shoved}!
|
||||
hands-component-disarm-success-others-message = {CAPITALIZE(THE($disarmer))} disarms {THE($disarmed)}!
|
||||
hands-component-disarm-success-message = You disarm {THE($disarmed)}!
|
||||
hands-component-shove-success-others-message = {CAPITALIZE(THE($shover))} shoves {THE($shoved)}!
|
||||
hands-component-shove-success-message = You shove {THE($shoved)}!
|
||||
|
||||
9
Resources/Locale/en-US/identity/identity-system.ftl
Normal file
9
Resources/Locale/en-US/identity/identity-system.ftl
Normal file
@@ -0,0 +1,9 @@
|
||||
identity-unknown-name = ???
|
||||
|
||||
identity-age-young = young
|
||||
identity-age-middle-aged = middle-aged
|
||||
identity-age-old = old
|
||||
|
||||
identity-gender-feminine = woman
|
||||
identity-gender-masculine = man
|
||||
identity-gender-person = person
|
||||
@@ -1,2 +1,2 @@
|
||||
stunnable-component-disarm-success-others = {$source} pushes {$target}!
|
||||
stunnable-component-disarm-success = You push {$target}!
|
||||
stunnable-component-disarm-success-others = {CAPITALIZE(THE($source))} pushes {THE($target)}!
|
||||
stunnable-component-disarm-success = You push {THE($target)}!
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
stunned-component-disarm-success = You push {$target} down!
|
||||
stunned-component-disarm-success-others = {$source} pushes {$target} down!
|
||||
stunned-component-disarm-success = You push {THE($target)} down!
|
||||
stunned-component-disarm-success-others = {CAPITALIZE(THE($source))} pushes {THE($target)} down!
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
- HidesHair
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
@@ -76,6 +77,7 @@
|
||||
- HidesHair
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
Blunt: 0.5
|
||||
Slash: 0.8
|
||||
Piercing: 0.8
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadEVAHelmetBase
|
||||
@@ -143,6 +144,7 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- HidesHair
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadEVAHelmetBase
|
||||
@@ -167,6 +169,7 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/Head/Helmets/templar.rsi
|
||||
- type: IngestionBlocker
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadBase
|
||||
@@ -190,6 +193,7 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/Head/Helmets/wizardhelm.rsi
|
||||
- type: IngestionBlocker
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadHardsuitWithLightBase
|
||||
@@ -221,7 +225,7 @@
|
||||
- type: PressureProtection
|
||||
highPressureMultiplier: 0.65
|
||||
lowPressureMultiplier: 1000
|
||||
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadHardsuitWithLightBase
|
||||
@@ -250,6 +254,7 @@
|
||||
- type: PressureProtection
|
||||
highPressureMultiplier: 0.45
|
||||
lowPressureMultiplier: 1000
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadBase
|
||||
@@ -268,6 +273,7 @@
|
||||
Slash: 0.5
|
||||
Piercing: 0.5
|
||||
Heat: 0.9
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadEVAHelmetBase
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
components:
|
||||
- type: IngestionBlocker
|
||||
- type: FlashImmunity
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: WeldingMaskBase
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
- type: IngestionBlocker
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: IdentityBlocker
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskPullableBase
|
||||
parent: ClothingMaskGas
|
||||
id: ClothingMaskGasSecurity
|
||||
name: security gas mask
|
||||
description: A standard issue Security gas mask.
|
||||
@@ -23,13 +24,9 @@
|
||||
sprite: Clothing/Mask/gassecurity.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Mask/gassecurity.rsi
|
||||
- type: BreathMask
|
||||
- type: IngestionBlocker
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskPullableBase
|
||||
parent: ClothingMaskGas
|
||||
id: ClothingMaskGasSyndicate
|
||||
name: syndicate gas mask
|
||||
description: A close-fitting tactical mask that can be connected to an air supply.
|
||||
@@ -38,14 +35,10 @@
|
||||
sprite: Clothing/Mask/gassyndicate.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Mask/gassyndicate.rsi
|
||||
- type: BreathMask
|
||||
- type: IngestionBlocker
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: FlashImmunity
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskPullableBase
|
||||
parent: ClothingMaskGas
|
||||
id: ClothingMaskGasAtmos
|
||||
name: atmospheric gas mask
|
||||
description: Improved gas mask utilized by atmospheric technicians. It's flameproof!
|
||||
@@ -54,10 +47,6 @@
|
||||
sprite: Clothing/Mask/gasatmos.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Mask/gasatmos.rsi
|
||||
- type: BreathMask
|
||||
- type: IngestionBlocker
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: Armor
|
||||
modifiers:
|
||||
coefficients:
|
||||
@@ -94,7 +83,7 @@
|
||||
protection: 0.05
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskPullableBase
|
||||
parent: ClothingMaskGas
|
||||
id: ClothingMaskGasExplorer
|
||||
name: explorer gas mask
|
||||
description: A military-grade gas mask that can be connected to an air supply.
|
||||
@@ -103,10 +92,6 @@
|
||||
sprite: Clothing/Mask/gasexplorer.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Mask/gasexplorer.rsi
|
||||
- type: BreathMask
|
||||
- type: IngestionBlocker
|
||||
- type: DiseaseProtection
|
||||
protection: 0.05
|
||||
- type: Armor
|
||||
modifiers:
|
||||
coefficients:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
- !type:WashCreamPieReaction
|
||||
- type: Flashable
|
||||
- type: Polymorphable
|
||||
- type: Identity
|
||||
- type: Hands
|
||||
- type: MovementSpeedModifier
|
||||
- type: MovedByPressure
|
||||
|
||||
Reference in New Issue
Block a user