cherrypick: PR 149 and 329 from cosmatic-drift-14/cosmatic-drift (#3409)

* Synth Trait (cosmatic-drift-14/cosmatic-drift#149 and cosmatic-drift-14/cosmatic-drift#329) from cosmatic-drift-14/cosmatic-drift

* Initial trait implementation

* Fix the trait.

* Readd fields.

* fix: required comments for code changes upstream

* feat: added excluded species field to traits.yml

* fix: switching races now disables the unsupported trait

* chore: added missing comment

* fix: requested changes

* fix: CR Round 2

* chore: missed changes in foreign file
This commit is contained in:
Falcon 2025-04-10 10:42:24 -07:00 committed by GitHub
parent e517320b23
commit d94ea1d0e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 137 additions and 4 deletions

View File

@ -227,6 +227,7 @@ namespace Content.Client.Lobby.UI
{
SpeciesButton.SelectId(args.Id);
SetSpecies(_species[args.Id].ID);
RefreshTraits(); // DeltaV - Allows for hiding traits
UpdateHairPickers();
OnSkinColorOnValueChanged();
};
@ -559,6 +560,14 @@ namespace Content.Client.Lobby.UI
foreach (var trait in traits)
{
// Begin DeltaV Additions - Species trait exclusion
if (Profile?.Species is { } selectedSpecies && trait.ExcludedSpecies.Contains(selectedSpecies))
{
Profile = Profile?.WithoutTraitPreference(trait.ID, _prototypeManager);
continue;
}
// End DeltaV Additions
if (trait.Category == null)
{
defaultTraits.Add(trait.ID);

View File

@ -1,14 +1,22 @@
using Content.Server._CD.Traits; // CD - synth trait
using Content.Server.Silicons.Laws;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Station.Components;
// CD - start synth trait
using Content.Server.Chat.Managers;
using Content.Shared.Chat;
using Robust.Shared.Player;
using Robust.Shared.Random;
// CD - end synth trait
namespace Content.Server.StationEvents.Events;
public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
{
[Dependency] private readonly IonStormSystem _ionStorm = default!;
[Dependency] private readonly IChatManager _chatManager = default!; // CD - Used for synth trait
protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
@ -17,6 +25,22 @@ public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
if (!TryGetRandomStation(out var chosenStation))
return;
// CD - Go through everyone with the SynthComponent and inform them a storm is happening.
var synthQuery = EntityQueryEnumerator<SynthComponent>();
while (synthQuery.MoveNext(out var ent, out var synthComp))
{
if (RobustRandom.Prob(synthComp.AlertChance))
continue;
if (!TryComp<ActorComponent>(ent, out var actor))
continue;
var msg = Loc.GetString("station-event-ion-storm-synth");
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Yellow);
}
// CD - End of synth trait
var query = EntityQueryEnumerator<SiliconLawBoundComponent, TransformComponent, IonStormTargetComponent>();
while (query.MoveNext(out var ent, out var lawBound, out var xform, out var target))
{

View File

@ -0,0 +1,14 @@
namespace Content.Server._CD.Traits;
/// <summary>
/// Set players' blood to coolant, and is used to notify them of ion storms
/// </summary>
[RegisterComponent, Access(typeof(SynthSystem))]
public sealed partial class SynthComponent : Component
{
/// <summary>
/// The chance that the synth is alerted of an ion storm
/// </summary>
[DataField]
public float AlertChance = 0.3f;
}

View File

@ -0,0 +1,36 @@
using Content.Server.Body.Systems;
using Content.Server.Database;
using Content.Shared.Chat.TypingIndicator;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;
namespace Content.Server._CD.Traits;
public sealed class SynthSystem : EntitySystem
{
// Begin DeltaV - make strings static readonly
private static readonly ProtoId<TypingIndicatorPrototype> RobotTypingIndicator = "robot";
private static readonly ProtoId<ReagentPrototype> SynthBloodReagent = "SynthBlood";
// End DeltaV
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SynthComponent, ComponentStartup>(OnStartup);
}
private void OnStartup(EntityUid uid, SynthComponent component, ComponentStartup args)
{
if (TryComp<TypingIndicatorComponent>(uid, out var indicator))
{
indicator.TypingIndicatorPrototype = RobotTypingIndicator; // DeltaV - make strings static readonly
Dirty(uid, indicator);
}
// Give them synth blood. Ion storm notif is handled in that system
_bloodstream.ChangeBloodReagent(uid, SynthBloodReagent); // DeltaV - make strings static readonly
}
}

View File

@ -1,4 +1,4 @@
using Robust.Shared.GameStates;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Chat.TypingIndicator;
@ -7,13 +7,13 @@ namespace Content.Shared.Chat.TypingIndicator;
/// Show typing indicator icon when player typing text in chat box.
/// Added automatically when player poses entity.
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedTypingIndicatorSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] // CD - AutoGenerateComponentState fixes a bug with synth trait
// [Access(typeof(SharedTypingIndicatorSystem))] CD - Restricted access breaks synth trait because it rewrites the speech bubble over the default race indicator
public sealed partial class TypingIndicatorComponent : Component
{
/// <summary>
/// Prototype id that store all visual info about typing indicator.
/// </summary>
[DataField("proto")]
[DataField("proto"), AutoNetworkedField] // CD - AutoNetworkedField fixes a bug in synth trait
public ProtoId<TypingIndicatorPrototype> TypingIndicatorPrototype = "default";
}

View File

@ -1,5 +1,6 @@
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
using Content.Shared.Humanoid.Prototypes; // DeltaV - Trait species hiding
namespace Content.Shared.Traits;
@ -60,4 +61,10 @@ public sealed partial class TraitPrototype : IPrototype
/// </summary>
[DataField]
public ProtoId<TraitCategoryPrototype>? Category;
/// <summary>
/// DeltaV - Hides traits from specific species
/// </summary>
[DataField]
public HashSet<ProtoId<SpeciesPrototype>> ExcludedSpecies = new();
}

View File

@ -0,0 +1,2 @@
reagent-name-synth-blood = synth blood
reagent-desc-synth-blood = Not quite coolant, not quite blue powerade.

View File

@ -0,0 +1 @@
station-event-ion-storm-synth = You detect an Ion Storm. Your internal systems may be tampered with or damaged as a result.

View File

@ -0,0 +1,2 @@
trait-synth-name = Synthetic
trait-synth-desc = You are a biomechanical construct, who bleeds coolant and is notified of ongoing Ion Storms.

View File

@ -0,0 +1,23 @@
- type: reagent
id: SynthBlood
name: reagent-name-synth-blood
group: Biological
desc: reagent-desc-synth-blood
flavor: metallic
color: "#00b8f5"
recognizable: true
physicalDesc: reagent-physical-desc-reflective
slippery: false
metabolisms:
Drink:
effects:
- !type:SatiateThirst
factor: 1.5
conditions:
- !type:OrganType
type: Human
shouldHave: false
footstepSound:
collection: FootstepBlood
params:
volume: 6

View File

@ -0,0 +1,15 @@
- type: trait
category: Quirks
id: Synthetic
name: trait-synth-name
description: trait-synth-desc
# Begin DeltaV Additions - blacklist IPCs
blacklist:
components:
- Silicon
- BorgChassis
excludedSpecies:
- IPC
# End DeltaV Additions - blacklist IPCs
components:
- type: Synth