-
Notifications
You must be signed in to change notification settings - Fork 592
After all this time, finally, stains #5898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: starlight-dev
Are you sure you want to change the base?
Changes from all commits
1e5c455
1a716c9
5fc98a3
eee9c6d
b73cad7
255b857
22379f0
9a4bd41
f63c5a7
77f7ba9
dd0dec1
821602c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| using Content.Client.Clothing; | ||
| using Content.Client.Items.Systems; | ||
| using Content.Shared._Funkystation.Stains.Components; | ||
| using Content.Shared._Funkystation.Stains.Systems; | ||
| using Content.Shared.Chemistry.EntitySystems; | ||
| using Content.Shared.Clothing; | ||
| using Content.Shared.FixedPoint; | ||
| using Content.Shared.Hands; | ||
| using Robust.Client.GameObjects; | ||
| using Robust.Shared.Prototypes; | ||
|
|
||
| namespace Content.Client._Funkystation.Stains; | ||
|
|
||
| public sealed partial class StainSystem : SharedStainSystem | ||
| { | ||
| [Dependency] private IPrototypeManager _prototypeManager = null!; | ||
| [Dependency] private SharedSolutionContainerSystem _solution = null!; | ||
| [Dependency] private SpriteSystem _sprite = null!; | ||
|
|
||
| public override void Initialize() | ||
| { | ||
| base.Initialize(); | ||
| SubscribeLocalEvent<StainableComponent, AppearanceChangeEvent>(OnAppearanceChanged); | ||
| SubscribeLocalEvent<StainableComponent, GetEquipmentVisualsEvent>(OnEquipmentVisuals, after: [typeof(ClientClothingSystem)]); | ||
| SubscribeLocalEvent<StainableComponent, GetInhandVisualsEvent>(OnInhandVisuals, after: [typeof(ItemSystem)]); | ||
| } | ||
|
|
||
| private void OnAppearanceChanged(Entity<StainableComponent> ent, ref AppearanceChangeEvent args) | ||
| { | ||
| if (args.Sprite == null) | ||
| return; | ||
|
|
||
| var spriteEnt = new Entity<SpriteComponent?>(ent.Owner, args.Sprite); | ||
|
|
||
| var layers = new List<int>(ent.Comp.RevealedLayers); | ||
| layers.Sort((a, b) => b.CompareTo(a)); | ||
|
|
||
| foreach (var layer in layers) | ||
| { | ||
| _sprite.RemoveLayer(spriteEnt, layer); | ||
| } | ||
|
|
||
| ent.Comp.RevealedLayers.Clear(); | ||
|
|
||
| foreach (var (_, layerData) in BuildVisuals(ent, ent.Comp.IconVisuals, "icon")) | ||
| { | ||
| ent.Comp.RevealedLayers.Add(_sprite.AddLayer(spriteEnt, layerData, null)); | ||
| } | ||
| } | ||
|
|
||
| private void OnEquipmentVisuals(Entity<StainableComponent> ent, ref GetEquipmentVisualsEvent args) | ||
| { | ||
| if (ent.Comp.ClothingVisuals.TryGetValue(args.Slot, out var layers)) | ||
| args.Layers.AddRange(BuildVisuals(ent, layers, args.Slot)); | ||
| } | ||
|
|
||
| private void OnInhandVisuals(Entity<StainableComponent> ent, ref GetInhandVisualsEvent args) | ||
| { | ||
| if (ent.Comp.ItemVisuals.TryGetValue(args.Location.ToString(), out var layers)) | ||
| args.Layers.AddRange(BuildVisuals(ent, layers, args.Location.ToString())); | ||
| } | ||
|
|
||
| private IEnumerable<(string, PrototypeLayerData)> BuildVisuals(Entity<StainableComponent> ent, List<PrototypeLayerData> templates, string prefix) | ||
| { | ||
| if (!_solution.TryGetSolution(ent.Owner, ent.Comp.SolutionName, out _, out var sol) || sol.Volume <= FixedPoint2.Zero) | ||
| yield break; | ||
|
|
||
| var color = sol.GetColor(_prototypeManager); | ||
| for (var i = 0; i < templates.Count; i++) | ||
| { | ||
| var layer = templates[i]; | ||
| layer.Color = color; | ||
| yield return ($"stain-{prefix}-{i}", layer); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| using Content.Shared._Funkystation.WashingMachine; | ||
|
|
||
| namespace Content.Client._Funkystation.WashingMachine; | ||
|
|
||
| public sealed class WashingMachineSystem : SharedWashingMachineSystem; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| using Content.Shared._Funkystation.Stains.Components; | ||
| using Content.Shared._Funkystation.Stains.Systems; | ||
| using Content.Shared.Chemistry.Components; | ||
| using Content.Shared.Tag; | ||
| using Robust.Shared.Prototypes; | ||
|
|
||
| namespace Content.Server._Funkystation.Stains; | ||
|
|
||
| public sealed partial class StainSystem : SharedStainSystem | ||
| { | ||
| [Dependency] private TagSystem _tag = null!; | ||
|
|
||
| private static readonly ProtoId<TagPrototype> Tag = "DNASolutionScannable"; | ||
|
|
||
| protected override void OnStained(Entity<StainableComponent> ent, Entity<SolutionComponent> solution) | ||
| { | ||
| base.OnStained(ent, solution); | ||
|
|
||
| _tag.AddTag(ent.Owner, Tag); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| using Content.Shared._Funkystation.WashingMachine; | ||
| using Content.Shared._Funkystation.Stains.Components; | ||
| using Content.Shared._Funkystation.Stains.Systems; | ||
| using Content.Shared.Chemistry.EntitySystems; | ||
| using Content.Shared.Chemistry.Components; | ||
| using Content.Shared.Damage; | ||
| using Content.Shared.Damage.Prototypes; | ||
| using Content.Shared.Destructible; | ||
| using Content.Shared.Storage.Components; | ||
| using Content.Server.Forensics; | ||
| using Content.Shared.Clothing.Components; | ||
| using Robust.Shared.Audio; | ||
| using Robust.Shared.Prototypes; | ||
| using Robust.Shared.Random; | ||
| using System.Linq; | ||
| using Content.Shared.Chemistry; | ||
| using Content.Shared.Damage.Systems; | ||
|
|
||
| namespace Content.Server._Funkystation.WashingMachine; | ||
|
|
||
| public sealed partial class WashingMachineSystem : SharedWashingMachineSystem | ||
| { | ||
| [Dependency] private SharedSolutionContainerSystem _solution = null!; | ||
| [Dependency] private ForensicsSystem _forensics = null!; | ||
|
|
||
| protected override void UpdateForensics(Entity<WashingMachineComponent> ent, HashSet<EntityUid> items) | ||
| { | ||
| if (!TryComp<ForensicsComponent>(ent.Owner, out var forensics)) | ||
| return; | ||
|
|
||
| foreach (var item in items) | ||
| { | ||
| // Pull DNA out of the item's stain solution before the shared FinishWash washes it out. | ||
| if (TryComp<StainableComponent>(item, out var stain) | ||
| && _solution.TryGetSolution(item, stain.SolutionName, out var sol)) | ||
| { | ||
| forensics.DNAs.UnionWith(_forensics.GetSolutionsDNA(sol.Value.Comp.Solution)); | ||
| } | ||
|
|
||
| if (!TryComp<FiberComponent>(item, out var fiber)) | ||
| continue; | ||
|
|
||
| var fiberText = fiber.FiberColor == null | ||
| ? Loc.GetString("forensic-fibers", ("material", fiber.FiberMaterial)) | ||
| : Loc.GetString("forensic-fibers-colored", | ||
| ("color", fiber.FiberColor), | ||
| ("material", fiber.FiberMaterial)); | ||
|
|
||
| forensics.Fibers.Add(fiberText); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ | |
| using Content.Shared.Verbs; | ||
| using Content.Shared.Weapons.Melee; | ||
| using Content.Shared.Weapons.Melee.Events; | ||
| using Content.Shared._Funkystation.Fluids; | ||
| using Robust.Shared.Player; | ||
|
|
||
| namespace Content.Shared.Fluids; | ||
|
|
@@ -163,6 +164,14 @@ private void SplashOnMeleeHit(Entity<SpillableComponent> entity, ref MeleeHitEve | |
|
|
||
| var splitSolution = _solutionContainerSystem.SplitSolution(soln.Value, totalSplit / hitCount); | ||
|
|
||
| // Forky - Start - Stains | ||
| if (splitSolution.Volume > 0) | ||
| { | ||
| var stainEv = new SpilledOnEvent(entity.Owner, splitSolution.Clone()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. partial it out |
||
| RaiseLocalEvent(hit, stainEv); | ||
| } | ||
| // Forky - End | ||
|
|
||
| AdminLogger.Add(LogType.MeleeHit, | ||
| $"{ToPrettyString(args.User):actor} " | ||
| + $"splashed {SharedSolutionContainerSystem.ToPrettyString(splitSolution):solution} " | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| using System.Linq; | ||
| using Content.Shared._Funkystation.Fluids; | ||
| using Content.Shared.Administration.Logs; | ||
| using Content.Shared.Chemistry; | ||
| using Content.Shared.Chemistry.Components; | ||
|
|
@@ -10,17 +11,22 @@ | |
| using Content.Shared.FixedPoint; | ||
| using Content.Shared.Fluids.Components; | ||
| using Content.Shared.Friction; | ||
| using Content.Shared.Gravity; | ||
| using Content.Shared.Inventory; | ||
| using Content.Shared.Movement.Components; | ||
| using Content.Shared.Movement.Events; | ||
| using Content.Shared.Movement.Systems; | ||
| using Content.Shared.Nutrition.EntitySystems; | ||
| using Content.Shared.Popups; | ||
| using Content.Shared.Slippery; | ||
| using Content.Shared.Standing; | ||
| using Content.Shared.StepTrigger.Components; | ||
| using Content.Shared.StepTrigger.Systems; | ||
| using Robust.Shared.Audio.Systems; | ||
| using Robust.Shared.Containers; | ||
| using Robust.Shared.Map; | ||
| using Robust.Shared.Physics.Components; | ||
| using Robust.Shared.Physics.Events; | ||
| using Robust.Shared.Prototypes; | ||
| using Robust.Shared.Timing; | ||
|
|
||
|
|
@@ -41,6 +47,13 @@ public abstract partial class SharedPuddleSystem : EntitySystem | |
| [Dependency] private SpeedModifierContactsSystem _speedModContacts = default!; | ||
| [Dependency] private StepTriggerSystem _stepTrigger = default!; | ||
| [Dependency] private TileFrictionController _tile = default!; | ||
| [Dependency] private InventorySystem _inventory = default!; // Funky - Clothing stains | ||
| [Dependency] private StandingStateSystem _standing = default!; // Moff - Clothing stains | ||
| [Dependency] private SharedGravitySystem _gravity = default!; // Moff - Clothing Stains | ||
|
|
||
| [Dependency] private EntityQuery<StepTriggerComponent> _stepTriggerQuery = default!; | ||
| [Dependency] private EntityQuery<ReactiveComponent> _reactiveQuery = default!; | ||
| [Dependency] private EntityQuery<EvaporationComponent> _evaporationQuery = default!; | ||
|
Comment on lines
+50
to
+56
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Mark these changes as Starlight-owned. The repository convention requires Starlight markers for changes outside 🤖 Prompt for AI Agents |
||
|
|
||
| private ProtoId<ReagentPrototype>[] _standoutReagents = []; | ||
|
|
||
|
|
@@ -55,10 +68,6 @@ public abstract partial class SharedPuddleSystem : EntitySystem | |
| // loses & then gains reagents in a single tick. | ||
| private HashSet<EntityUid> _deletionQueue = []; | ||
|
|
||
| private EntityQuery<StepTriggerComponent> _stepTriggerQuery; | ||
| private EntityQuery<ReactiveComponent> _reactiveQuery; | ||
| private EntityQuery<EvaporationComponent> _evaporationQuery; | ||
|
|
||
| public override void Initialize() | ||
| { | ||
| base.Initialize(); | ||
|
|
@@ -98,6 +107,40 @@ public override void Update(float frameTime) | |
| TickEvaporation(); | ||
| } | ||
|
|
||
| // Moff start - we basically rewrote this function compared to what funky has | ||
| // Using startcollide rather than onstep, since the onstep is messed with by slippable... its bleak | ||
| [SubscribeLocalEvent] | ||
| private void OnStepInPuddle(Entity<PuddleComponent> ent, ref StartCollideEvent args) | ||
| { | ||
| // The thing stepping in the puddle. Because I keep forgetting which is which | ||
| var stepper = args.OtherEntity; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. partial it out |
||
|
|
||
| if (!_solutionContainerSystem.ResolveSolution(ent.Owner, ent.Comp.SolutionName, ref ent.Comp.Solution, out var solution)) | ||
| return; | ||
|
|
||
| if (solution.Volume <= FixedPoint2.Zero) | ||
| return; | ||
|
|
||
| // Check if its in air... because... if you're not on the ground you don't get spilled on | ||
| if (TryComp<PhysicsComponent>(stepper, out var physicsComp) | ||
| && (physicsComp.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(stepper))) | ||
| return; | ||
|
|
||
| // Choose le target... | ||
| // if standing and have shoes, just get it on their shoes | ||
| EntityUid target; | ||
| if (_standing.IsDown(stepper)) // on the ground, spill it on them in general | ||
| target = stepper; | ||
| else if (_inventory.TryGetSlotEntity(stepper, "shoes", out var shoes) && shoes is { } shoeUid) | ||
| target = shoeUid; | ||
| else | ||
| return; | ||
|
|
||
| var spilledEvent = new SpilledOnEvent(ent.Owner, solution); | ||
| RaiseLocalEvent(target, spilledEvent); | ||
| } | ||
| // Moff end | ||
|
|
||
| private void OnPrototypesReloaded(PrototypesReloadedEventArgs ev) | ||
| { | ||
| if (ev.WasModified<ReagentPrototype>()) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Content.Shared.Chemistry.Components; | ||
| using Content.Shared.Inventory; | ||
|
|
||
| namespace Content.Shared._Funkystation.Fluids; | ||
|
|
||
| /// <summary> | ||
| /// Raised when a fluid is spilled on an entity | ||
| /// </summary> | ||
| public sealed class SpilledOnEvent(EntityUid source, Solution solution) : EntityEventArgs, IInventoryRelayEvent | ||
| { | ||
| public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET; | ||
|
|
||
| public EntityUid Source = source; | ||
| public Solution Solution = solution; | ||
|
Comment on lines
+9
to
+14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Make stain transfer consume
Update the consumer to transfer from 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| using Content.Shared.Inventory; | ||
| using Robust.Shared.GameStates; | ||
|
|
||
| namespace Content.Shared._Funkystation.Stains.Components; | ||
|
|
||
| /// <summary> | ||
| /// Prevents entities equipped in specific slots underneath this item from getting stained | ||
| /// </summary> | ||
| [RegisterComponent, NetworkedComponent] | ||
| public sealed partial class StainBlockerComponent : Component | ||
| { | ||
| [DataField("slots", required: true)] | ||
| public SlotFlags BlockedSlots; | ||
|
Comment on lines
+12
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Add XML documentation to avoid RA0032 build errors.
🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Configure stain layers for in-hand clothing.
OnInhandVisualsreads onlyItemVisuals. The reviewed prototypes define onlyIconVisuals, so stained clothing has no overlay while held.Content.Client/_Funkystation/Stains/StainSystem.cs#L57-L60: Add a safe fallback only if the icon layer data is valid for in-hand rendering.Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml#L30-L37: Add the requireditemVisualsmappings.Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml#L27-L34: Add the required base helmetitemVisualsmappings.Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml#L216-L223: Add the required hardsuit helmetitemVisualsmappings.Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml#L16-L23: Add the requireditemVisualsmappings.Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml#L13-L20: Add inherited outerwearitemVisualsmappings.📍 Affects 5 files
Content.Client/_Funkystation/Stains/StainSystem.cs#L57-L60(this comment)Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml#L30-L37Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml#L27-L34Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml#L216-L223Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml#L16-L23Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml#L13-L20🤖 Prompt for AI Agents