Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5aab2d0
Fixed Radium & Sulfur Barrel Prices & Re-Added Back Barrel Sales
LukeZurg22 Nov 20, 2025
aa906fc
Added New Pressure Plate Textures [Sketch]
LukeZurg22 Nov 20, 2025
6bbaab9
Tuned Popsicle Sticks to be Sellable
LukeZurg22 Nov 20, 2025
173a8eb
Fixed Pressure Plate Sprite Credit
LukeZurg22 Nov 20, 2025
cf104fb
Added Warper Textures
LukeZurg22 Nov 21, 2025
529aef2
Set Warper Textures to Mining Station Textures, For Now
LukeZurg22 Nov 21, 2025
fb7fcae
Added Warper Localization
LukeZurg22 Nov 21, 2025
1abcc5e
Tuned Wooden Crate Sprites
LukeZurg22 Nov 21, 2025
6e07e7d
Updated warper.ftl
LukeZurg22 Nov 21, 2025
835371c
Tuned Emancipation Grid Cost to 15k from 25k
LukeZurg22 Nov 21, 2025
f33e4c4
Added New Locale to warper.ftl
LukeZurg22 Nov 21, 2025
6157c4c
Added Warper Prototypes
LukeZurg22 Nov 21, 2025
24ea1f8
Added Warper System & Component
LukeZurg22 Nov 21, 2025
c18f0dd
Add stencil decals for use in the spraypainter (#3778)
Alkheemist Aug 16, 2025
7bedbbc
Ported New Spraypainter Tools (PART 1)
LukeZurg22 Nov 21, 2025
daeea97
Ported New Spray Painter Locale (PART 2)
LukeZurg22 Nov 21, 2025
0f0a286
Ported New Spraypainter Ammo Sprites (PART 3)
LukeZurg22 Nov 21, 2025
61dd6f3
Updated ActionUIController.cs
LukeZurg22 Nov 21, 2025
9b75841
Reordered Airlock Prototypes (PART 5)
LukeZurg22 Nov 21, 2025
65f1165
Moved RechargeComponent to Shared
LukeZurg22 Nov 21, 2025
c229e87
Ported DeltaV Felinids
LukeZurg22 Nov 21, 2025
eb5d1cf
Added Spraypainter Ammo to Engineering Lathe (PART 6)
LukeZurg22 Nov 21, 2025
d5c28ab
Fixed Paintable Airlocks in external.yml (PART 7)
LukeZurg22 Nov 21, 2025
46c83a9
Removed Paintable Airlock Components from Frontier Airlocks (PART 8)
LukeZurg22 Nov 21, 2025
a40428d
Resolved Airlock Components (PART 4)
LukeZurg22 Nov 21, 2025
7ee991c
Refactored Charges for Various Actions & Tools
LukeZurg22 Nov 21, 2025
eec2212
Fixed ChitinidSystem.cs Charges Reference, Hopefully
LukeZurg22 Nov 21, 2025
19b1a54
Ported Charges Systems (PART 9)
LukeZurg22 Nov 21, 2025
d2e4fe1
Updated animate_spell.yml
LukeZurg22 Nov 21, 2025
cfb77e3
Fixed Structures Closets Canisters Lockers and Group Paintabilities
LukeZurg22 Nov 21, 2025
2f9f1c5
Updated fluff_lights.yml
LukeZurg22 Nov 21, 2025
41de8d9
Updated lantern.yml
LukeZurg22 Nov 21, 2025
7e9ea2b
Added Expanded SoundFont
LukeZurg22 Nov 21, 2025
eb8532b
Spraypainter Systems Overhaul Port
LukeZurg22 Nov 21, 2025
f1b6238
Ported Paintable Components
LukeZurg22 Nov 21, 2025
97a751f
Switched Dashes to Charges
LukeZurg22 Nov 21, 2025
7bb82b6
Updated Door System
LukeZurg22 Nov 21, 2025
f98bd0a
Cleaned gas_canisters.yml
LukeZurg22 Nov 21, 2025
01d4af2
Updated security.yml
LukeZurg22 Nov 21, 2025
392e6ef
Updated shuttle.yml
LukeZurg22 Nov 21, 2025
6222255
Updated EmagSystem.cs
LukeZurg22 Nov 21, 2025
79e989e
Updated EntityStorageVisualizerSystem.cs
LukeZurg22 Nov 21, 2025
fcf3781
Updated FlashSystem.cs
LukeZurg22 Nov 21, 2025
d957820
Updated LimitedChargesComponent.cs
LukeZurg22 Nov 21, 2025
5f12429
Updated Projectile YAMLs
LukeZurg22 Nov 21, 2025
a3f41ce
Ported Paintable Crates & Groups
LukeZurg22 Nov 21, 2025
b65a57b
Ported Paintable Group Categories (PART 10)
LukeZurg22 Nov 21, 2025
b7f6f2a
Added Missing Sprayer Sprites
LukeZurg22 Nov 21, 2025
3f7190c
Ported Atmos Pipe Layering Fix
LukeZurg22 Nov 21, 2025
c0fd2ec
Updated clockwork.yml Paintable Airlocks
LukeZurg22 Nov 21, 2025
002790b
Updated lockers.yml to be Paintable
LukeZurg22 Nov 21, 2025
793cb26
Removed MaxPressure from GasPressurePumpBoundUserInterface.cs
LukeZurg22 Nov 21, 2025
e6e6ccd
Removed Salvage Airlock from Paint Groups
LukeZurg22 Nov 21, 2025
b12e622
Replaced Non-Present Airlock Textures with Placeholders
LukeZurg22 Nov 21, 2025
9ae814e
Updated SharedAtmosPipeLayersSystem.cs To No Longer Popup Predicted M…
LukeZurg22 Nov 21, 2025
ddf633c
Removed Salvage Airlocks from Painter
LukeZurg22 Nov 21, 2025
1d99a83
Ported New RCD Shared Charges Handling
LukeZurg22 Nov 21, 2025
42c3552
Ported Spray Painter System
LukeZurg22 Nov 21, 2025
1837524
Updated SpellbookSystem.cs to use New Charge System
LukeZurg22 Nov 21, 2025
1c94711
Removed Invalid Wall Locker Reference in locker_groups.yml
LukeZurg22 Nov 21, 2025
01b9610
Reworked Warper YML
LukeZurg22 Nov 21, 2025
08a0c33
Greatly Improved Warper System & Fixed Bugs
LukeZurg22 Nov 21, 2025
5aed43b
Updated NullSectorIntro.xml
LukeZurg22 Nov 21, 2025
a8bb5b7
Tuned Lattice Texture to be more Like a Lattice
LukeZurg22 Nov 21, 2025
9719a22
Added Eeble
LukeZurg22 Nov 21, 2025
c2f354a
Ported TC14 Rock Texture
LukeZurg22 Nov 21, 2025
79968ae
Fixed Eeble Sprite Size in meta.json
LukeZurg22 Nov 21, 2025
2d9f813
Beginning Complete and Utter Overhaul of Asteroids & Rocks
LukeZurg22 Nov 22, 2025
37d61eb
Iron & Wall Rock Checkpoints
LukeZurg22 Nov 22, 2025
435593d
Finalized New Asteroids
LukeZurg22 Nov 22, 2025
5ba73d7
Sorted Gas Canister Spray Painting
LukeZurg22 Nov 22, 2025
25e81fb
Removed Unneeded Sprite References in asteroid.yml
LukeZurg22 Nov 22, 2025
449feb3
Added More SprayPainterAmmo accessibility
LukeZurg22 Nov 22, 2025
fd42d6e
Ported Frontier Magic Spray Painter
LukeZurg22 Nov 22, 2025
ac47974
Fixing Linter Errors
LukeZurg22 Nov 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Content.Client/Atmos/EntitySystems/GasCanisterAppearanceSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.SprayPainter.Prototypes;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;

namespace Content.Client.Atmos.EntitySystems;

/// <summary>
/// Used to change the appearance of gas canisters.
/// </summary>
public sealed class GasCanisterAppearanceSystem : VisualizerSystem<GasCanisterComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;

protected override void OnAppearanceChange(EntityUid uid, GasCanisterComponent component, ref AppearanceChangeEvent args)
{
if (!AppearanceSystem.TryGetData<string>(uid,
PaintableVisuals.Prototype,
out var protoName,
args.Component) || args.Sprite is null)
return;

if (!_prototypeManager.HasIndex(protoName))
return;

// Create the given prototype and get its first layer.
var tempUid = Spawn(protoName);
SpriteSystem.LayerSetRsiState(uid, 0, SpriteSystem.LayerGetRsiState(tempUid, 0));
QueueDel(tempUid);
}
}
7 changes: 1 addition & 6 deletions Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.UserInterface;

