Spray Paint (Review Ready) (#23003)
* Spray Paint (Draft) * paint colors, paints in maints loot, cargo crate of paints. * fix * remove paint (sort of) * moved paintcleaner into own system * Moved paint to server (had to unfortunately) * doafter now breaks when moving away. * cant paint mobstatecomp * loads of fixes * fixes * fixes * nopaintshadercomp * fixes * fix * use locale for paint remove string * remove nopaintshadercomponent and use blacklist * remove enabled.true from visualizer * paint doafter event. * add verbs for paint and remove paint and icon for paint verb. * fixes * no longer replaces shader when shader exists. * replace forloop with foreach, check shader before adding and removing. * paint doafter now separate so no copy paste code * Entities in sprayed targets item slots are also now correctly sprayed. * fix * fix * fix airlock psray painter now removes painted before painting door. * spray paints now use openablecomponent. * fix * fix damn accesstypes. * fix * fix
120
Content.Client/Paint/PaintVisualizerSystem.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using static Robust.Client.GameObjects.SpriteComponent;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.Hands;
|
||||||
|
using Content.Shared.Paint;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Paint
|
||||||
|
{
|
||||||
|
public sealed class PaintedVisualizerSystem : VisualizerSystem<PaintedComponent>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Visualizer for Paint which applies a shader and colors the entity.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
|
|
||||||
|
public ShaderInstance? Shader; // in Robust.Client.Graphics so cannot move to shared component.
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PaintedComponent, HeldVisualsUpdatedEvent>(OnHeldVisualsUpdated);
|
||||||
|
SubscribeLocalEvent<PaintedComponent, ComponentShutdown>(OnShutdown);
|
||||||
|
SubscribeLocalEvent<PaintedComponent, EquipmentVisualsUpdatedEvent>(OnEquipmentVisualsUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAppearanceChange(EntityUid uid, PaintedComponent component, ref AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
// ShaderPrototype sadly in Robust.Client, cannot move to shared component.
|
||||||
|
Shader = _protoMan.Index<ShaderPrototype>(component.ShaderName).Instance();
|
||||||
|
|
||||||
|
if (args.Sprite == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_appearance.TryGetData<bool>(uid, PaintVisuals.Painted, out bool isPainted))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sprite = args.Sprite;
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var spriteLayer in sprite.AllLayers)
|
||||||
|
{
|
||||||
|
if (spriteLayer is not Layer layer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (layer.Shader == null) // If shader isn't null we dont want to replace the original shader.
|
||||||
|
{
|
||||||
|
layer.Shader = Shader;
|
||||||
|
layer.Color = component.Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHeldVisualsUpdated(EntityUid uid, PaintedComponent component, HeldVisualsUpdatedEvent args)
|
||||||
|
{
|
||||||
|
if (args.RevealedLayers.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp(args.User, out SpriteComponent? sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var revealed in args.RevealedLayers)
|
||||||
|
{
|
||||||
|
if (!sprite.LayerMapTryGet(revealed, out var layer) || sprite[layer] is not Layer notlayer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sprite.LayerSetShader(layer, component.ShaderName);
|
||||||
|
sprite.LayerSetColor(layer, component.Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEquipmentVisualsUpdated(EntityUid uid, PaintedComponent component, EquipmentVisualsUpdatedEvent args)
|
||||||
|
{
|
||||||
|
if (args.RevealedLayers.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp(args.Equipee, out SpriteComponent? sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var revealed in args.RevealedLayers)
|
||||||
|
{
|
||||||
|
if (!sprite.LayerMapTryGet(revealed, out var layer) || sprite[layer] is not Layer notlayer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sprite.LayerSetShader(layer, component.ShaderName);
|
||||||
|
sprite.LayerSetColor(layer, component.Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShutdown(EntityUid uid, PaintedComponent component, ref ComponentShutdown args)
|
||||||
|
{
|
||||||
|
if (!TryComp(uid, out SpriteComponent? sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.BeforeColor = sprite.Color;
|
||||||
|
Shader = _protoMan.Index<ShaderPrototype>(component.ShaderName).Instance();
|
||||||
|
|
||||||
|
if (!Terminating(uid))
|
||||||
|
{
|
||||||
|
foreach (var spriteLayer in sprite.AllLayers)
|
||||||
|
{
|
||||||
|
if (spriteLayer is not Layer layer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (layer.Shader == Shader) // If shader isn't same as one in component we need to ignore it.
|
||||||
|
{
|
||||||
|
layer.Shader = null;
|
||||||
|
if (layer.Color == component.Color) // If color isn't the same as one in component we don't want to change it.
|
||||||
|
layer.Color = component.BeforeColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
180
Content.Server/Paint/PaintSystem.cs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Paint;
|
||||||
|
using Content.Shared.Sprite;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Content.Shared.SubFloor;
|
||||||
|
using Content.Server.Nutrition.Components;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
|
||||||
|
namespace Content.Server.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Colors target and consumes reagent on each color success.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PaintSystem : SharedPaintSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
|
[Dependency] private readonly OpenableSystem _openable = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PaintComponent, AfterInteractEvent>(OnInteract);
|
||||||
|
SubscribeLocalEvent<PaintComponent, PaintDoAfterEvent>(OnPaint);
|
||||||
|
SubscribeLocalEvent<PaintComponent, GetVerbsEvent<UtilityVerb>>(OnPaintVerb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteract(EntityUid uid, PaintComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (!args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Target is not { Valid: true } target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PrepPaint(uid, component, target, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPaintVerb(EntityUid uid, PaintComponent component, GetVerbsEvent<UtilityVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanInteract || !args.CanAccess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var paintText = Loc.GetString("paint-verb");
|
||||||
|
|
||||||
|
var verb = new UtilityVerb()
|
||||||
|
{
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
PrepPaint(uid, component, args.Target, args.User);
|
||||||
|
},
|
||||||
|
|
||||||
|
Text = paintText,
|
||||||
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/paint.svg.192dpi.png"))
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
private void PrepPaint(EntityUid uid, PaintComponent component, EntityUid target, EntityUid user)
|
||||||
|
{
|
||||||
|
|
||||||
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, user, component.Delay, new PaintDoAfterEvent(), uid, target: target, used: uid)
|
||||||
|
{
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnDamage = true,
|
||||||
|
NeedHand = true,
|
||||||
|
BreakOnHandChange = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_doAfterSystem.TryStartDoAfter(doAfterEventArgs))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPaint(Entity<PaintComponent> entity, ref PaintDoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Target == null || args.Used == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Handled || args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Target is not { Valid: true } target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_openable.IsOpen(entity))
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("paint-closed", ("used", args.Used)), args.User, args.User, PopupType.Medium);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasComp<PaintedComponent>(target) || HasComp<RandomSpriteComponent>(target))
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("paint-failure-painted", ("target", args.Target)), args.User, args.User, PopupType.Medium);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity.Comp.Blacklist?.IsValid(target, EntityManager) != true || HasComp<HumanoidAppearanceComponent>(target) || HasComp<SubFloorHideComponent>(target))
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("paint-failure", ("target", args.Target)), args.User, args.User, PopupType.Medium);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (TryPaint(entity, target))
|
||||||
|
{
|
||||||
|
EnsureComp<PaintedComponent>(target, out PaintedComponent? paint);
|
||||||
|
EnsureComp<AppearanceComponent>(target);
|
||||||
|
|
||||||
|
paint.Color = entity.Comp.Color; // set the target color to the color specified in the spray paint yml.
|
||||||
|
_audio.PlayPvs(entity.Comp.Spray, entity);
|
||||||
|
paint.Enabled = true;
|
||||||
|
|
||||||
|
if (HasComp<InventoryComponent>(target)) // Paint any clothing the target is wearing.
|
||||||
|
{
|
||||||
|
if (_inventory.TryGetSlots(target, out var slotDefinitions))
|
||||||
|
{
|
||||||
|
foreach (var slot in slotDefinitions)
|
||||||
|
{
|
||||||
|
if (!_inventory.TryGetSlotEntity(target, slot.Name, out var slotEnt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (slotEnt == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HasComp<PaintedComponent>(slotEnt.Value) || !entity.Comp.Blacklist?.IsValid(slotEnt.Value, EntityManager) != true
|
||||||
|
|| HasComp<RandomSpriteComponent>(slotEnt.Value) || HasComp<HumanoidAppearanceComponent>(slotEnt.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
EnsureComp<PaintedComponent>(slotEnt.Value, out PaintedComponent? slotpaint);
|
||||||
|
EnsureComp<AppearanceComponent>(slotEnt.Value);
|
||||||
|
slotpaint.Color = entity.Comp.Color;
|
||||||
|
_appearanceSystem.SetData(slotEnt.Value, PaintVisuals.Painted, true);
|
||||||
|
Dirty(slotEnt.Value, slotpaint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_popup.PopupEntity(Loc.GetString("paint-success", ("target", args.Target)), args.User, args.User, PopupType.Medium);
|
||||||
|
_appearanceSystem.SetData(target, PaintVisuals.Painted, true);
|
||||||
|
Dirty(target, paint);
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryPaint(entity, target))
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("paint-empty", ("used", args.Used)), args.User, args.User, PopupType.Medium);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryPaint(Entity<PaintComponent> reagent, EntityUid target)
|
||||||
|
{
|
||||||
|
if (HasComp<HumanoidAppearanceComponent>(target) || HasComp<SubFloorHideComponent>(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_solutionContainer.TryGetSolution(reagent.Owner, reagent.Comp.Solution, out _, out var solution))
|
||||||
|
{
|
||||||
|
var quantity = solution.RemoveReagent(reagent.Comp.Reagent, reagent.Comp.ConsumptionUnit);
|
||||||
|
if (quantity > 0)// checks quantity of solution is more than 0.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (quantity < 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,11 +80,6 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
_adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(args.User)} used {ToPrettyString(uid)} which spawned {ToPrettyString(entityToPlaceInHands.Value)}");
|
_adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(args.User)} used {ToPrettyString(uid)} which spawned {ToPrettyString(entityToPlaceInHands.Value)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.Sound != null)
|
|
||||||
{
|
|
||||||
_audio.PlayPvs(component.Sound, uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
component.Uses--;
|
component.Uses--;
|
||||||
|
|
||||||
// Delete entity only if component was successfully used
|
// Delete entity only if component was successfully used
|
||||||
@@ -97,6 +92,7 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
if (entityToPlaceInHands != null)
|
if (entityToPlaceInHands != null)
|
||||||
{
|
{
|
||||||
_hands.PickupOrDrop(args.User, entityToPlaceInHands.Value);
|
_hands.PickupOrDrop(args.User, entityToPlaceInHands.Value);
|
||||||
|
_audio.PlayPvs(component.Sound, entityToPlaceInHands.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
60
Content.Shared/Paint/PaintComponent.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Entity when used on another entity will paint target entity.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(SharedPaintSystem))]
|
||||||
|
public sealed partial class PaintComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Noise made when paint applied.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public SoundSpecifier Spray = new SoundPathSpecifier("/Audio/Effects/spray2.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Solution on the entity that contains the paint.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string Solution = "drink";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long the doafter will take.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public int Delay = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reagent that will be used as paint.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public ProtoId<ReagentPrototype> Reagent = "SpaceGlue";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Color that the painting entity will instruct the painted entity to be.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Color Color = Color.FromHex("#c62121");
|
||||||
|
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public EntityWhitelist? Blacklist;
|
||||||
|
/// <summary>
|
||||||
|
/// Reagent consumption per use.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public FixedPoint2 ConsumptionUnit = FixedPoint2.New(5);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Duration per unit
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan DurationPerUnit = TimeSpan.FromSeconds(6);
|
||||||
|
}
|
||||||
9
Content.Shared/Paint/PaintDoAfterEvent.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class PaintDoAfterEvent : SimpleDoAfterEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
24
Content.Shared/Paint/PaintRemoverComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes paint from an entity that was painted with spray paint.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[Access(typeof(PaintRemoverSystem))]
|
||||||
|
public sealed partial class PaintRemoverComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sound when target is cleaned.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Effects/Fluids/watersplash.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DoAfter wait time.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public float CleanDelay = 2f;
|
||||||
|
}
|
||||||
9
Content.Shared/Paint/PaintRemoverDoAfterEvent.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class PaintRemoverDoAfterEvent : SimpleDoAfterEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
96
Content.Shared/Paint/PaintRemoverSystem.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Content.Shared.Sprite;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes paint from an entity.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PaintRemoverSystem : SharedPaintSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PaintRemoverComponent, AfterInteractEvent>(OnInteract);
|
||||||
|
SubscribeLocalEvent<PaintRemoverComponent, PaintRemoverDoAfterEvent>(OnDoAfter);
|
||||||
|
SubscribeLocalEvent<PaintRemoverComponent, GetVerbsEvent<UtilityVerb>>(OnPaintRemoveVerb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When entity is painted, remove paint from that entity.
|
||||||
|
private void OnInteract(EntityUid uid, PaintRemoverComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!args.CanReach || args.Target is not { Valid: true } target || !HasComp<PaintedComponent>(target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.CleanDelay, new PaintRemoverDoAfterEvent(), uid, args.Target, uid)
|
||||||
|
{
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
MovementThreshold = 1.0f,
|
||||||
|
});
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoAfter(EntityUid uid, PaintRemoverComponent component, DoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Cancelled || args.Handled || args.Args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Target is not { Valid: true } target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp(target, out PaintedComponent? paint))
|
||||||
|
return;
|
||||||
|
|
||||||
|
paint.Enabled = false;
|
||||||
|
_audio.PlayPredicted(component.Sound, target, args.User);
|
||||||
|
_popup.PopupClient(Loc.GetString("paint-removed", ("target", target)), args.User, args.User, PopupType.Medium);
|
||||||
|
_appearanceSystem.SetData(target, PaintVisuals.Painted, false);
|
||||||
|
RemComp<PaintedComponent>(target);
|
||||||
|
Dirty(target, paint);
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPaintRemoveVerb(EntityUid uid, PaintRemoverComponent component, GetVerbsEvent<UtilityVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanInteract || !args.CanAccess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var paintremovalText = Loc.GetString("paint-remove-verb");
|
||||||
|
|
||||||
|
var verb = new UtilityVerb()
|
||||||
|
{
|
||||||
|
Act = () => {
|
||||||
|
|
||||||
|
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.CleanDelay, new PaintRemoverDoAfterEvent(), uid, args.Target, uid)
|
||||||
|
{
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
MovementThreshold = 1.0f,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
Text = paintremovalText
|
||||||
|
};
|
||||||
|
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Content.Shared/Paint/PaintedComponent.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component applied to target entity when painted.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class PaintedComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Color of the paint.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Color Color = Color.FromHex("#2cdbd5");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to remove the color when component removed.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Color BeforeColor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If paint is enabled.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool Enabled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the shader.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public string ShaderName = "Greyscale";
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PaintVisuals : byte
|
||||||
|
{
|
||||||
|
Painted,
|
||||||
|
}
|
||||||
11
Content.Shared/Paint/SharedPaintSystem.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Content.Shared.Paint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Colors target and consumes reagent on each color success.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class SharedPaintSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public virtual void UpdateAppearance(EntityUid uid, PaintedComponent? component = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using Content.Shared.DoAfter;
|
|||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Paint;
|
||||||
using Content.Shared.SprayPainter.Components;
|
using Content.Shared.SprayPainter.Components;
|
||||||
using Content.Shared.SprayPainter.Prototypes;
|
using Content.Shared.SprayPainter.Prototypes;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
@@ -129,6 +130,8 @@ public abstract class SharedSprayPainterSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemComp<PaintedComponent>(ent);
|
||||||
|
|
||||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, painter.AirlockSprayTime, new SprayPainterDoorDoAfterEvent(sprite, style.Department), args.Used, target: ent, used: args.Used)
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, painter.AirlockSprayTime, new SprayPainterDoorDoAfterEvent(sprite, style.Department), args.Used, target: ent, used: args.Used)
|
||||||
{
|
{
|
||||||
BreakOnTargetMove = true,
|
BreakOnTargetMove = true,
|
||||||
|
|||||||
8
Resources/Locale/en-US/paint/paint.ftl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
paint-success = {THE($target)} has been covered in paint!
|
||||||
|
paint-failure = Can't cover {THE($target)} in paint!
|
||||||
|
paint-failure-painted = {THE($target)} is already covered in paint!
|
||||||
|
paint-empty = {THE($used)} is empty!
|
||||||
|
paint-removed = You clean off the paint!
|
||||||
|
paint-closed = You must open {THE($used)} first!
|
||||||
|
paint-verb = Paint
|
||||||
|
paint-remove-verb = Remove Paint
|
||||||
@@ -68,6 +68,16 @@
|
|||||||
category: cargoproduct-category-name-fun
|
category: cargoproduct-category-name-fun
|
||||||
group: market
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: FunSprayPaints
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
state: death2_cap
|
||||||
|
product: CrateFunSprayPaints
|
||||||
|
cost: 2000
|
||||||
|
category: Fun
|
||||||
|
group: market
|
||||||
|
|
||||||
- type: cargoProduct
|
- type: cargoProduct
|
||||||
id: FunParty
|
id: FunParty
|
||||||
icon:
|
icon:
|
||||||
|
|||||||
@@ -290,14 +290,21 @@
|
|||||||
contents:
|
contents:
|
||||||
- id: SnapPopBox
|
- id: SnapPopBox
|
||||||
- id: CrazyGlue
|
- id: CrazyGlue
|
||||||
amount: 2
|
|
||||||
- id: PlasticBanana
|
- id: PlasticBanana
|
||||||
|
- id: FunnyPaint
|
||||||
|
orGroup: Paint
|
||||||
|
prob: 0.5
|
||||||
|
- id: FunnyPaintYellow
|
||||||
|
orGroup: Paint
|
||||||
|
prob: 0.5
|
||||||
- id: WhoopieCushion
|
- id: WhoopieCushion
|
||||||
- id: ToyHammer
|
- id: ToyHammer
|
||||||
- id: MrChips
|
- id: MrChips
|
||||||
orGroup: GiftPool
|
prob: 0.5
|
||||||
|
orGroup: Dummy
|
||||||
- id: MrDips
|
- id: MrDips
|
||||||
orGroup: Giftpool
|
prob: 0.5
|
||||||
|
orGroup: Dummy
|
||||||
- id: RevolverCapGun
|
- id: RevolverCapGun
|
||||||
- id: BalloonNT
|
- id: BalloonNT
|
||||||
- id: ClothingShoesClownLarge
|
- id: ClothingShoesClownLarge
|
||||||
@@ -330,6 +337,41 @@
|
|||||||
amount: 15
|
amount: 15
|
||||||
prob: 0.05
|
prob: 0.05
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateFunSprayPaints
|
||||||
|
name: spray paint crate
|
||||||
|
description: a crate filled with spray paint.
|
||||||
|
parent: CratePlastic
|
||||||
|
suffix: Spray Paint
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: SprayPaintBlue
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintRed
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintOrange
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintBlack
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintGreen
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintPurple
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: SprayPaintWhite
|
||||||
|
amount: 2
|
||||||
|
prob: 0.33
|
||||||
|
- id: DeathPaint
|
||||||
|
amount: 2
|
||||||
|
- id: DeathPaintTwo
|
||||||
|
amount: 2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: dartboard box set
|
name: dartboard box set
|
||||||
description: A box with everything you need for a fun game of darts.
|
description: A box with everything you need for a fun game of darts.
|
||||||
|
|||||||
@@ -145,6 +145,10 @@
|
|||||||
prob: 0.25
|
prob: 0.25
|
||||||
- id: StrangePill
|
- id: StrangePill
|
||||||
prob: 0.20
|
prob: 0.20
|
||||||
|
- id: DeathPaint
|
||||||
|
prob: 0.05
|
||||||
|
- id: DeathPaintTwo
|
||||||
|
prob: 0.05
|
||||||
- id: DrinkMopwataBottleRandom
|
- id: DrinkMopwataBottleRandom
|
||||||
prob: 0.20
|
prob: 0.20
|
||||||
- id: ModularReceiver
|
- id: ModularReceiver
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
- CrateMaterialPlastic
|
- CrateMaterialPlastic
|
||||||
- CrateMaterialWood
|
- CrateMaterialWood
|
||||||
- CrateMaterialPlasteel
|
- CrateMaterialPlasteel
|
||||||
|
- CrateFunSprayPaints
|
||||||
- CrateFunArtSupplies
|
- CrateFunArtSupplies
|
||||||
- CrateEngineeringCableLV
|
- CrateEngineeringCableLV
|
||||||
- CrateEngineeringCableMV
|
- CrateEngineeringCableMV
|
||||||
|
|||||||
@@ -173,7 +173,12 @@
|
|||||||
- MaterialCloth10
|
- MaterialCloth10
|
||||||
- MaterialWoodPlank10
|
- MaterialWoodPlank10
|
||||||
- ResearchDisk
|
- ResearchDisk
|
||||||
|
- DeathPaint
|
||||||
- Plunger
|
- Plunger
|
||||||
|
- SprayPaintBlue
|
||||||
|
- SprayPaintRed
|
||||||
|
- SprayPaintGreen
|
||||||
|
- SprayPaintOrange
|
||||||
- TechnologyDisk
|
- TechnologyDisk
|
||||||
- PowerCellMedium
|
- PowerCellMedium
|
||||||
- PowerCellSmall
|
- PowerCellSmall
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
tags:
|
tags:
|
||||||
- Carp
|
- Carp
|
||||||
- DoorBumpOpener
|
- DoorBumpOpener
|
||||||
|
- NoPaint
|
||||||
- type: ReplacementAccent
|
- type: ReplacementAccent
|
||||||
accent: genericAggressive
|
accent: genericAggressive
|
||||||
- type: Speech
|
- type: Speech
|
||||||
|
|||||||
@@ -93,3 +93,6 @@
|
|||||||
- RevenantTheme
|
- RevenantTheme
|
||||||
- type: Speech
|
- type: Speech
|
||||||
speechVerb: Ghost
|
speechVerb: Ghost
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
|
|||||||
@@ -104,6 +104,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- CannotSuicide
|
- CannotSuicide
|
||||||
|
- NoPaint
|
||||||
|
|
||||||
# From the uplink injector
|
# From the uplink injector
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -212,6 +213,7 @@
|
|||||||
tags:
|
tags:
|
||||||
- CannotSuicide
|
- CannotSuicide
|
||||||
- FootstepSound
|
- FootstepSound
|
||||||
|
- NoPaint
|
||||||
- type: Inventory
|
- type: Inventory
|
||||||
templateId: holoclown
|
templateId: holoclown
|
||||||
- type: Hands
|
- type: Hands
|
||||||
|
|||||||
292
Resources/Prototypes/Entities/Objects/Fun/spray_paint.yml
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
# Base Paints
|
||||||
|
- type: entity
|
||||||
|
parent: BaseItem
|
||||||
|
id: PaintBase
|
||||||
|
name: spray paint
|
||||||
|
description: A tin of spray paint.
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: Appearance
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
state: clown_cap
|
||||||
|
layers:
|
||||||
|
- state: clown_cap
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
- type: Paint
|
||||||
|
consumptionUnit: 10
|
||||||
|
blacklist:
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
heldPrefix: spray
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 50
|
||||||
|
reagents:
|
||||||
|
- ReagentId: SpaceGlue
|
||||||
|
Quantity: 50
|
||||||
|
- type: TrashOnSolutionEmpty
|
||||||
|
solution: drink
|
||||||
|
- type: Sealable
|
||||||
|
- type: Openable
|
||||||
|
sound:
|
||||||
|
path: /Audio/Effects/pop_high.ogg
|
||||||
|
closeable: true
|
||||||
|
closeSound:
|
||||||
|
path: /Audio/Effects/pop_high.ogg
|
||||||
|
|
||||||
|
# Paints
|
||||||
|
|
||||||
|
# funnypaint
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: FunnyPaint
|
||||||
|
name: funny paint
|
||||||
|
description: A tin of funny paint, manufactured by Honk! Co.
|
||||||
|
components:
|
||||||
|
- type: Paint
|
||||||
|
color: "#fa74df"
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
heldPrefix: clown
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "clown"}
|
||||||
|
False: {state: "clown_cap"}
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: FunnyPaintYellow
|
||||||
|
name: funny paint
|
||||||
|
description: A tin of funny paint, manufactured by Honk! Co.
|
||||||
|
components:
|
||||||
|
- type: Paint
|
||||||
|
color: "#d5e028"
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
heldPrefix: clown
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
state: clown2_cap
|
||||||
|
layers:
|
||||||
|
- state: clown2_cap
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "clown2"}
|
||||||
|
False: {state: "clown2_cap"}
|
||||||
|
|
||||||
|
#death paint
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: DeathPaint
|
||||||
|
components:
|
||||||
|
- type: Paint
|
||||||
|
color: "#ff20c8"
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
heldPrefix: spray
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
state: death_cap
|
||||||
|
layers:
|
||||||
|
- state: death_cap
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "death"}
|
||||||
|
False: {state: "death_cap"}
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: DeathPaintTwo
|
||||||
|
components:
|
||||||
|
- type: Paint
|
||||||
|
color: "#ff2020"
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
heldPrefix: spray
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
state: death2_cap
|
||||||
|
layers:
|
||||||
|
- state: death2_cap
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "death2"}
|
||||||
|
False: {state: "death2_cap"}
|
||||||
|
|
||||||
|
#Sprays
|
||||||
|
|
||||||
|
#Blue
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintBlue
|
||||||
|
suffix: Blue
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#5890f7"
|
||||||
|
- type: Paint
|
||||||
|
color: "#5890f7"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#5890f7"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#5890f7"}
|
||||||
|
|
||||||
|
#Red
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintRed
|
||||||
|
suffix: Red
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#ff3b3b"
|
||||||
|
- type: Paint
|
||||||
|
color: "#ff3b3b"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#ff3b3b"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#ff3b3b"}
|
||||||
|
|
||||||
|
#Green
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintGreen
|
||||||
|
suffix: Green
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#73f170"
|
||||||
|
- type: Paint
|
||||||
|
color: "#73f170"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#73f170"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#73f170"}
|
||||||
|
|
||||||
|
#Black
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintBlack
|
||||||
|
suffix: Black
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#3a3a3a"
|
||||||
|
- type: Paint
|
||||||
|
color: "#3a3a3a"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#3a3a3a"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#3a3a3a"}
|
||||||
|
|
||||||
|
#Orange
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintOrange
|
||||||
|
suffix: Orange
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#f6a44b"
|
||||||
|
- type: Paint
|
||||||
|
color: "#f6a44b"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#f6a44b"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#f6a44b"}
|
||||||
|
|
||||||
|
#Purple
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintPurple
|
||||||
|
suffix: Purple
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#c063f5"
|
||||||
|
- type: Paint
|
||||||
|
color: "#c063f5"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#c063f5"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#c063f5"}
|
||||||
|
|
||||||
|
#White
|
||||||
|
- type: entity
|
||||||
|
parent: PaintBase
|
||||||
|
id: SprayPaintWhite
|
||||||
|
suffix: White
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Fun/spraycans.rsi
|
||||||
|
layers:
|
||||||
|
- state: spray
|
||||||
|
map: ["Base"]
|
||||||
|
- state: spray_cap_colors
|
||||||
|
map: ["enum.OpenableVisuals.Layer"]
|
||||||
|
color: "#f2f2f2"
|
||||||
|
- type: Paint
|
||||||
|
color: "#f2f2f2"
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.OpenableVisuals.Opened:
|
||||||
|
enum.OpenableVisuals.Layer:
|
||||||
|
True: {state: "spray_colors" , color: "#f2f2f2"}
|
||||||
|
False: {state: "spray_cap_colors" , color: "#f2f2f2"}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Sheet
|
- Sheet
|
||||||
|
- NoPaint
|
||||||
- type: Material
|
- type: Material
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
tags:
|
tags:
|
||||||
- Sheet
|
- Sheet
|
||||||
- Metal
|
- Metal
|
||||||
|
- NoPaint
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Metallic
|
damageModifierSet: Metallic
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Sheet
|
- Sheet
|
||||||
|
- NoPaint
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
@@ -110,6 +111,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Sheet
|
- Sheet
|
||||||
|
- NoPaint
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: SheetPlasma
|
parent: SheetPlasma
|
||||||
@@ -132,6 +134,7 @@
|
|||||||
tags:
|
tags:
|
||||||
- Plastic
|
- Plastic
|
||||||
- Sheet
|
- Sheet
|
||||||
|
- NoPaint
|
||||||
- type: Material
|
- type: Material
|
||||||
- type: PhysicalComposition
|
- type: PhysicalComposition
|
||||||
materialComposition:
|
materialComposition:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- RawMaterial
|
- RawMaterial
|
||||||
|
- NoPaint
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
Blunt: 5
|
Blunt: 5
|
||||||
- type: Stack
|
- type: Stack
|
||||||
count: 1
|
count: 1
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
solution: soap
|
solution: soap
|
||||||
- type: DeleteOnSolutionEmpty
|
- type: DeleteOnSolutionEmpty
|
||||||
solution: soap
|
solution: soap
|
||||||
|
- type: PaintRemover
|
||||||
- type: FlavorProfile
|
- type: FlavorProfile
|
||||||
flavors:
|
flavors:
|
||||||
- clean
|
- clean
|
||||||
|
|||||||
@@ -78,6 +78,9 @@
|
|||||||
malus: 0
|
malus: 0
|
||||||
- type: Reflect
|
- type: Reflect
|
||||||
enabled: false
|
enabled: false
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
- type: IgnitionSource
|
- type: IgnitionSource
|
||||||
temperature: 700
|
temperature: 700
|
||||||
|
|
||||||
@@ -156,6 +159,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Write
|
- Write
|
||||||
|
- NoPaint
|
||||||
- type: DisarmMalus
|
- type: DisarmMalus
|
||||||
malus: 0
|
malus: 0
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
sound:
|
sound:
|
||||||
path: /Audio/Ambience/Objects/fireplace.ogg
|
path: /Audio/Ambience/Objects/fireplace.ogg
|
||||||
- type: AlwaysHot
|
- type: AlwaysHot
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: LegionnaireBonfire
|
id: LegionnaireBonfire
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
behaviors:
|
behaviors:
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: HoloFan
|
id: HoloFan
|
||||||
|
|||||||
@@ -92,6 +92,9 @@
|
|||||||
- type: GuideHelp
|
- type: GuideHelp
|
||||||
guides:
|
guides:
|
||||||
- Botany
|
- Botany
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- NoPaint
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: hydroponicsTray
|
parent: hydroponicsTray
|
||||||
|
|||||||
@@ -908,6 +908,9 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
id: NoBlockAnchoring
|
id: NoBlockAnchoring
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: NoPaint
|
||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: NozzleBackTank
|
id: NozzleBackTank
|
||||||
|
|
||||||
|
|||||||
39
Resources/Textures/Interface/VerbIcons/paint.svg
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
version="1.1"
|
||||||
|
id="svg834"
|
||||||
|
sodipodi:docname="plus.svg"
|
||||||
|
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs838" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview836"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#eeeeee"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="33.666667"
|
||||||
|
inkscape:cx="11.985149"
|
||||||
|
inkscape:cy="7.2475248"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg834" />
|
||||||
|
<path
|
||||||
|
d="M 22.69307,10.252475 H 13.806931 V 1.3663366 H 10.252475 V 10.252475 H 1.3663366 v 3.554455 h 8.8861384 v 8.886139 h 3.554456 V 13.80693 h 8.886139 z"
|
||||||
|
id="path832"
|
||||||
|
inkscape:label="path832"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke-width:0.888614" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Resources/Textures/Interface/VerbIcons/paint.svg.192dpi.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
sample:
|
||||||
|
filter: true
|
||||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -58,9 +58,6 @@
|
|||||||
{
|
{
|
||||||
"name": "spray"
|
"name": "spray"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "spray_cap"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "spray_cap_colors"
|
"name": "spray_cap_colors"
|
||||||
},
|
},
|
||||||
@@ -70,6 +67,22 @@
|
|||||||
{
|
{
|
||||||
"name": "equipped-BELT",
|
"name": "equipped-BELT",
|
||||||
"directions": 4
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clown-inhand-right",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clown-inhand-left",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spray-inhand-right",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spray-inhand-left",
|
||||||
|
"directions": 4
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 246 B |