Make flashlights, atmos hardsuit, and RGB use the new layer features (#6253)

* Make flashlights, atmos hardsuit, and RGB use the new layer features

* avoid self-conflict

* fix rgb not updating on add

* cleanup

* Update Content.Client/Light/RgbLightControllerSystem.cs

Co-authored-by: mirrorcult <lunarautomaton6@gmail.com>

* cleanup diff

Co-authored-by: mirrorcult <lunarautomaton6@gmail.com>
This commit is contained in:
Leon Friedrich
2022-03-30 18:57:35 +13:00
committed by GitHub
parent 5c7a1534db
commit 4bc73ac591
43 changed files with 365 additions and 99 deletions

View File

@@ -1,4 +1,5 @@
using Content.Client.Items.Components; using Content.Client.Items.Components;
using Content.Shared.Hands.Components;
using Content.Shared.Light.Component; using Content.Shared.Light.Component;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
@@ -6,9 +7,11 @@ using Robust.Client.UserInterface.Controls;
using Robust.Shared.Analyzers; using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.ViewVariables; using System.Collections.Generic;
using static Robust.Client.UserInterface.Controls.BoxContainer; using static Robust.Client.UserInterface.Controls.BoxContainer;
using static Robust.Shared.GameObjects.SharedSpriteComponent;
namespace Content.Client.Light.Components namespace Content.Client.Light.Components
{ {
@@ -17,6 +20,37 @@ namespace Content.Client.Light.Components
public sealed class HandheldLightComponent : SharedHandheldLightComponent, IItemStatus public sealed class HandheldLightComponent : SharedHandheldLightComponent, IItemStatus
{ {
public byte? Level; public byte? Level;
public bool Activated;
/// <summary>
/// Whether to automatically set item-prefixes when toggling the flashlight.
/// </summary>
/// <remarks>
/// Flashlights should probably be using explicit unshaded sprite, in-hand and clothing layers, this is
/// mostly here for backwards compatibility.
/// </remarks>
[DataField("addPrefix")]
public bool AddPrefix = false;
/// <summary>
/// Sprite layer that will have it's visibility toggled when this item is toggled.
/// </summary>
[DataField("layer")]
public string Layer = "light";
/// <summary>
/// Layers to add to the sprite of the player that is holding this entity.
/// </summary>
[DataField("inhandVisuals")]
public Dictionary<HandLocation, List<PrototypeLayerData>> InhandVisuals = new();
/// <summary>
/// Layers to add to the sprite of the player that is wearing this entity.
/// </summary>
[DataField("clothingVisuals")]
public readonly Dictionary<string, List<PrototypeLayerData>> ClothingVisuals = new();
public Color Color { get; internal set; }
public Control MakeControl() public Control MakeControl()
{ {

View File

@@ -1,16 +1,77 @@
using Content.Client.Clothing;
using Content.Client.Items.Systems;
using Content.Client.Light.Components; using Content.Client.Light.Components;
using Content.Shared.Clothing;
using Content.Shared.Hands;
using Content.Shared.Item;
using Content.Shared.Light.Component; using Content.Shared.Light.Component;
using Robust.Shared.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using System.Linq;
namespace Content.Client.Light; namespace Content.Client.Light;
public sealed class HandheldLightSystem : EntitySystem public sealed class HandheldLightSystem : EntitySystem
{ {
[Dependency] private readonly ItemSystem _itemSys = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<HandheldLightComponent, ComponentHandleState>(OnHandleState); SubscribeLocalEvent<HandheldLightComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<HandheldLightComponent, GetInhandVisualsEvent>(OnGetHeldVisuals, after: new[] { typeof(ItemSystem) } );
SubscribeLocalEvent<HandheldLightComponent, GetEquipmentVisualsEvent>(OnGetEquipmentVisuals, after: new[] { typeof(ClothingSystem)});
}
/// <summary>
/// Add the unshaded light overlays to any clothing sprites.
/// </summary>
private void OnGetEquipmentVisuals(EntityUid uid, HandheldLightComponent component, GetEquipmentVisualsEvent args)
{
if (!component.Activated)
return;
if (!component.ClothingVisuals.TryGetValue(args.Slot, out var layers))
return;
var i = 0;
foreach (var layer in layers)
{
var key = layer.MapKeys?.FirstOrDefault();
if (key == null)
{
key = i == 0 ? $"{args.Slot}-light" : $"{args.Slot}-light-{i}";
i++;
}
args.Layers.Add((key, layer));
}
}
/// <summary>
/// Add the unshaded light overlays to any in-hand sprites.
/// </summary>
private void OnGetHeldVisuals(EntityUid uid, HandheldLightComponent component, GetInhandVisualsEvent args)
{
if (!component.Activated)
return;
if (!component.InhandVisuals.TryGetValue(args.Location, out var layers))
return;
var i = 0;
var defaultKey = $"inhand-{args.Location.ToString().ToLowerInvariant()}-light";
foreach (var layer in layers)
{
var key = layer.MapKeys?.FirstOrDefault();
if (key == null)
{
key = i == 0 ? defaultKey : $"{defaultKey}-{i}";
i++;
}
args.Layers.Add((key, layer));
}
} }
private void OnHandleState(EntityUid uid, HandheldLightComponent component, ref ComponentHandleState args) private void OnHandleState(EntityUid uid, HandheldLightComponent component, ref ComponentHandleState args)
@@ -19,5 +80,26 @@ public sealed class HandheldLightSystem : EntitySystem
return; return;
component.Level = state.Charge; component.Level = state.Charge;
if (state.Activated == component.Activated)
return;
component.Activated = state.Activated;
_itemSys.VisualsChanged(uid);
if (TryComp(component.Owner, out SpriteComponent? sprite))
{
sprite.LayerSetVisible(component.Layer, state.Activated);
}
if (TryComp(uid, out PointLightComponent? light))
{
light.Enabled = state.Activated;
}
// really hand-held lights should be using a separate unshaded layer. (see FlashlightVisualizer)
// this prefix stuff is largely for backwards compatibility with RSIs/yamls that have not been updated.
if (component.AddPrefix && TryComp(uid, out SharedItemComponent? item))
item.EquippedPrefix = state.Activated ? "on" : "off";
} }
} }

View File

@@ -1,20 +1,21 @@
using System;
using System.Linq; using System.Linq;
using Content.Shared.Item; using Content.Client.Items.Systems;
using Content.Shared.Clothing;
using Content.Shared.Hands;
using Content.Shared.Inventory.Events;
using Content.Shared.Light; using Content.Shared.Light;
using Content.Shared.Light.Component; using Content.Shared.Light.Component;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using static Robust.Client.GameObjects.SpriteComponent;
namespace Content.Client.Light namespace Content.Client.Light
{ {
public sealed class RgbLightControllerSystem : SharedRgbLightControllerSystem public sealed class RgbLightControllerSystem : SharedRgbLightControllerSystem
{ {
[Dependency] private IGameTiming _gameTiming = default!; [Dependency] private IGameTiming _gameTiming = default!;
[Dependency] private ItemSystem _itemSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -23,77 +24,137 @@ namespace Content.Client.Light
SubscribeLocalEvent<RgbLightControllerComponent, ComponentHandleState>(OnHandleState); SubscribeLocalEvent<RgbLightControllerComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<RgbLightControllerComponent, ComponentShutdown>(OnComponentShutdown); SubscribeLocalEvent<RgbLightControllerComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<RgbLightControllerComponent, ComponentStartup>(OnComponentStart); SubscribeLocalEvent<RgbLightControllerComponent, ComponentStartup>(OnComponentStart);
SubscribeLocalEvent<RgbLightControllerComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<RgbLightControllerComponent, EquipmentVisualsUpdatedEvent>(OnEquipmentVisualsUpdated);
SubscribeLocalEvent<RgbLightControllerComponent, HeldVisualsUpdatedEvent>(OnHeldVisualsUpdated);
} }
private void OnComponentStart(EntityUid uid, RgbLightControllerComponent rgb, ComponentStartup args) private void OnComponentStart(EntityUid uid, RgbLightControllerComponent rgb, ComponentStartup args)
{ {
if (TryComp(uid, out PointLightComponent? light)) GetOriginalColors(uid, rgb);
rgb.OriginalLightColor = light.Color;
if (TryComp(uid, out SharedItemComponent? item)) // trigger visuals updated events
rgb.OriginalItemColor = item.Color; _itemSystem.VisualsChanged(uid);
GetOriginalSpriteColors(uid, rgb);
} }
private void OnComponentShutdown(EntityUid uid, RgbLightControllerComponent rgb, ComponentShutdown args) private void OnComponentShutdown(EntityUid uid, RgbLightControllerComponent rgb, ComponentShutdown args)
{ {
if (TryComp(uid, out PointLightComponent? light)) ResetOriginalColors(uid, rgb);
light.Color = rgb.OriginalLightColor;
if (TryComp(uid, out SharedItemComponent? item)) // and reset any in-hands or clothing sprites
item.Color = rgb.OriginalItemColor; _itemSystem.VisualsChanged(uid);
ResetSpriteColors(uid, rgb);
} }
private void OnGotUnequipped(EntityUid uid, RgbLightControllerComponent rgb, GotUnequippedEvent args)
{
rgb.Holder = null;
rgb.HolderLayers = null;
}
private void OnHeldVisualsUpdated(EntityUid uid, RgbLightControllerComponent rgb, HeldVisualsUpdatedEvent args)
{
if (args.RevealedLayers.Count == 0)
{
rgb.Holder = null;
rgb.HolderLayers = null;
return;
}
rgb.Holder = args.User;
rgb.HolderLayers = new();
if (!TryComp(args.User, out SpriteComponent? sprite))
return;
foreach (var key in args.RevealedLayers)
{
if (!sprite.LayerMapTryGet(key, out var index) || sprite[index] is not Layer layer)
continue;
if (layer.ShaderPrototype == "unshaded")
rgb.HolderLayers.Add(key);
}
}
private void OnEquipmentVisualsUpdated(EntityUid uid, RgbLightControllerComponent rgb, EquipmentVisualsUpdatedEvent args)
{
rgb.Holder = args.Equipee;
rgb.HolderLayers = new();
if (!TryComp(args.Equipee, out SpriteComponent? sprite))
return;
foreach (var key in args.RevealedLayers)
{
if (!sprite.LayerMapTryGet(key, out var index) || sprite[index] is not Layer layer)
continue;
if (layer.ShaderPrototype == "unshaded")
rgb.HolderLayers.Add(key);
}
}
private void OnHandleState(EntityUid uid, RgbLightControllerComponent rgb, ref ComponentHandleState args) private void OnHandleState(EntityUid uid, RgbLightControllerComponent rgb, ref ComponentHandleState args)
{ {
if (args.Current is not RgbLightControllerState state) if (args.Current is not RgbLightControllerState state)
return; return;
ResetSpriteColors(uid, rgb); ResetOriginalColors(uid, rgb);
rgb.CycleRate = state.CycleRate; rgb.CycleRate = state.CycleRate;
rgb.Layers = state.Layers; rgb.Layers = state.Layers;
GetOriginalColors(uid, rgb);
// get the new original sprite colors (necessary if rgb.Layers was updated).
GetOriginalSpriteColors(uid, rgb);
} }
private void GetOriginalSpriteColors(EntityUid uid, RgbLightControllerComponent? rgb = null, SpriteComponent? sprite = null) private void GetOriginalColors(EntityUid uid, RgbLightControllerComponent? rgb = null, PointLightComponent? light = null, SpriteComponent? sprite = null)
{ {
if (!Resolve(uid, ref rgb, ref sprite)) if (!Resolve(uid, ref rgb, ref sprite, ref light))
return; return;
rgb.OriginalLightColor = light.Color;
rgb.OriginalLayerColors = new();
var layerCount = sprite.AllLayers.Count();
// if layers is null, get unshaded layers
if (rgb.Layers == null) if (rgb.Layers == null)
{ {
rgb.OriginalSpriteColor = sprite.Color; rgb.Layers = new();
rgb.OriginalLayerColors = null;
for (var i = 0; i < layerCount; i++)
{
if (sprite[i] is Layer layer && layer.ShaderPrototype == "unshaded")
{
rgb.Layers.Add(i);
rgb.OriginalLayerColors[i] = layer.Color;
}
}
return; return;
} }
var spriteLayerCount = sprite.AllLayers.Count(); foreach (var index in rgb.Layers.ToArray())
rgb.OriginalLayerColors = new(rgb.Layers.Count);
foreach (var layer in rgb.Layers.ToArray())
{ {
if (layer < spriteLayerCount) if (index < layerCount)
rgb.OriginalLayerColors[layer] = sprite[layer].Color; rgb.OriginalLayerColors[index] = sprite[index].Color;
else else
rgb.Layers.Remove(layer); {
// admeme fuck-ups or bad yaml?
Logger.Warning($"RGB light attempted to use invalid sprite index {index} on entity {ToPrettyString(uid)}");
rgb.Layers.Remove(index);
}
} }
} }
private void ResetSpriteColors(EntityUid uid, RgbLightControllerComponent? rgb = null, SpriteComponent? sprite = null) private void ResetOriginalColors(EntityUid uid, RgbLightControllerComponent? rgb = null, PointLightComponent? light = null, SpriteComponent? sprite = null)
{ {
if (!Resolve(uid, ref rgb, ref sprite)) if (!Resolve(uid, ref rgb, ref sprite, ref light))
return; return;
light.Color = rgb.OriginalLightColor;
if (rgb.Layers == null || rgb.OriginalLayerColors == null) if (rgb.Layers == null || rgb.OriginalLayerColors == null)
{
sprite.Color = rgb.OriginalSpriteColor;
return; return;
}
foreach (var (layer, color) in rgb.OriginalLayerColors) foreach (var (layer, color) in rgb.OriginalLayerColors)
{ {
@@ -109,9 +170,7 @@ namespace Content.Client.Light
light.Color = color; light.Color = color;
if (rgb.Layers == null) if (rgb.Layers != null)
sprite.Color = color;
else
{ {
foreach (var layer in rgb.Layers) foreach (var layer in rgb.Layers)
{ {
@@ -119,9 +178,14 @@ namespace Content.Client.Light
} }
} }
// not all rgb is hand-held (Hence, not part of EntityQuery) // is the entity being held by someone?
if (TryComp(rgb.Owner, out SharedItemComponent? item)) if (rgb.HolderLayers == null || !TryComp(rgb.Holder, out SpriteComponent? holderSprite))
item.Color = color; continue;
foreach (var layer in rgb.HolderLayers)
{
holderSprite.LayerSetColor(layer, color);
}
} }
} }

View File

@@ -5,7 +5,6 @@ using Content.Server.PowerCell;
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Light.Component; using Content.Shared.Light.Component;
using Content.Shared.Rounding; using Content.Shared.Rounding;
using Content.Shared.Toggleable; using Content.Shared.Toggleable;
@@ -67,7 +66,7 @@ namespace Content.Server.Light.EntitySystems
private void OnGetState(EntityUid uid, HandheldLightComponent component, ref ComponentGetState args) private void OnGetState(EntityUid uid, HandheldLightComponent component, ref ComponentGetState args)
{ {
args.State = new SharedHandheldLightComponent.HandheldLightComponentState(GetLevel(component)); args.State = new SharedHandheldLightComponent.HandheldLightComponentState(component.Activated, GetLevel(component));
} }
private byte? GetLevel(HandheldLightComponent component) private byte? GetLevel(HandheldLightComponent component)
@@ -169,8 +168,8 @@ namespace Content.Server.Light.EntitySystems
{ {
if (!component.Activated) return false; if (!component.Activated) return false;
SetState(component, false);
component.Activated = false; component.Activated = false;
_actionSystem.SetToggled(component.ToggleAction, false);
_activeLights.Remove(component); _activeLights.Remove(component);
component.LastLevel = null; component.LastLevel = null;
component.Dirty(EntityManager); component.Dirty(EntityManager);
@@ -203,36 +202,15 @@ namespace Content.Server.Light.EntitySystems
} }
component.Activated = true; component.Activated = true;
SetState(component, true); _actionSystem.SetToggled(component.ToggleAction, true);
_activeLights.Add(component); _activeLights.Add(component);
component.LastLevel = GetLevel(component); component.LastLevel = GetLevel(component);
component.Dirty(EntityManager); Dirty(component);
SoundSystem.Play(Filter.Pvs(component.Owner), component.TurnOnSound.GetSound(), component.Owner); SoundSystem.Play(Filter.Pvs(component.Owner), component.TurnOnSound.GetSound(), component.Owner);
return true; return true;
} }
private void SetState(HandheldLightComponent component, bool on)
{
// TODO: Oh dear
if (EntityManager.TryGetComponent(component.Owner, out SpriteComponent? sprite))
{
sprite.LayerSetVisible(1, on);
}
if (EntityManager.TryGetComponent(component.Owner, out PointLightComponent? light))
{
light.Enabled = on;
}
if (EntityManager.TryGetComponent(component.Owner, out SharedItemComponent? item))
{
item.EquippedPrefix = on ? "on" : "off";
}
_actionSystem.SetToggled(component.ToggleAction, on);
}
public void TryUpdate(HandheldLightComponent component, float frameTime) public void TryUpdate(HandheldLightComponent component, float frameTime)
{ {
if (!_powerCell.TryGetBatteryFromSlot(component.Owner, out var battery)) if (!_powerCell.TryGetBatteryFromSlot(component.Owner, out var battery))

View File

@@ -84,9 +84,6 @@ public abstract partial class InventorySystem
if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component)) if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))
return; return;
// un-rotate entities. needed for things like directional flashlights on hardsuit helmets
Transform(args.Entity).LocalRotation = 0;
var equippedEvent = new DidEquipEvent(uid, args.Entity, slotDef); var equippedEvent = new DidEquipEvent(uid, args.Entity, slotDef);
RaiseLocalEvent(uid, equippedEvent); RaiseLocalEvent(uid, equippedEvent);

View File

@@ -6,12 +6,17 @@ using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Content.Shared.Light.Component; namespace Content.Shared.Light.Component;
/// <summary> /// <summary>
/// Networked ~~solely for admemes~~ for completely legitimate reasons, like hacked energy swords. /// Makes the color of lights on an entity fluctuate. Will update point-light color and modulate some or all of the
/// sprite layers. Will also modulate the color of any unshaded layers that this entity contributes to a wearer or holder.
/// </summary> /// </summary>
/// <remarks>
/// Networked ~~solely for admemes~~ for completely legitimate reasons, like hacked energy swords.
/// </remarks>
[NetworkedComponent] [NetworkedComponent]
[RegisterComponent] [RegisterComponent]
[Friend(typeof(SharedRgbLightControllerSystem))] [Friend(typeof(SharedRgbLightControllerSystem))]
@@ -21,23 +26,37 @@ public sealed class RgbLightControllerComponent : Robust.Shared.GameObjects.Comp
public float CycleRate { get; set; } = 0.1f; public float CycleRate { get; set; } = 0.1f;
/// <summary> /// <summary>
/// What layers of the sprite to modulate? If null, will affect the whole sprite. /// What layers of the sprite to modulate? If null, will affect only unshaded layers.
/// </summary> /// </summary>
[DataField("layers")] [DataField("layers")]
public List<int>? Layers; public List<int>? Layers;
// original colors when rgb was added. Used to revert Colors when removed. /// <summary>
/// Original light color from befor the rgb was aded. Used to revert colors when removed.
/// </summary>
public Color OriginalLightColor; public Color OriginalLightColor;
public Color OriginalItemColor;
public Color OriginalSpriteColor; /// <summary>
/// Original colors of the sprite layersfrom before the rgb was added. Used to revert colors when removed.
/// </summary>
public Dictionary<int, Color>? OriginalLayerColors; public Dictionary<int, Color>? OriginalLayerColors;
/// <summary>
/// User that is holding or wearing this entity
/// </summary>
public EntityUid? Holder;
/// <summary>
/// List of unshaded layers on the holder/wearer that are being modulated.
/// </summary>
public List<string>? HolderLayers;
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class RgbLightControllerState : ComponentState public sealed class RgbLightControllerState : ComponentState
{ {
public readonly float CycleRate; public readonly float CycleRate;
public readonly List<int>? Layers; public List<int>? Layers;
public RgbLightControllerState(float cycleRate, List<int>? layers) public RgbLightControllerState(float cycleRate, List<int>? layers)
{ {

View File

@@ -17,8 +17,11 @@ namespace Content.Shared.Light.Component
{ {
public byte? Charge { get; } public byte? Charge { get; }
public HandheldLightComponentState(byte? charge) public bool Activated { get; }
public HandheldLightComponentState(bool activated, byte? charge)
{ {
Activated = activated;
Charge = charge; Charge = charge;
} }
} }

View File

@@ -1,6 +1,7 @@
using Content.Shared.Light.Component; using Content.Shared.Light.Component;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Content.Shared.Light; namespace Content.Shared.Light;
@@ -33,7 +34,7 @@ public abstract class SharedRgbLightControllerSystem : EntitySystem
if (!Resolve(uid, ref rgb)) if (!Resolve(uid, ref rgb))
return; return;
rgb.CycleRate = rate; rgb.CycleRate = Math.Clamp(0.01f, rate, 1); // lets not give people seizures
rgb.Dirty(); rgb.Dirty();
} }
} }

View File

@@ -58,20 +58,26 @@
name: base hardsuit helmet with light name: base hardsuit helmet with light
components: components:
- type: Sprite - type: Sprite
netsync: true netsync: false
layers: layers:
- state: icon - state: icon
- state: icon-flash - state: icon-flash
visible: false visible: false
map: [ "light" ]
- type: Clothing - type: Clothing
HeldPrefix: off HeldPrefix: off
- type: PointLight - type: PointLight
netsync: false
enabled: false enabled: false
radius: 3 radius: 6
energy: 2
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: Appearance - type: Appearance
visuals: visuals:
- type: FlashLightVisualizer - type: FlashLightVisualizer
- type: HandheldLight - type: HandheldLight
addPrefix: true
toggleAction: toggleAction:
name: action-name-toggle-light name: action-name-toggle-light
description: action-description-toggle-light description: action-description-toggle-light

View File

@@ -10,6 +10,7 @@
- state: light-icon - state: light-icon
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Clothing - type: Clothing
HeldPrefix: off HeldPrefix: off
- type: PointLight - type: PointLight
@@ -19,6 +20,7 @@
visuals: visuals:
- type: FlashLightVisualizer - type: FlashLightVisualizer
- type: HandheldLight - type: HandheldLight
addPrefix: true
toggleAction: toggleAction:
name: action-name-toggle-light name: action-name-toggle-light
description: action-description-toggle-light description: action-description-toggle-light

View File

@@ -5,9 +5,44 @@
description: A special hardsuit helmet designed for working in low-pressure, high thermal environments. description: A special hardsuit helmet designed for working in low-pressure, high thermal environments.
components: components:
- type: Sprite - type: Sprite
netsync: false
sprite: Clothing/Head/Hardsuits/atmospherics.rsi sprite: Clothing/Head/Hardsuits/atmospherics.rsi
layers:
- state: icon
- state: icon-unshaded
shader: unshaded
- state: light-overlay
visible: false
shader: unshaded
map: [ "light" ]
- type: HandheldLight
addPrefix: false
inhandVisuals:
left:
- state: inhand-left-light
shader: unshaded
right:
- state: inhand-right-light
shader: unshaded
clothingVisuals:
head:
- state: equipped-head-light
shader: unshaded
- type: Clothing - type: Clothing
sprite: Clothing/Head/Hardsuits/atmospherics.rsi clothingVisuals:
head:
- state: equipped-head
- state: equipped-head-unshaded
shader: unshaded
inhandVisuals:
left:
- state: inhand-left
- state: inhand-left-unshaded
shader: unshaded
right:
- state: inhand-right
- state: inhand-right-unshaded
shader: unshaded
- type: entity - type: entity
parent: ClothingHeadHardsuitBase parent: ClothingHeadHardsuitBase

View File

@@ -5,6 +5,7 @@
abstract: true abstract: true
components: components:
- type: HandheldLight - type: HandheldLight
addPrefix: true
toggleAction: toggleAction:
name: action-name-toggle-light name: action-name-toggle-light
description: action-description-toggle-light description: action-description-toggle-light
@@ -31,6 +32,7 @@
- state: lamp-on - state: lamp-on
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Item - type: Item
sprite: Objects/Misc/Lights/lamp.rsi sprite: Objects/Misc/Lights/lamp.rsi
- type: PointLight - type: PointLight
@@ -53,6 +55,7 @@
- state: bananalamp_on - state: bananalamp_on
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: PointLight - type: PointLight
enabled: false enabled: false
radius: 3 radius: 3
@@ -74,6 +77,7 @@
- state: lampgreen-on - state: lampgreen-on
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Item - type: Item
sprite: Objects/Misc/Lights/lampgreen.rsi sprite: Objects/Misc/Lights/lampgreen.rsi
- type: PointLight - type: PointLight
@@ -96,6 +100,7 @@
- state: floodlight_on - state: floodlight_on
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Physics - type: Physics
- type: Fixtures - type: Fixtures
fixtures: fixtures:

View File

@@ -9,6 +9,14 @@
- Flashlight - Flashlight
- DroneUsable - DroneUsable
- type: HandheldLight - type: HandheldLight
addPrefix: false
inhandVisuals:
left:
- state: inhand-left-light
shader: unshaded
right:
- state: inhand-right-light
shader: unshaded
toggleAction: toggleAction:
name: action-name-toggle-light name: action-name-toggle-light
description: action-description-toggle-light description: action-description-toggle-light
@@ -26,10 +34,11 @@
- state: flashlight-overlay - state: flashlight-overlay
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Item - type: Item
sprite: Objects/Tools/flashlight.rsi sprite: Objects/Tools/flashlight.rsi
HeldPrefix: off
- type: PointLight - type: PointLight
netsync: false
enabled: false enabled: false
mask: /Textures/Effects/LightMasks/cone.png mask: /Textures/Effects/LightMasks/cone.png
autoRot: true autoRot: true
@@ -47,6 +56,15 @@
- type: PowerCellSlot - type: PowerCellSlot
cellSlot: cellSlot:
startingItem: PowerCellSmallSuper startingItem: PowerCellSmallSuper
- type: HandheldLight
addPrefix: false
inhandVisuals:
left:
- state: inhand-left-light
shader: unshaded
right:
- state: inhand-right-light
shader: unshaded
- type: Sprite - type: Sprite
sprite: Objects/Tools/seclite.rsi sprite: Objects/Tools/seclite.rsi
layers: layers:
@@ -54,6 +72,7 @@
- state: seclite-overlay - state: seclite-overlay
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Item - type: Item
sprite: Objects/Tools/seclite.rsi sprite: Objects/Tools/seclite.rsi
- type: PointLight - type: PointLight

View File

@@ -5,6 +5,7 @@
description: The holy light guides the way. description: The holy light guides the way.
components: components:
- type: HandheldLight - type: HandheldLight
addPrefix: true
toggleAction: toggleAction:
name: action-name-toggle-light name: action-name-toggle-light
description: action-description-toggle-light description: action-description-toggle-light
@@ -18,10 +19,12 @@
- state: lantern-on - state: lantern-on
shader: unshaded shader: unshaded
visible: false visible: false
map: [ "light" ]
- type: Item - type: Item
sprite: Objects/Tools/lantern.rsi sprite: Objects/Tools/lantern.rsi
HeldPrefix: off HeldPrefix: off
- type: PointLight - type: PointLight
netsync: false
enabled: false enabled: false
radius: 3 radius: 3
energy: 2.5 energy: 2.5

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -10,31 +10,49 @@
{ {
"name": "icon" "name": "icon"
}, },
{
"name": "icon-unshaded"
},
{ {
"name": "icon-flash" "name": "icon-flash"
}, },
{ {
"name": "off-equipped-HELMET", "name": "light-overlay"
},
{
"name": "equipped-head",
"directions": 4 "directions": 4
}, },
{ {
"name": "off-inhand-left", "name": "equipped-head-light",
"directions": 4 "directions": 4
}, },
{ {
"name": "off-inhand-right", "name": "equipped-head-unshaded",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-equipped-HELMET", "name": "inhand-left",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-left", "name": "inhand-left-unshaded",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-right", "name": "inhand-left-light",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "inhand-right-unshaded",
"directions": 4
},
{
"name": "inhand-right-light",
"directions": 4 "directions": 4
} }
] ]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 424 B

After

Width:  |  Height:  |  Size: 424 B

View File

@@ -17,19 +17,19 @@
"name": "flashlight-overlay" "name": "flashlight-overlay"
}, },
{ {
"name": "off-inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4
}, },
{ {
"name": "off-inhand-right", "name": "inhand-right",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-left", "name": "inhand-left-light",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-right", "name": "inhand-right-light",
"directions": 4 "directions": 4
}, },
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 401 B

View File

@@ -17,19 +17,19 @@
"name": "seclite-overlay" "name": "seclite-overlay"
}, },
{ {
"name": "off-inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4
}, },
{ {
"name": "off-inhand-right", "name": "inhand-right",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-left", "name": "inhand-left-light",
"directions": 4 "directions": 4
}, },
{ {
"name": "on-inhand-right", "name": "inhand-right-light",
"directions": 4 "directions": 4
}, },
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B