Expand All @@ -14,9 +12,6 @@ namespace Content.Client.Atmos.UI;
[UsedImplicitly]
public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private const float MaxPressure = Atmospherics.MaxOutputPressure;

[ViewVariables]
private GasPressurePumpWindow? _window;

Expand Down
52 changes: 52 additions & 0 deletions Content.Client/Charges/ChargesSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Content.Client.Actions;
using Content.Shared.Actions;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;

namespace Content.Client.Charges;

public sealed class ChargesSystem : SharedChargesSystem
{
[Dependency] private readonly ActionsSystem _actions = default!;

private readonly Dictionary<EntityUid, int> _lastCharges = new();
private readonly Dictionary<EntityUid, int> _tempLastCharges = new();

public override void Update(float frameTime)
{
// Technically this should probably be in frameupdate but no one will ever notice a tick of delay on this.
base.Update(frameTime);

if (!_timing.IsFirstTimePredicted)
return;

// Update recharging actions. Server doesn't actually care about this and it's a waste of performance, actions are immediate.
var query = AllEntityQuery<AutoRechargeComponent, LimitedChargesComponent>();

while (query.MoveNext(out var uid, out var recharge, out var charges))
{
BaseActionComponent? actionComp = null;

if (!_actions.ResolveActionData(uid, ref actionComp, logError: false))
continue;

var current = GetCurrentCharges((uid, charges, recharge));

if (!_lastCharges.TryGetValue(uid, out var last) || current != last)
{
_actions.UpdateAction(uid, actionComp);
}

_tempLastCharges[uid] = current;
}

_lastCharges.Clear();

foreach (var (uid, value) in _tempLastCharges)
{
_lastCharges[uid] = value;
}

_tempLastCharges.Clear();
}
}
5 changes: 0 additions & 5 deletions Content.Client/Charges/Systems/ChargesSystem.cs

