Add Flashlight Visualizer/states (#1861)
* Add art assets for cloning * Added a 'Scan DNA' button to the medical scanner * Made the UI update unconditional for the medical scanner until checks for power changes are in place * Update Medical scanner to reflect powered status and fix #1774 * added a 'scan dna' button the the medical scanner that will add the contained bodies Uid to a list in CloningSystem, fixed an issue with the menu not populating if the scanner starts in an unpowered state * Add disabling logic to 'Scan DNA' button on medical scanner * Removed un-used libraries * Added playing parameter to radiatingLightComponent, changed it's animation key to radiatingLight * refactored RadiatingLight into a visualizer * Added different light animations for differnt power states of a flashlight * split out the radiating light visualizer into two seperate visualizers * further refactored and tweaked handheldlight animations * further lantern light tweaks * removed un-used attributes in flashlight and lantern prototypes * fix null check in handheldlightcomponent
This commit is contained in:
119
Content.Client/GameObjects/Components/FlashLightVisualizer.cs
Normal file
119
Content.Client/GameObjects/Components/FlashLightVisualizer.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.GameObjects.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.GameObjects.Components.Animations;
|
||||||
|
using Robust.Shared.Animations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class FlashLightVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
private readonly Animation _radiatingLightAnimation = new Animation
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(1),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty
|
||||||
|
{
|
||||||
|
ComponentType = typeof(PointLightComponent),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||||
|
Property = nameof(PointLightComponent.Radius),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(3.0f, 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(2.0f, 0.5f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(3.0f, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Animation _blinkingLightAnimation = new Animation
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(1),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty()
|
||||||
|
{
|
||||||
|
ComponentType = typeof(PointLightComponent),
|
||||||
|
//To create the blinking effect we go from nearly zero radius, to the light radius, and back
|
||||||
|
//We do this instead of messing with the `PointLightComponent.enabled` because we don't want the animation to affect component behavior
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Nearest,
|
||||||
|
Property = nameof(PointLightComponent.Radius),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(0.1f, 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(2f, 0.5f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(0.1f, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Action<string> _radiatingCallback;
|
||||||
|
private Action<string> _blinkingCallback;
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
if (component.Deleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.TryGetData(HandheldLightVisuals.Power,
|
||||||
|
out HandheldLightPowerStates state))
|
||||||
|
{
|
||||||
|
PlayAnimation(component, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayAnimation(AppearanceComponent component, HandheldLightPowerStates state)
|
||||||
|
{
|
||||||
|
component.Owner.EnsureComponent(out AnimationPlayerComponent animationPlayer);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case HandheldLightPowerStates.LowPower:
|
||||||
|
if (!animationPlayer.HasRunningAnimation("radiatingLight"))
|
||||||
|
{
|
||||||
|
animationPlayer.Play(_radiatingLightAnimation, "radiatingLight");
|
||||||
|
_radiatingCallback = (s) => animationPlayer.Play(_radiatingLightAnimation, s);
|
||||||
|
animationPlayer.AnimationCompleted += _radiatingCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case HandheldLightPowerStates.Dying:
|
||||||
|
animationPlayer.Stop("radiatingLight");
|
||||||
|
animationPlayer.AnimationCompleted -= _radiatingCallback;
|
||||||
|
if (!animationPlayer.HasRunningAnimation("blinkingLight"))
|
||||||
|
{
|
||||||
|
animationPlayer.Play(_blinkingLightAnimation, "blinkingLight");
|
||||||
|
_blinkingCallback = (s) => animationPlayer.Play(_blinkingLightAnimation, s);
|
||||||
|
animationPlayer.AnimationCompleted += _blinkingCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case HandheldLightPowerStates.FullPower:
|
||||||
|
if (animationPlayer.HasRunningAnimation("blinkingLight"))
|
||||||
|
{
|
||||||
|
animationPlayer.Stop("blinkingLight");
|
||||||
|
animationPlayer.AnimationCompleted -= _blinkingCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animationPlayer.HasRunningAnimation("radiatingLight"))
|
||||||
|
{
|
||||||
|
animationPlayer.Stop("radiatingLight");
|
||||||
|
animationPlayer.AnimationCompleted -= _radiatingCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Content.Client/GameObjects/Components/LanternVisualizer.cs
Normal file
56
Content.Client/GameObjects/Components/LanternVisualizer.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.GameObjects.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.GameObjects.Components.Animations;
|
||||||
|
using Robust.Shared.Animations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using YamlDotNet.RepresentationModel;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class LanternVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
private readonly Animation _radiatingLightAnimation = new Animation
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(5),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty
|
||||||
|
{
|
||||||
|
ComponentType = typeof(PointLightComponent),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||||
|
Property = nameof(PointLightComponent.Radius),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(3.0f, 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(2.0f, 1.5f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(3.0f, 3f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
if (component.Deleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayAnimation(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayAnimation(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
component.Owner.EnsureComponent(out AnimationPlayerComponent animationPlayer);
|
||||||
|
if (animationPlayer.HasRunningAnimation("radiatingLight")) return;
|
||||||
|
animationPlayer.Play(_radiatingLightAnimation, "radiatingLight");
|
||||||
|
animationPlayer.AnimationCompleted += s => animationPlayer.Play(_radiatingLightAnimation, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Robust.Client.Animations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.GameObjects.Components.Animations;
|
|
||||||
using Robust.Shared.Animations;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.GameObjects.Components
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public class RadiatingLightComponent : Component
|
|
||||||
{
|
|
||||||
public override string Name => "RadiatingLight";
|
|
||||||
|
|
||||||
protected override void Startup()
|
|
||||||
{
|
|
||||||
base.Startup();
|
|
||||||
|
|
||||||
var animation = new Animation
|
|
||||||
{
|
|
||||||
Length = TimeSpan.FromSeconds(4),
|
|
||||||
AnimationTracks =
|
|
||||||
{
|
|
||||||
new AnimationTrackComponentProperty
|
|
||||||
{
|
|
||||||
ComponentType = typeof(PointLightComponent),
|
|
||||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
|
||||||
Property = nameof(PointLightComponent.Radius),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(3.0f, 0),
|
|
||||||
new AnimationTrackProperty.KeyFrame(2.0f, 1),
|
|
||||||
new AnimationTrackProperty.KeyFrame(3.0f, 2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var playerComponent = Owner.EnsureComponent<AnimationPlayerComponent>();
|
|
||||||
playerComponent.Play(animation, "emergency");
|
|
||||||
|
|
||||||
playerComponent.AnimationCompleted += s => playerComponent.Play(animation, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.GameObjects.Components;
|
using Content.Shared.GameObjects.Components;
|
||||||
using Content.Shared.GameObjects.Components.Pointing;
|
|
||||||
using Content.Shared.Interfaces.GameObjects.Components;
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.GameObjects.EntitySystems;
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
/// Component that represents a handheld lightsource which can be toggled on and off.
|
/// Component that represents a handheld lightsource which can be toggled on and off.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit
|
internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing,
|
||||||
|
IMapInit
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ISharedNotifyManager _notifyManager = default!;
|
[Dependency] private readonly ISharedNotifyManager _notifyManager = default!;
|
||||||
|
|
||||||
@@ -41,9 +42,12 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_cellContainer.ContainedEntity == null) return null;
|
if (_cellContainer.ContainedEntity == null) return null;
|
||||||
|
if (_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent? cell))
|
||||||
|
{
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent? cell);
|
return null;
|
||||||
return cell;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +138,6 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
Activated = false;
|
Activated = false;
|
||||||
|
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TurnOn(IEntity user)
|
private void TurnOn(IEntity user)
|
||||||
@@ -147,7 +150,6 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
var cell = Cell;
|
var cell = Cell;
|
||||||
if (cell == null)
|
if (cell == null)
|
||||||
{
|
{
|
||||||
|
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Machines/button.ogg", Owner);
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Machines/button.ogg", Owner);
|
||||||
|
|
||||||
_notifyManager.PopupMessage(Owner, user, Loc.GetString("Cell missing..."));
|
_notifyManager.PopupMessage(Owner, user, Loc.GetString("Cell missing..."));
|
||||||
@@ -168,7 +170,6 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
SetState(true);
|
SetState(true);
|
||||||
|
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetState(bool on)
|
private void SetState(bool on)
|
||||||
@@ -191,10 +192,24 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
|
|
||||||
public void OnUpdate(float frameTime)
|
public void OnUpdate(float frameTime)
|
||||||
{
|
{
|
||||||
if (!Activated) return;
|
if (!Activated || Cell == null) return;
|
||||||
|
|
||||||
var cell = Cell;
|
var appearanceComponent = Owner.GetComponent<AppearanceComponent>();
|
||||||
if (cell == null || !cell.TryUseCharge(Wattage * frameTime)) TurnOff();
|
|
||||||
|
if (Cell.MaxCharge - Cell.CurrentCharge < Cell.MaxCharge * 0.70)
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(HandheldLightVisuals.Power, HandheldLightPowerStates.FullPower);
|
||||||
|
}
|
||||||
|
else if (Cell.MaxCharge - Cell.CurrentCharge < Cell.MaxCharge * 0.90)
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(HandheldLightVisuals.Power, HandheldLightPowerStates.LowPower);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(HandheldLightVisuals.Power, HandheldLightPowerStates.Dying);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cell == null || !Cell.TryUseCharge(Wattage * frameTime)) TurnOff();
|
||||||
|
|
||||||
Dirty();
|
Dirty();
|
||||||
}
|
}
|
||||||
@@ -226,7 +241,6 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
}
|
}
|
||||||
|
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/pistol_magout.ogg", Owner);
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/pistol_magout.ogg", Owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ComponentState GetComponentState()
|
public override ComponentState GetComponentState()
|
||||||
|
|||||||
@@ -11,16 +11,15 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
{
|
{
|
||||||
public override string Name => "Battery";
|
public override string Name => "Battery";
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)] public int MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
|
||||||
public int MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
|
|
||||||
private int _maxCharge;
|
private int _maxCharge;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float CurrentCharge { get => _currentCharge; set => SetCurrentCharge(value); }
|
public float CurrentCharge { get => _currentCharge; set => SetCurrentCharge(value); }
|
||||||
|
|
||||||
private float _currentCharge;
|
private float _currentCharge;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables] public BatteryState BatteryState { get; private set; }
|
||||||
public BatteryState BatteryState { get; private set; }
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
{
|
{
|
||||||
@@ -93,7 +92,7 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
private void SetMaxCharge(int newMax)
|
private void SetMaxCharge(int newMax)
|
||||||
{
|
{
|
||||||
_maxCharge = Math.Max(newMax, 0);
|
_maxCharge = Math.Max(newMax, 0);
|
||||||
_currentCharge = Math.Min( _currentCharge, MaxCharge);
|
_currentCharge = Math.Min(_currentCharge, MaxCharge);
|
||||||
UpdateStorageState();
|
UpdateStorageState();
|
||||||
OnChargeChanged();
|
OnChargeChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,20 @@ namespace Content.Shared.GameObjects.Components
|
|||||||
public bool HasCell { get; }
|
public bool HasCell { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum HandheldLightVisuals
|
||||||
|
{
|
||||||
|
Power
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum HandheldLightPowerStates
|
||||||
|
{
|
||||||
|
FullPower,
|
||||||
|
LowPower,
|
||||||
|
Dying,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,21 +4,24 @@
|
|||||||
id: FlashlightLantern
|
id: FlashlightLantern
|
||||||
description: They light the way to freedom
|
description: They light the way to freedom
|
||||||
components:
|
components:
|
||||||
- type: HandheldLight
|
- type: HandheldLight
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Tools/flashlight.rsi
|
sprite: Objects/Tools/flashlight.rsi
|
||||||
layers:
|
layers:
|
||||||
- state: lantern_off
|
- state: lantern_off
|
||||||
- state: HandheldLightOnOverlay
|
- state: HandheldLightOnOverlay
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Objects/Tools/flashlight.rsi
|
sprite: Objects/Tools/flashlight.rsi
|
||||||
state: lantern_off
|
state: lantern_off
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Tools/flashlight.rsi
|
sprite: Objects/Tools/flashlight.rsi
|
||||||
HeldPrefix: off
|
HeldPrefix: off
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
enabled: false
|
enabled: false
|
||||||
radius: 3
|
radius: 3
|
||||||
- type: LoopingSound
|
- type: LoopingSound
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: FlashLightVisualizer
|
||||||
|
|||||||
@@ -23,5 +23,7 @@
|
|||||||
radius: 3
|
radius: 3
|
||||||
energy: 2.5
|
energy: 2.5
|
||||||
color: "#FFC458"
|
color: "#FFC458"
|
||||||
- type: RadiatingLight
|
|
||||||
- type: LoopingSound
|
- type: LoopingSound
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: LanternVisualizer
|
||||||
|
|||||||
Reference in New Issue
Block a user