From 1eead99543d8142c9eec8bd1b6a32c157b355aa9 Mon Sep 17 00:00:00 2001 From: Red <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:34:10 +0300 Subject: [PATCH] You are surrounded by unknown suspicious individuals, my lord. (#1710) * base identity hide * ui * Better UI * store data in Mind * disable arrivals an leave announcement * tips updated * Enhance identity recognition and examination feedback Added logic to display remembered character names during examination and improved the process for remembering character names on map initialization. Also updated localization files to include new examination feedback strings. Minor refactoring and bug fixes in identity recognition systems. * Update CP14SharedIdentityRecognitionSystem.cs * fix --- .../Systems/Chat/ChatUIController.cs | 16 ++ .../CP14ClientIdentityRecognitionSystem.cs | 54 +++++++ ...14IdentityRecognitionBoundUserInterface.cs | 97 +++++++++++++ .../CP14RememberNameWindow.xaml | 8 + .../CP14RememberNameWindow.xaml.cs | 61 ++++++++ .../GameTicking/GameTicker.Spawning.cs | 4 +- .../IdentityManagement/IdentitySystem.cs | 10 ++ .../CP14IdentityRecognitionSystem.cs | 7 + .../_CP14/RoundLeave/CP14RoundLeaveSystem.cs | 21 ++- .../CP14RememberedNamesComponent.cs | 15 ++ .../CP14SharedIdentityRecognitionSystem.cs | 137 ++++++++++++++++++ .../CP14UnknownIdentityComponent.cs | 13 ++ .../_CP14/identity/identity_recognition.ftl | 5 + Resources/Locale/en-US/_CP14/tips/tip.ftl | 16 +- .../_CP14/identity/identity_recognition.ftl | 5 + Resources/Locale/ru-RU/_CP14/tips/tip.ftl | 16 +- .../Entities/Clothing/Masks/vampire_mask.yml | 10 +- .../_CP14/Entities/Mobs/Species/base.yml | 3 + .../Recipes/Workbench/Vampire/devourers.yml | 3 - .../Workbench/Vampire/night_children.yml | 3 - .../Recipes/Workbench/Vampire/unnameable.yml | 3 - Resources/Prototypes/_CP14/secret_weights.yml | 6 +- 22 files changed, 462 insertions(+), 51 deletions(-) create mode 100644 Content.Client/_CP14/IdentityRecognition/CP14ClientIdentityRecognitionSystem.cs create mode 100644 Content.Client/_CP14/IdentityRecognition/CP14IdentityRecognitionBoundUserInterface.cs create mode 100644 Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml create mode 100644 Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml.cs create mode 100644 Content.Server/_CP14/IdentityRecognition/CP14IdentityRecognitionSystem.cs create mode 100644 Content.Shared/_CP14/IdentityRecognition/CP14RememberedNamesComponent.cs create mode 100644 Content.Shared/_CP14/IdentityRecognition/CP14SharedIdentityRecognitionSystem.cs create mode 100644 Content.Shared/_CP14/IdentityRecognition/CP14UnknownIdentityComponent.cs create mode 100644 Resources/Locale/en-US/_CP14/identity/identity_recognition.ftl create mode 100644 Resources/Locale/ru-RU/_CP14/identity/identity_recognition.ftl diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index e324429859..d0a358155e 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -1,6 +1,7 @@ using System.Globalization; using System.Linq; using System.Numerics; +using Content.Client._CP14.IdentityRecognition; using Content.Client.Administration.Managers; using Content.Client.Chat; using Content.Client.Chat.Managers; @@ -820,6 +821,21 @@ public sealed partial class ChatUIController : UIController public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true) { + //CP14 transform message on clientside + if (_player.LocalEntity is not null && msg.SenderEntity.IsValid()) + { + var ev = new CP14ClientTransformNameEvent(msg.SenderEntity); + _ent.EventBus.RaiseLocalEvent(_player.LocalEntity.Value, ev); + + if (ev.Handled) + { + var oldName = SharedChatSystem.GetStringInsideTag(msg, "Name"); + var newName = ev.Name; + msg.WrappedMessage = msg.WrappedMessage.Replace($"[Name]{oldName}[/Name]", $"[Name]{newName}[/Name]"); + } + } + //CP14 end + // color the name unless it's something like "the old man" if ((msg.Channel == ChatChannel.Local || msg.Channel == ChatChannel.Whisper) && _chatNameColorsEnabled) { diff --git a/Content.Client/_CP14/IdentityRecognition/CP14ClientIdentityRecognitionSystem.cs b/Content.Client/_CP14/IdentityRecognition/CP14ClientIdentityRecognitionSystem.cs new file mode 100644 index 0000000000..05bc2c5676 --- /dev/null +++ b/Content.Client/_CP14/IdentityRecognition/CP14ClientIdentityRecognitionSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared._CP14.IdentityRecognition; +using Content.Shared.IdentityManagement; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; + +namespace Content.Client._CP14.IdentityRecognition; + +public sealed partial class CP14ClientIdentityRecognitionSystem : CP14SharedIdentityRecognitionSystem +{ + [Dependency] private readonly SharedMindSystem _mind = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTransformSpeakerName); + } + + private void OnTransformSpeakerName(Entity ent, ref CP14ClientTransformNameEvent args) + { + if (args.Handled) + return; + + var mindEntity = ent.Comp.Mind; + if (mindEntity is null) + return; + + TryComp(mindEntity.Value, out var knownNames); + + var speaker = GetEntity(args.Speaker); + + if (speaker == ent.Owner) + return; + + if (knownNames is not null && knownNames.Names.TryGetValue(args.Speaker.Id, out var name)) + { + args.Name = name; + } + else + { + args.Name = Identity.Name(speaker, EntityManager, ent); + } + args.Handled = true; + } +} + +public sealed class CP14ClientTransformNameEvent(NetEntity speaker) : EntityEventArgs +{ + public NetEntity Speaker = speaker; + + public string Name = string.Empty; + + public bool Handled { get; set; } +} diff --git a/Content.Client/_CP14/IdentityRecognition/CP14IdentityRecognitionBoundUserInterface.cs b/Content.Client/_CP14/IdentityRecognition/CP14IdentityRecognitionBoundUserInterface.cs new file mode 100644 index 0000000000..d934880f13 --- /dev/null +++ b/Content.Client/_CP14/IdentityRecognition/CP14IdentityRecognitionBoundUserInterface.cs @@ -0,0 +1,97 @@ +using Content.Shared._CP14.IdentityRecognition; +using Content.Shared.Labels.Components; +using Content.Shared.Mind.Components; +using Robust.Client.Player; +using Robust.Client.UserInterface; + +namespace Content.Client._CP14.IdentityRecognition; + +public sealed class CP14IdentityRecognitionBoundUserInterface : BoundUserInterface +{ + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + [ViewVariables] + private CP14RememberNameWindow? _window; + + private NetEntity? _rememberedTarget; + + public CP14IdentityRecognitionBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + IoCManager.InjectDependencies(this); + } + + protected override void Open() + { + base.Open(); + + _window = this.CreateWindow(); + + if (_entManager.TryGetComponent(Owner, out HandLabelerComponent? labeler)) + { + _window.SetMaxLabelLength(labeler!.MaxLabelChars); + } + + _window.OnRememberedNameChanged += OnLabelChanged; + Reload(); + } + + private void OnLabelChanged(string newLabel) + { + if (_rememberedTarget is null) + return; + + // Focus moment + var currentName = CurrentName(); + + if (currentName is not null && currentName.Equals(newLabel)) + return; + + SendPredictedMessage(new CP14RememberedNameChangedMessage(newLabel, _rememberedTarget.Value)); + } + + public void Reload() + { + if (_window is null) + return; + + var currentName = CurrentName(); + + if (currentName is null) + return; + + _window.SetCurrentLabel(currentName); + } + + private string? CurrentName() + { + if (_rememberedTarget is null) + return null; + if (!_entManager.TryGetComponent(_player.LocalEntity, out var mindContainer)) + return null; + if (!_entManager.TryGetComponent(mindContainer.Mind, out var knownNames)) + return null; + + var netId = _rememberedTarget.Value.Id; + return knownNames.Names.GetValueOrDefault(netId); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (_window is null) + return; + + switch (state) + { + case CP14RememberNameUiState rememberNameUiState: + _rememberedTarget = rememberNameUiState.Target; + + var currentName = CurrentName(); + if (currentName is not null) + _window.SetCurrentLabel(currentName); + break; + } + } +} diff --git a/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml b/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml new file mode 100644 index 0000000000..e69281ef20 --- /dev/null +++ b/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml @@ -0,0 +1,8 @@ + + + + diff --git a/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml.cs b/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml.cs new file mode 100644 index 0000000000..bd693420ec --- /dev/null +++ b/Content.Client/_CP14/IdentityRecognition/CP14RememberNameWindow.xaml.cs @@ -0,0 +1,61 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._CP14.IdentityRecognition; + +[GenerateTypedNameReferences] +public sealed partial class CP14RememberNameWindow : DefaultWindow +{ + public event Action? OnRememberedNameChanged; + + /// + /// Is the user currently entering text into the control? + /// + private bool _focused; + // TODO LineEdit Make this a bool on the LineEdit control + + private string _label = string.Empty; + + public CP14RememberNameWindow() + { + RobustXamlLoader.Load(this); + + LabelLineEdit.OnTextChanged += e => + { + _label = e.Text; + OnRememberedNameChanged?.Invoke(_label); + }; + + LabelLineEdit.OnFocusEnter += _ => _focused = true; + LabelLineEdit.OnFocusExit += _ => + { + _focused = false; + LabelLineEdit.Text = _label; + }; + } + + protected override void Opened() + { + base.Opened(); + + // Give the editor keyboard focus, since that's the only + // thing the user will want to be doing with this UI + LabelLineEdit.GrabKeyboardFocus(); + } + + public void SetCurrentLabel(string label) + { + if (label == _label) + return; + + _label = label; + if (!_focused) + LabelLineEdit.Text = label; + } + + public void SetMaxLabelLength(int maxLength) + { + LabelLineEdit.IsValid = s => s.Length <= maxLength; + } +} diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index b05572849e..ecdcc50610 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -284,7 +284,7 @@ namespace Content.Server.GameTicking var jobName = _jobs.MindTryGetJobName(newMind); _admin.UpdatePlayerList(player); - if (lateJoin && !silent) + if (lateJoin && !silent && false) //CP14 disable arrival snnouncement { if (jobPrototype.JoinNotifyCrew) { @@ -301,7 +301,7 @@ namespace Content.Server.GameTicking else { _chatSystem.DispatchStationAnnouncement(station, - Loc.GetString("cp14-latejoin-arrival-announcement",//CrystallEdge + Loc.GetString("latejoin-arrival-announcement", ("character", MetaData(mob).EntityName), ("gender", character.Gender), // CrystallEdge-LastnameGender ("entity", mob), diff --git a/Content.Server/IdentityManagement/IdentitySystem.cs b/Content.Server/IdentityManagement/IdentitySystem.cs index 131544e569..3173018712 100644 --- a/Content.Server/IdentityManagement/IdentitySystem.cs +++ b/Content.Server/IdentityManagement/IdentitySystem.cs @@ -90,6 +90,16 @@ public sealed class IdentitySystem : SharedIdentitySystem var representation = GetIdentityRepresentation(uid); var name = GetIdentityName(uid, representation); + //CP14 override character name + if (TryComp(uid, out var humanoid)) + { + var species = _humanoid.GetSpeciesRepresentation(humanoid.Species).ToLower(); + var age = _humanoid.GetAgeRepresentation(humanoid.Species, humanoid.Age); + + name = age + " " + species; + } + //CP14 end + // Clone the old entity's grammar to the identity entity, for loc purposes. if (TryComp(uid, out var grammar)) { diff --git a/Content.Server/_CP14/IdentityRecognition/CP14IdentityRecognitionSystem.cs b/Content.Server/_CP14/IdentityRecognition/CP14IdentityRecognitionSystem.cs new file mode 100644 index 0000000000..03a5e106f9 --- /dev/null +++ b/Content.Server/_CP14/IdentityRecognition/CP14IdentityRecognitionSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared._CP14.IdentityRecognition; + +namespace Content.Server._CP14.IdentityRecognition; + +public sealed class CP14IdentityRecognitionSystem : CP14SharedIdentityRecognitionSystem +{ +} diff --git a/Content.Server/_CP14/RoundLeave/CP14RoundLeaveSystem.cs b/Content.Server/_CP14/RoundLeave/CP14RoundLeaveSystem.cs index ba99d64911..48ff5b614e 100644 --- a/Content.Server/_CP14/RoundLeave/CP14RoundLeaveSystem.cs +++ b/Content.Server/_CP14/RoundLeave/CP14RoundLeaveSystem.cs @@ -135,19 +135,16 @@ public sealed class CP14RoundLeaveSystem : EntitySystem _stationRecords.RemoveRecord(key, stationRecords); } - _chatSystem.DispatchStationAnnouncement(station.Value, - Loc.GetString( - _mobState.IsAlive(uid) ? "cp14-earlyleave-ship-announcement" : "cp14-earlyleave-ship-announcement-dead", - ("character", name), - ("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName)) - ), - Loc.GetString("cp14-ship-sender"), - playDefaultSound: false - ); + //_chatSystem.DispatchStationAnnouncement(station.Value, + // Loc.GetString( + // _mobState.IsAlive(uid) ? "cp14-earlyleave-ship-announcement" : "cp14-earlyleave-ship-announcement-dead", + // ("character", name), + // ("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName)) + // ), + // Loc.GetString("cp14-ship-sender"), + // playDefaultSound: false + //); QueueDel(uid); - - //if (mind is not null && mind.Value.Comp.Session is not null) - // _gameTicker.Respawn(mind.Value.Comp.Session); } } diff --git a/Content.Shared/_CP14/IdentityRecognition/CP14RememberedNamesComponent.cs b/Content.Shared/_CP14/IdentityRecognition/CP14RememberedNamesComponent.cs new file mode 100644 index 0000000000..afce91a5b6 --- /dev/null +++ b/Content.Shared/_CP14/IdentityRecognition/CP14RememberedNamesComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._CP14.IdentityRecognition; + +/// +/// Stores all the names of other characters that the player has memorized. +/// These players will be visible to the player under that name, rather than as nameless characters. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CP14RememberedNamesComponent : Component +{ + //Pair of NetEntity Id and names + [DataField, AutoNetworkedField] + public Dictionary Names = []; +} diff --git a/Content.Shared/_CP14/IdentityRecognition/CP14SharedIdentityRecognitionSystem.cs b/Content.Shared/_CP14/IdentityRecognition/CP14SharedIdentityRecognitionSystem.cs new file mode 100644 index 0000000000..d72788c966 --- /dev/null +++ b/Content.Shared/_CP14/IdentityRecognition/CP14SharedIdentityRecognitionSystem.cs @@ -0,0 +1,137 @@ +using Content.Shared.Examine; +using Content.Shared.Ghost; +using Content.Shared.IdentityManagement; +using Content.Shared.IdentityManagement.Components; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; +using Content.Shared.Verbs; +using Robust.Shared.Player; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared._CP14.IdentityRecognition; + +public abstract class CP14SharedIdentityRecognitionSystem : EntitySystem +{ + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly SharedIdentitySystem _identity = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnUnknownIdentityVerb); + SubscribeLocalEvent(OnExaminedEvent); + + SubscribeLocalEvent(OnRememberedNameChanged); + + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (!TryComp(ent, out var mind)) + return; + + if (mind.OwnedEntity is null) + return; + + if (mind.CharacterName is null) + return; + + RememberCharacter(ent, GetNetEntity(mind.OwnedEntity.Value), mind.CharacterName); + } + + private void OnUnknownIdentityVerb(Entity ent, ref GetVerbsEvent args) + { + if (HasComp(args.User)) + return; + + if(!_mind.TryGetMind(args.User, out var mindId, out var mind)) + return; + + if (!TryComp(args.User, out var actor)) + return; + + if (args.User == ent.Owner) + return; + + EnsureComp(mindId); + + var seeAttemptEv = new SeeIdentityAttemptEvent(); + RaiseLocalEvent(ent.Owner, seeAttemptEv); + + var _args = args; + var verb = new Verb + { + Priority = 2, + Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/sentient.svg.192dpi.png")), + Text = Loc.GetString("cp14-remember-name-verb"), + Disabled = seeAttemptEv.Cancelled, + Act = () => + { + _uiSystem.SetUiState(_args.User, CP14RememberNameUiKey.Key, new CP14RememberNameUiState(GetNetEntity(ent))); + _uiSystem.TryToggleUi(_args.User, CP14RememberNameUiKey.Key, actor.PlayerSession); + }, + }; + args.Verbs.Add(verb); + } + + private void OnExaminedEvent(Entity ent, ref ExaminedEvent args) + { + var ev = new SeeIdentityAttemptEvent(); + RaiseLocalEvent(ent.Owner, ev); + + if (ev.Cancelled) + return; + + if (!_mind.TryGetMind(args.Examiner, out var mindId, out var mind)) + return; + + if (!TryComp(mindId, out var knownNames)) + return; + + if (knownNames.Names.TryGetValue(GetNetEntity(ent).Id, out var name)) + { + args.PushMarkup(Loc.GetString("cp14-remember-name-examine", ("name", name)), priority: -1); + } + } + + private void OnRememberedNameChanged(Entity ent, ref CP14RememberedNameChangedMessage args) + { + var mindEntity = ent.Comp.Mind; + + if (mindEntity is null) + return; + + RememberCharacter(mindEntity.Value, args.Target, args.Name); + } + + private void RememberCharacter(EntityUid mindEntity, NetEntity targetId, string name) + { + var knownNames = EnsureComp(mindEntity); + + knownNames.Names[targetId.Id] = name; + Dirty(mindEntity, knownNames); + } +} + +[Serializable, NetSerializable] +public sealed class CP14RememberedNameChangedMessage(string name, NetEntity target) : BoundUserInterfaceMessage +{ + public string Name { get; } = name; + public NetEntity Target { get; } = target; +} + +[Serializable, NetSerializable] +public enum CP14RememberNameUiKey +{ + Key, +} + +[Serializable, NetSerializable] +public sealed class CP14RememberNameUiState(NetEntity target) : BoundUserInterfaceState +{ + public NetEntity Target = target; +} diff --git a/Content.Shared/_CP14/IdentityRecognition/CP14UnknownIdentityComponent.cs b/Content.Shared/_CP14/IdentityRecognition/CP14UnknownIdentityComponent.cs new file mode 100644 index 0000000000..0cf57892f6 --- /dev/null +++ b/Content.Shared/_CP14/IdentityRecognition/CP14UnknownIdentityComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._CP14.IdentityRecognition; + +/// +/// defines this character's name as unknown. +/// The name can be memorized via KnownNamesComponent, +/// and is hidden when IdentityBlocker is enabled. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class CP14UnknownIdentityComponent : Component +{ +} diff --git a/Resources/Locale/en-US/_CP14/identity/identity_recognition.ftl b/Resources/Locale/en-US/_CP14/identity/identity_recognition.ftl new file mode 100644 index 0000000000..6aea55ce4b --- /dev/null +++ b/Resources/Locale/en-US/_CP14/identity/identity_recognition.ftl @@ -0,0 +1,5 @@ +cp14-remember-name-verb = Remember name + +cp14-remember-name-name = Name + +cp14-remember-name-examine = You remember this character as [color=yellow]{$name}[/color] \ No newline at end of file diff --git a/Resources/Locale/en-US/_CP14/tips/tip.ftl b/Resources/Locale/en-US/_CP14/tips/tip.ftl index 75b4c4ec65..b17c71caa0 100644 --- a/Resources/Locale/en-US/_CP14/tips/tip.ftl +++ b/Resources/Locale/en-US/_CP14/tips/tip.ftl @@ -1,17 +1,17 @@ cp14-tips-1 = Keep an eye on the condition of your weapon! You can inspect it to see its condition and sharpness. cp14-tips-2 = If your weapon is dull, you can sharpen it with sharpening stones. cp14-tips-3 = Some light weapons, such as daggers or sickles, are effective for dual wield combat. -cp14-tips-4 = Some magic items can only work after being attuned. To customize the binding, press the RMB and select the desired action. +cp14-tips-4 = Initially, you don't know the names of the other characters! But you can remember any names and nicknames for them via the context menu. cp14-tips-5 = As an alchemist, if you mix some reagents together, you can no longer separate them! Look for the right alchemical reactions that will allow you to edit your solution. cp14-tips-6 = As an alchemist, remember to keep your cauldron off the stove or fire. Your potion may boil over, releasing a reagent cloud. -cp14-tips-7 = You can use shields to parry enemy attacks! Hit the enemy with a shield strike immediately after his attack and you can knock the weapon out of his hands. +cp14-tips-7 = As a vampire, if you try to suck out the essence of blood but there is none at the target, it can mean one of two things: Either you are eating another vampire, or your victim has already been eaten by other vampires. cp14-tips-8 = If you run out of magic energy, you can still use spells and spend mana, but it will damage you and potentially render you unconscious! -cp14-tips-9 = Don't go on the demiplanes alone, kids! The demiplanes are designed to be difficult for a group of 4 people. +cp14-tips-9 = Be careful during thunderstorms! Lightning can strike anyone and anything that is not under cover. It can cause massive fires. cp14-tips-10 = Tall bushes are good for hiding your character! But they slow you down a lot and make a lot of noise if you move in them. cp14-tips-11 = Don't forget to lock your doors if you don't want anyone to get in! -cp14-tips-12 = You can examine the demiplane key to see what you can find in it. The information may be incomplete, but you can still navigate by it, and choose where you want to go. -cp14-tips-13 = As a farmer, don't forget to water your vegetable garden! Plants die without watering. +cp14-tips-12 = You can create your own keys and locks to ensure the privacy of your territory! To do this, use key files and screwdrivers! +cp14-tips-13 = Tip number 13 does not exist. cp14-tips-14 = Demiplanes can be very dangerous, don't neglect medical consumables and alchemist potions. -cp14-tips-15 = When you use the demiplane key, an unstable rift opens up that will draw in up to 4 nearby players after a while. -cp14-tips-16 = When moving between or from the demiplane, you can additionally grab a large item (or the corpse of a dead friend) by pulling it with you during the teleportation time. -cp14-tips-17 = If you wish to leave the round, you may board a traveling ship. When it travels to the empire, you will leave the round and free up your role for another player. \ No newline at end of file +cp14-tips-15 = You can look inside the giant crystal connecting the demiplanes to see the entire current map of demiplane connections! +cp14-tips-16 = The main source of income for adventurers is the extraction of raw resources within pocket dimensions known as demi-planes. +cp14-tips-17 = The magic vision spell allows you to see where and when spells were used! Investigators can use this to search for criminals. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_CP14/identity/identity_recognition.ftl b/Resources/Locale/ru-RU/_CP14/identity/identity_recognition.ftl new file mode 100644 index 0000000000..05304de6af --- /dev/null +++ b/Resources/Locale/ru-RU/_CP14/identity/identity_recognition.ftl @@ -0,0 +1,5 @@ +cp14-remember-name-verb = Запомнить имя + +cp14-remember-name-name = Имя + +cp14-remember-name-examine = Вы помните этого персонажа как [color=yellow]{$name}[/color] \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_CP14/tips/tip.ftl b/Resources/Locale/ru-RU/_CP14/tips/tip.ftl index 5822011e4b..8e9eee1762 100644 --- a/Resources/Locale/ru-RU/_CP14/tips/tip.ftl +++ b/Resources/Locale/ru-RU/_CP14/tips/tip.ftl @@ -1,17 +1,17 @@ cp14-tips-1 = Следите за состоянием вашего оружия! Вы можете осмотреть его, чтобы увидеть его состояние и остроту. cp14-tips-2 = Если ваше оружие затупилось, вы можете заточить его при помощи точильных камней. cp14-tips-3 = Некоторое легкое оружие, такое как кинжалы или серпы, эффективно для боя с двух рук. -cp14-tips-4 = Некоторые магические предметы могут работать только после привязки. Чтобы настроить привязку, нажмите ПКМ и выберите нужное действие. +cp14-tips-4 = Изначально вы не знаете как зовут других персонажей! Но вы можете запомнить любые имена и клички для них через контекстное меню. cp14-tips-5 = Будучи алхимиком, если вы смешали какие-то реагенты вместе, вы больше не сможете их разделить! Ищите нужные алхимические реакции, которые позволят вам редактировать ваш раствор. cp14-tips-6 = Будучи алхимиком, не забывайте убрать ваш котелок с печки или костра. Ваше зелье может выкипеть, выпустив реагентное облако. -cp14-tips-7 = Вы можете использовать щиты, чтобы парировать вражеские атаки! Попадите по противнику ударом щита сразу же после его атаки, и вы сможете выбить оружие из его рук. +cp14-tips-7 = Будучи вампиром, если вы пытаетесь высосать эссенции крови, но ее у цели нет, это может значить одно из двух: Или вы кушаете другого вампира, или вашу жертву уже кушали другие вампиры. cp14-tips-8 = Если у вас кончилась магическая энергия, вы все еще можете использовать заклинания и тратить ману, но это будет наносить вам урон, и потенциально может лишить вас сознания! -cp14-tips-9 = Не ходите, дети, в демипланы в одиночку! Демипланы рассчитаны по сложности на группу из 4 человек. +cp14-tips-9 = Будьте внимательны во время грозы! Молния может ударить в кого угодно и во что угодно, что не находится под крышей. И вызвать массвые пожары. cp14-tips-10 = Высокие кусты неплохо прячут вашего персонажа! Но сильно замедляют передвижение и шумят, если вы двигаетесь в них. cp14-tips-11 = Не забывайте закрывать двери на ключ, если не хотите чтобы туда заходил кто попало! -cp14-tips-12 = Вы можете осмотреть ключ демиплана, чтобы узнать, что вы можете в нем найти. Информация может быть неполной, но по ней вы все равно можете ориентироваться, и выбирать куда вы хотите отправиться. -cp14-tips-13 = Будучи фермером, не забывайте поливать свой огород! Растения умирают без полива. +cp14-tips-12 = Вы можете создавать свои ключи и замки, чтобы обеспечить приватность территории! Для этого пользуйтесь нпильниками для ключей и отвертками! +cp14-tips-13 = Совета номер 13 не существует. cp14-tips-14 = Демипланы могут быть очень опасны, не пренебрегайте медицинскими расходными материалами и алхимическими зельями. -cp14-tips-15 = Когда вы используете ключ демиплана, открывается нестабильный разлом, который через некоторое время затянет в себя до 4 ближайших игроков. -cp14-tips-16 = Перемещаясь между демипланом или из него, вы можете дополнительно захватить с собой большой предмет (или труп погибшего союзника), держа его во время момента телепортации. -cp14-tips-17 = Если вы хотите покинуть раунд, вы можете сесть на странствующий корабль. Когда он отправится в империю, вы покинете раунд и освободите свою роль для другого игрока. \ No newline at end of file +cp14-tips-15 = Вы можете заглянуть внутрь гигантского кристалла связи с демипланами, чтобы увидеть всю текущую карту демипланов! +cp14-tips-16 = Основным заработком авантюристов является добыча сырых ресурсов внутри карманных измерений-демипланов. +cp14-tips-17 = Заклинание магического зрения позволяет видеть где и когда были использованы заклинания! Дознаватели стражи могут использовать это для поиска преступников. \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Clothing/Masks/vampire_mask.yml b/Resources/Prototypes/_CP14/Entities/Clothing/Masks/vampire_mask.yml index 085cf76239..1164b5598d 100644 --- a/Resources/Prototypes/_CP14/Entities/Clothing/Masks/vampire_mask.yml +++ b/Resources/Prototypes/_CP14/Entities/Clothing/Masks/vampire_mask.yml @@ -4,24 +4,16 @@ - CP14ClothingMaskBase - CP14BaseMajorContraband id: CP14ClothingMaskVampireVoiceBase - description: This mask reeks of blood. The spells inside it distort the speaker's voice. + description: This mask reeks of blood. Effectively conceals the identity of the wearer. suffix: Voice mask components: - type: HideLayerClothing slots: - Snout - type: IdentityBlocker - - type: VoiceMask - - type: UserInterface - interfaces: - enum.ChameleonUiKey.Key: - type: ChameleonBoundUserInterface - enum.VoiceMaskUIKey.Key: - type: VoiceMaskBoundUserInterface - type: PhysicalComposition materialComposition: CP14Leather: 10 - CP14BloodEssence: 1 - type: entity parent: CP14ClothingMaskVampireVoiceBase diff --git a/Resources/Prototypes/_CP14/Entities/Mobs/Species/base.yml b/Resources/Prototypes/_CP14/Entities/Mobs/Species/base.yml index 49d11c6e0d..608cfc8041 100644 --- a/Resources/Prototypes/_CP14/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/_CP14/Entities/Mobs/Species/base.yml @@ -195,6 +195,8 @@ type: HumanoidMarkingModifierBoundUserInterface enum.StrippingUiKey.Key: type: StrippableBoundUserInterface + enum.CP14RememberNameUiKey.Key: + type: CP14IdentityRecognitionBoundUserInterface - type: Puller - type: Speech speechSounds: Alto @@ -236,6 +238,7 @@ - MartialArts - Craftsmanship - type: CP14VampireEssenceHolder + - type: CP14UnknownIdentity - type: entity parent: diff --git a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/devourers.yml b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/devourers.yml index cd89d20844..47347e877a 100644 --- a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/devourers.yml +++ b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/devourers.yml @@ -9,9 +9,6 @@ - !type:StackResource stack: CP14ThinLeather count: 2 - - !type:StackResource - stack: CP14BloodEssence - count: 1 result: CP14ClothingMaskVampireVoiceDevourers resultCount: 1 diff --git a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/night_children.yml b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/night_children.yml index a6601158e2..cb9e9c6165 100644 --- a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/night_children.yml +++ b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/night_children.yml @@ -9,9 +9,6 @@ - !type:StackResource stack: CP14ThinLeather count: 2 - - !type:StackResource - stack: CP14BloodEssence - count: 1 result: CP14ClothingMaskVampireVoiceNightChildrens resultCount: 1 diff --git a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/unnameable.yml b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/unnameable.yml index 847582f168..9ec1f19145 100644 --- a/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/unnameable.yml +++ b/Resources/Prototypes/_CP14/Recipes/Workbench/Vampire/unnameable.yml @@ -9,9 +9,6 @@ - !type:StackResource stack: CP14ThinLeather count: 2 - - !type:StackResource - stack: CP14BloodEssence - count: 1 result: CP14ClothingMaskVampireVoiceUnnameable resultCount: 1 diff --git a/Resources/Prototypes/_CP14/secret_weights.yml b/Resources/Prototypes/_CP14/secret_weights.yml index da43c6a6c5..3fd4c2c47e 100644 --- a/Resources/Prototypes/_CP14/secret_weights.yml +++ b/Resources/Prototypes/_CP14/secret_weights.yml @@ -1,6 +1,6 @@ - type: weightedRandom id: Secret weights: - CP14Peaceful: 1 - CP14GameRuleVampireClanBattleTriple: 1 - CP14GameRuleVampireClanBattleDouble: 1 \ No newline at end of file + CP14Peaceful: 0.2 + CP14GameRuleVampireClanBattleTriple: 0.4 + CP14GameRuleVampireClanBattleDouble: 0.4 \ No newline at end of file