This file was deleted.

30 changes: 16 additions & 14 deletions Content.Client/Doors/DoorSystem.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.SprayPainter.Prototypes;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Prototypes;

namespace Content.Client.Doors;

public sealed class DoorSystem : SharedDoorSystem
{
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -84,8 +86,8 @@ private void OnAppearanceChange(Entity<DoorComponent> entity, ref AppearanceChan
if (!AppearanceSystem.TryGetData<DoorState>(entity, DoorVisuals.State, out var state, args.Component))
state = DoorState.Closed;

if (AppearanceSystem.TryGetData<string>(entity, DoorVisuals.BaseRSI, out var baseRsi, args.Component))
UpdateSpriteLayers(args.Sprite, baseRsi);
if (AppearanceSystem.TryGetData<string>(entity, PaintableVisuals.Prototype, out var prototype, args.Component))
UpdateSpriteLayers((entity.Owner, args.Sprite), prototype);

if (_animationSystem.HasRunningAnimation(entity, DoorComponent.AnimationKey))
_animationSystem.Stop(entity.Owner, DoorComponent.AnimationKey);
Expand All @@ -95,21 +97,21 @@ private void OnAppearanceChange(Entity<DoorComponent> entity, ref AppearanceChan

private void UpdateAppearanceForDoorState(Entity<DoorComponent> entity, SpriteComponent sprite, DoorState state)
{
sprite.DrawDepth = state is DoorState.Open ? entity.Comp.OpenDrawDepth : entity.Comp.ClosedDrawDepth;
_sprite.SetDrawDepth((entity.Owner, sprite), state is DoorState.Open ? entity.Comp.OpenDrawDepth : entity.Comp.ClosedDrawDepth);

switch (state)
{
case DoorState.Open:
foreach (var (layer, layerState) in entity.Comp.OpenSpriteStates)
{
sprite.LayerSetState(layer, layerState);
_sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
}

return;
case DoorState.Closed:
foreach (var (layer, layerState) in entity.Comp.ClosedSpriteStates)
{
sprite.LayerSetState(layer, layerState);
_sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
}

return;
Expand Down Expand Up @@ -138,14 +140,14 @@ private void UpdateAppearanceForDoorState(Entity<DoorComponent> entity, SpriteCo
}
}

private void UpdateSpriteLayers(SpriteComponent sprite, string baseRsi)
private void UpdateSpriteLayers(Entity<SpriteComponent> sprite, string targetProto)
{
if (!_resourceCache.TryGetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / baseRsi, out var res))
{
Log.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace);
if (!_prototypeManager.TryIndex(targetProto, out var target))
return;

if (!target.TryGetComponent(out SpriteComponent? targetSprite, _componentFactory))
return;
}

sprite.BaseRSI = res.RSI;
_sprite.SetBaseRsi(sprite.AsNullable(), targetSprite.BaseRSI);
}
}
2 changes: 2 additions & 0 deletions Content.Client/IconSmoothing/IconSmoothComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Robust.Client.Graphics;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

// ReSharper disable InconsistentNaming

namespace Content.Client.IconSmoothing
{
/// <summary>
Expand Down
139 changes: 106 additions & 33 deletions Content.Client/SprayPainter/SprayPainterSystem.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,129 @@
using System.Linq;
using Content.Client.Items;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Decals;
using Content.Shared.SprayPainter;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Content.Shared.SprayPainter.Components;
using Content.Shared.SprayPainter.Prototypes;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using System.Linq;
using Robust.Shared.Graphics;

namespace Content.Client.SprayPainter;

/// <summary>
/// Client-side spray painter functions. Caches information for spray painter windows and updates the UI to reflect component state.
/// </summary>
public sealed class SprayPainterSystem : SharedSprayPainterSystem
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;

public List<SprayPainterDecalEntry> Decals = [];
public Dictionary<string, List<string>> PaintableGroupsByCategory = new();
public Dictionary<string, Dictionary<string, EntProtoId>> PaintableStylesByGroup = new();

public override void Initialize()
{
base.Initialize();

public List<SprayPainterEntry> Entries { get; private set; } = new();
Subs.ItemStatus<SprayPainterComponent>(ent => new StatusControl(ent));
SubscribeLocalEvent<SprayPainterComponent, AfterAutoHandleStateEvent>(OnStateUpdate);
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);

protected override void CacheStyles()
CachePrototypes();
}

private void OnStateUpdate(Entity<SprayPainterComponent> ent, ref AfterAutoHandleStateEvent args)
{
base.CacheStyles();
UpdateUi(ent);
}

Entries.Clear();
foreach (var style in Styles)
protected override void UpdateUi(Entity<SprayPainterComponent> ent)
{
if (_ui.TryGetOpenUi(ent.Owner, SprayPainterUiKey.Key, out var bui))
bui.Update();
}

private void OnPrototypesReloaded(PrototypesReloadedEventArgs args)
{
if (!args.WasModified<PaintableGroupCategoryPrototype>() || !args.WasModified<PaintableGroupPrototype>() || !args.WasModified<DecalPrototype>())
return;

CachePrototypes();
}

private void CachePrototypes()
{
PaintableGroupsByCategory.Clear();
PaintableStylesByGroup.Clear();
foreach (var category in Proto.EnumeratePrototypes<PaintableGroupCategoryPrototype>().OrderBy(x => x.ID))
{
var name = style.Name;
string? iconPath = Groups
.FindAll(x => x.StylePaths.ContainsKey(name))?
.MaxBy(x => x.IconPriority)?.StylePaths[name];
if (iconPath == null)
var groupList = new List<string>();
foreach (var groupId in category.Groups)
{
Entries.Add(new SprayPainterEntry(name, null));
continue;
if (!Proto.TryIndex(groupId, out var group))
continue;

groupList.Add(groupId);
PaintableStylesByGroup[groupId] = group.Styles;
}

RSIResource doorRsi = _resourceCache.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / new ResPath(iconPath));
if (!doorRsi.RSI.TryGetState("closed", out var icon))
{
Entries.Add(new SprayPainterEntry(name, null));
if (groupList.Count > 0)
PaintableGroupsByCategory[category.ID] = groupList;
}

Decals.Clear();
foreach (var decalPrototype in Proto.EnumeratePrototypes<DecalPrototype>().OrderBy(x => x.ID))
{
if (!decalPrototype.Tags.Contains("station")
&& !decalPrototype.Tags.Contains("markings")
|| decalPrototype.Tags.Contains("dirty"))
continue;
}

Entries.Add(new SprayPainterEntry(name, icon.Frame0));
Decals.Add(new SprayPainterDecalEntry(decalPrototype.ID, decalPrototype.Sprite));
}
}
}

public sealed class SprayPainterEntry
{
public string Name;
public Texture? Icon;

public SprayPainterEntry(string name, Texture? icon)
private sealed class StatusControl : Control
{
Name = name;
Icon = icon;
private readonly RichTextLabel _label;
private readonly Entity<SprayPainterComponent> _entity;
private DecalPaintMode? _lastPaintingDecals = null;

public StatusControl(Entity<SprayPainterComponent> ent)
{
_entity = ent;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
}

protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);

if (_entity.Comp.DecalMode == _lastPaintingDecals)
return;

_lastPaintingDecals = _entity.Comp.DecalMode;

string modeLocString = _entity.Comp.DecalMode switch
{
DecalPaintMode.Add => "spray-painter-item-status-add",
DecalPaintMode.Remove => "spray-painter-item-status-remove",
_ => "spray-painter-item-status-off"
};

_label.SetMarkupPermissive(Robust.Shared.Localization.Loc.GetString("spray-painter-item-status-label",
("mode", Robust.Shared.Localization.Loc.GetString(modeLocString))));
}
}
}

/// <summary>
/// A spray paintable decal, mapped by ID.
/// </summary>
public sealed record SprayPainterDecalEntry(string Name, SpriteSpecifier Sprite);
Loading
Loading