Ghosts do booo (spooky) (#3363)
* Light now use visualizer * Added ghost actions * Add hotkey input for ghosts * no message * Testing blinking animation * Better animation * Better customization * No abuse * Reversed sln * No fun for ghosts * No fun for ghosts x2 * Cooldown for lights * Moved to component deps * This tollist is unnecessary * Enums to byte Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Some lights can ignore ghosts now Co-authored-by: Alex Evgrashin <evgrashin.adl@gmail.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using Content.Shared.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Animations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using YamlDotNet.RepresentationModel;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class PoweredLightVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
private float _minBlinkingTime;
|
||||||
|
private float _maxBlinkingTime;
|
||||||
|
private string? _blinkingSound;
|
||||||
|
|
||||||
|
private bool _wasBlinking;
|
||||||
|
|
||||||
|
private Action<string>? _blinkingCallback;
|
||||||
|
|
||||||
|
public override void LoadData(YamlMappingNode node)
|
||||||
|
{
|
||||||
|
base.LoadData(node);
|
||||||
|
|
||||||
|
var serializer = YamlObjectSerializer.NewReader(node);
|
||||||
|
serializer.DataField(ref _minBlinkingTime, "minBlinkingTime", 0.5f);
|
||||||
|
serializer.DataField(ref _maxBlinkingTime, "maxBlinkingTime", 2.0f);
|
||||||
|
serializer.DataField(ref _blinkingSound, "blinkingSound", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
|
||||||
|
if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
|
||||||
|
if (!component.Owner.TryGetComponent(out PointLightComponent? light)) return;
|
||||||
|
if (!component.TryGetData(PoweredLightVisuals.BulbState, out PoweredLightState state)) return;
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PoweredLightState.Empty:
|
||||||
|
sprite.LayerSetState(PoweredLightLayers.Base, "empty");
|
||||||
|
ToggleBlinkingAnimation(component, false);
|
||||||
|
light.Enabled = false;
|
||||||
|
break;
|
||||||
|
case PoweredLightState.Off:
|
||||||
|
sprite.LayerSetState(PoweredLightLayers.Base, "off");
|
||||||
|
ToggleBlinkingAnimation(component, false);
|
||||||
|
light.Enabled = false;
|
||||||
|
break;
|
||||||
|
case PoweredLightState.On:
|
||||||
|
if (component.TryGetData(PoweredLightVisuals.BulbColor, out Color color))
|
||||||
|
light.Color = color;
|
||||||
|
if (component.TryGetData(PoweredLightVisuals.Blinking, out bool isBlinking))
|
||||||
|
ToggleBlinkingAnimation(component, isBlinking);
|
||||||
|
if (!isBlinking)
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(PoweredLightLayers.Base, "on");
|
||||||
|
light.Enabled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PoweredLightState.Broken:
|
||||||
|
sprite.LayerSetState(PoweredLightLayers.Base, "broken");
|
||||||
|
ToggleBlinkingAnimation(component, false);
|
||||||
|
light.Enabled = false;
|
||||||
|
break;
|
||||||
|
case PoweredLightState.Burned:
|
||||||
|
sprite.LayerSetState(PoweredLightLayers.Base, "burn");
|
||||||
|
ToggleBlinkingAnimation(component, false);
|
||||||
|
light.Enabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ToggleBlinkingAnimation(AppearanceComponent component, bool isBlinking)
|
||||||
|
{
|
||||||
|
if (isBlinking == _wasBlinking)
|
||||||
|
return;
|
||||||
|
_wasBlinking = isBlinking;
|
||||||
|
|
||||||
|
component.Owner.EnsureComponent(out AnimationPlayerComponent animationPlayer);
|
||||||
|
|
||||||
|
if (isBlinking)
|
||||||
|
{
|
||||||
|
_blinkingCallback = (animName) => animationPlayer.Play(BlinkingAnimation(), "blinking");
|
||||||
|
animationPlayer.AnimationCompleted += _blinkingCallback;
|
||||||
|
animationPlayer.Play(BlinkingAnimation(), "blinking");
|
||||||
|
}
|
||||||
|
else if (animationPlayer.HasRunningAnimation("blinking"))
|
||||||
|
{
|
||||||
|
if (_blinkingCallback != null)
|
||||||
|
animationPlayer.AnimationCompleted -= _blinkingCallback;
|
||||||
|
animationPlayer.Stop("blinking");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Animation BlinkingAnimation()
|
||||||
|
{
|
||||||
|
var random = IoCManager.Resolve<IRobustRandom>();
|
||||||
|
var randomTime = random.NextFloat() *
|
||||||
|
(_maxBlinkingTime - _minBlinkingTime) + _minBlinkingTime;
|
||||||
|
|
||||||
|
var blinkingAnim = new Animation()
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(randomTime),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty
|
||||||
|
{
|
||||||
|
ComponentType = typeof(PointLightComponent),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Nearest,
|
||||||
|
Property = nameof(PointLightComponent.Enabled),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(false, 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(true, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new AnimationTrackSpriteFlick()
|
||||||
|
{
|
||||||
|
LayerKey = PoweredLightLayers.Base,
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackSpriteFlick.KeyFrame("off", 0),
|
||||||
|
new AnimationTrackSpriteFlick.KeyFrame("on", 0.5f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_blinkingSound != null)
|
||||||
|
{
|
||||||
|
blinkingAnim.AnimationTracks.Add(new AnimationTrackPlaySound()
|
||||||
|
{
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackPlaySound.KeyFrame(_blinkingSound, 0.5f)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return blinkingAnim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,26 +46,28 @@ namespace Content.Client.Input
|
|||||||
human.AddFunction(ContentKeyFunctions.Arcade1);
|
human.AddFunction(ContentKeyFunctions.Arcade1);
|
||||||
human.AddFunction(ContentKeyFunctions.Arcade2);
|
human.AddFunction(ContentKeyFunctions.Arcade2);
|
||||||
human.AddFunction(ContentKeyFunctions.Arcade3);
|
human.AddFunction(ContentKeyFunctions.Arcade3);
|
||||||
human.AddFunction(ContentKeyFunctions.OpenActionsMenu);
|
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar0);
|
// actions should be common (for ghosts, mobs, etc)
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar1);
|
common.AddFunction(ContentKeyFunctions.OpenActionsMenu);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar2);
|
common.AddFunction(ContentKeyFunctions.Hotbar0);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar3);
|
common.AddFunction(ContentKeyFunctions.Hotbar1);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar4);
|
common.AddFunction(ContentKeyFunctions.Hotbar2);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar5);
|
common.AddFunction(ContentKeyFunctions.Hotbar3);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar6);
|
common.AddFunction(ContentKeyFunctions.Hotbar4);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar7);
|
common.AddFunction(ContentKeyFunctions.Hotbar5);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar8);
|
common.AddFunction(ContentKeyFunctions.Hotbar6);
|
||||||
human.AddFunction(ContentKeyFunctions.Hotbar9);
|
common.AddFunction(ContentKeyFunctions.Hotbar7);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout1);
|
common.AddFunction(ContentKeyFunctions.Hotbar8);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout2);
|
common.AddFunction(ContentKeyFunctions.Hotbar9);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout3);
|
common.AddFunction(ContentKeyFunctions.Loadout1);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout4);
|
common.AddFunction(ContentKeyFunctions.Loadout2);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout5);
|
common.AddFunction(ContentKeyFunctions.Loadout3);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout6);
|
common.AddFunction(ContentKeyFunctions.Loadout4);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout7);
|
common.AddFunction(ContentKeyFunctions.Loadout5);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout8);
|
common.AddFunction(ContentKeyFunctions.Loadout6);
|
||||||
human.AddFunction(ContentKeyFunctions.Loadout9);
|
common.AddFunction(ContentKeyFunctions.Loadout7);
|
||||||
|
common.AddFunction(ContentKeyFunctions.Loadout8);
|
||||||
|
common.AddFunction(ContentKeyFunctions.Loadout9);
|
||||||
|
|
||||||
var ghost = contexts.New("ghost", "common");
|
var ghost = contexts.New("ghost", "common");
|
||||||
ghost.AddFunction(EngineKeyFunctions.MoveUp);
|
ghost.AddFunction(EngineKeyFunctions.MoveUp);
|
||||||
|
|||||||
54
Content.Server/Actions/GhostBoo.cs
Normal file
54
Content.Server/Actions/GhostBoo.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.GameObjects.Components.Mobs;
|
||||||
|
using Content.Shared.Utility;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Actions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Blink lights and scare livings
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class GhostBoo : IInstantAction
|
||||||
|
{
|
||||||
|
private float _radius;
|
||||||
|
private float _cooldown;
|
||||||
|
private int _maxTargets;
|
||||||
|
|
||||||
|
void IExposeData.ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
serializer.DataField(ref _radius, "radius", 3);
|
||||||
|
serializer.DataField(ref _cooldown, "cooldown", 120);
|
||||||
|
serializer.DataField(ref _maxTargets, "maxTargets", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DoInstantAction(InstantActionEventArgs args)
|
||||||
|
{
|
||||||
|
if (!args.Performer.TryGetComponent<SharedActionsComponent>(out var actions)) return;
|
||||||
|
|
||||||
|
// find all IGhostBooAffected nearby and do boo on them
|
||||||
|
var entityMan = args.Performer.EntityManager;
|
||||||
|
var ents = entityMan.GetEntitiesInRange(args.Performer, _radius, false);
|
||||||
|
|
||||||
|
var booCounter = 0;
|
||||||
|
foreach (var ent in ents)
|
||||||
|
{
|
||||||
|
var boos = ent.GetAllComponents<IGhostBooAffected>().ToList();
|
||||||
|
foreach (var boo in boos)
|
||||||
|
{
|
||||||
|
if (boo.AffectedByGhostBoo(args))
|
||||||
|
booCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (booCounter >= _maxTargets)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.Cooldown(args.ActionType, Cooldowns.SecondsFromNow(_cooldown));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#nullable enable
|
||||||
|
using Content.Shared.Actions;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Observer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allow ghost to interact with object by boo action
|
||||||
|
/// </summary>
|
||||||
|
public interface IGhostBooAffected
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes when ghost used boo action near entity.
|
||||||
|
/// Use it to blink lights or make something spooky.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">Boo action details</param>
|
||||||
|
/// <returns>Returns true if object was affected</returns>
|
||||||
|
bool AffectedByGhostBoo(InstantActionEventArgs args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,11 @@ using Content.Server.GameObjects.Components.Items.Storage;
|
|||||||
using Content.Server.GameObjects.Components.MachineLinking;
|
using Content.Server.GameObjects.Components.MachineLinking;
|
||||||
using Content.Server.GameObjects.Components.MachineLinking.Signals;
|
using Content.Server.GameObjects.Components.MachineLinking.Signals;
|
||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
|
using Content.Shared.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Content.Shared.Interfaces.GameObjects.Components;
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -15,6 +18,7 @@ using Robust.Shared.Audio;
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -25,17 +29,27 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
/// Component that represents a wall light. It has a light bulb that can be replaced when broken.
|
/// Component that represents a wall light. It has a light bulb that can be replaced when broken.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class PoweredLightComponent : Component, IInteractHand, IInteractUsing, IMapInit, ISignalReceiver<bool>, ISignalReceiver<ToggleSignal>
|
public class PoweredLightComponent : Component, IInteractHand, IInteractUsing, IMapInit, ISignalReceiver<bool>, ISignalReceiver<ToggleSignal>, IGhostBooAffected
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
public override string Name => "PoweredLight";
|
public override string Name => "PoweredLight";
|
||||||
|
|
||||||
private static readonly TimeSpan _thunkDelay = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan _thunkDelay = TimeSpan.FromSeconds(2);
|
||||||
|
// time to blink light when ghost made boo nearby
|
||||||
|
private static readonly TimeSpan ghostBlinkingTime = TimeSpan.FromSeconds(10);
|
||||||
|
private static readonly TimeSpan ghostBlinkingCooldown = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
|
[ComponentDependency]
|
||||||
|
private readonly AppearanceComponent? _appearance;
|
||||||
|
|
||||||
private TimeSpan _lastThunk;
|
private TimeSpan _lastThunk;
|
||||||
|
private TimeSpan? _lastGhostBlink;
|
||||||
private bool _hasLampOnSpawn;
|
private bool _hasLampOnSpawn;
|
||||||
|
|
||||||
[ViewVariables] private bool _on;
|
[ViewVariables] private bool _on;
|
||||||
|
[ViewVariables] private bool _isBlinking;
|
||||||
|
[ViewVariables] private bool _ignoreGhostsBoo;
|
||||||
|
|
||||||
private LightBulbType BulbType = LightBulbType.Tube;
|
private LightBulbType BulbType = LightBulbType.Tube;
|
||||||
[ViewVariables] private ContainerSlot _lightBulbContainer = default!;
|
[ViewVariables] private ContainerSlot _lightBulbContainer = default!;
|
||||||
@@ -145,6 +159,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
serializer.DataField(ref BulbType, "bulb", LightBulbType.Tube);
|
serializer.DataField(ref BulbType, "bulb", LightBulbType.Tube);
|
||||||
serializer.DataField(ref _on, "on", true);
|
serializer.DataField(ref _on, "on", true);
|
||||||
serializer.DataField(ref _hasLampOnSpawn, "hasLampOnSpawn", true);
|
serializer.DataField(ref _hasLampOnSpawn, "hasLampOnSpawn", true);
|
||||||
|
serializer.DataField(ref _ignoreGhostsBoo, "ignoreGhostsBoo", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -163,13 +178,11 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
public void UpdateLight()
|
public void UpdateLight()
|
||||||
{
|
{
|
||||||
var powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
var powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
var sprite = Owner.GetComponent<SpriteComponent>();
|
|
||||||
var light = Owner.GetComponent<PointLightComponent>();
|
|
||||||
if (LightBulb == null) // No light bulb.
|
if (LightBulb == null) // No light bulb.
|
||||||
{
|
{
|
||||||
powerReceiver.Load = 0;
|
powerReceiver.Load = 0;
|
||||||
sprite.LayerSetState(0, "empty");
|
_appearance?.SetData(PoweredLightVisuals.BulbState, PoweredLightState.Empty);
|
||||||
light.Enabled = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,9 +192,8 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
if (powerReceiver.Powered && _on)
|
if (powerReceiver.Powered && _on)
|
||||||
{
|
{
|
||||||
powerReceiver.Load = LightBulb.PowerUse;
|
powerReceiver.Load = LightBulb.PowerUse;
|
||||||
sprite.LayerSetState(0, "on");
|
_appearance?.SetData(PoweredLightVisuals.BulbState, PoweredLightState.On);
|
||||||
light.Enabled = true;
|
_appearance?.SetData(PoweredLightVisuals.BulbColor, LightBulb.Color);
|
||||||
light.Color = LightBulb.Color;
|
|
||||||
var time = _gameTiming.CurTime;
|
var time = _gameTiming.CurTime;
|
||||||
if (time > _lastThunk + _thunkDelay)
|
if (time > _lastThunk + _thunkDelay)
|
||||||
{
|
{
|
||||||
@@ -191,17 +203,14 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprite.LayerSetState(0, "off");
|
_appearance?.SetData(PoweredLightVisuals.BulbState, PoweredLightState.Off);
|
||||||
light.Enabled = false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LightBulbState.Broken:
|
case LightBulbState.Broken:
|
||||||
sprite.LayerSetState(0, "broken");
|
_appearance?.SetData(PoweredLightVisuals.BulbState, PoweredLightState.Broken);
|
||||||
light.Enabled = false;
|
|
||||||
break;
|
break;
|
||||||
case LightBulbState.Burned:
|
case LightBulbState.Burned:
|
||||||
sprite.LayerSetState(0, "burned");
|
_appearance?.SetData(PoweredLightVisuals.BulbState, PoweredLightState.Burned);
|
||||||
light.Enabled = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,5 +277,36 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
|
|||||||
_on = !_on;
|
_on = !_on;
|
||||||
UpdateLight();
|
UpdateLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ToggleBlinkingLight(bool isNowBlinking)
|
||||||
|
{
|
||||||
|
if (_isBlinking == isNowBlinking)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isBlinking = isNowBlinking;
|
||||||
|
_appearance?.SetData(PoweredLightVisuals.Blinking, _isBlinking);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AffectedByGhostBoo(InstantActionEventArgs args)
|
||||||
|
{
|
||||||
|
if (_ignoreGhostsBoo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check cooldown first to prevent abuse
|
||||||
|
var time = _gameTiming.CurTime;
|
||||||
|
if (_lastGhostBlink != null)
|
||||||
|
{
|
||||||
|
if (time <= _lastGhostBlink + ghostBlinkingCooldown)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_lastGhostBlink = time;
|
||||||
|
|
||||||
|
ToggleBlinkingLight(true);
|
||||||
|
Owner.SpawnTimer(ghostBlinkingTime, () => {
|
||||||
|
ToggleBlinkingLight(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
Error,
|
Error,
|
||||||
HumanScream,
|
HumanScream,
|
||||||
Disarm,
|
Disarm,
|
||||||
|
GhostBoo,
|
||||||
DebugInstant,
|
DebugInstant,
|
||||||
DebugToggle,
|
DebugToggle,
|
||||||
DebugTargetPoint,
|
DebugTargetPoint,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#nullable enable
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PoweredLightVisuals : byte
|
||||||
|
{
|
||||||
|
BulbState,
|
||||||
|
BulbColor,
|
||||||
|
Blinking
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PoweredLightState : byte
|
||||||
|
{
|
||||||
|
Empty,
|
||||||
|
On,
|
||||||
|
Off,
|
||||||
|
Broken,
|
||||||
|
Burned
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PoweredLightLayers : byte
|
||||||
|
{
|
||||||
|
Base
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,19 @@
|
|||||||
repeat: true
|
repeat: true
|
||||||
behavior: !type:DisarmAction { }
|
behavior: !type:DisarmAction { }
|
||||||
|
|
||||||
|
- type: action
|
||||||
|
actionType: GhostBoo
|
||||||
|
icon: Interface/Actions/scream.png
|
||||||
|
name: "Boo"
|
||||||
|
description: "Scare your crew members because of boredom!"
|
||||||
|
filters:
|
||||||
|
- ghost
|
||||||
|
behaviorType: Instant
|
||||||
|
behavior: !type:GhostBoo
|
||||||
|
radius: 3
|
||||||
|
cooldown: 120
|
||||||
|
maxTargets: 3
|
||||||
|
|
||||||
- type: action
|
- type: action
|
||||||
actionType: DebugInstant
|
actionType: DebugInstant
|
||||||
icon: Interface/Alerts/Human/human1.png
|
icon: Interface/Alerts/Human/human1.png
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
- type: EmergencyLight
|
- type: EmergencyLight
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Constructible/Lighting/emergency_light.rsi
|
sprite: Constructible/Lighting/emergency_light.rsi
|
||||||
state: emergency_light_off
|
layers:
|
||||||
|
- state: emergency_light_off
|
||||||
placement:
|
placement:
|
||||||
snap:
|
snap:
|
||||||
- Wallmount
|
- Wallmount
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
- type: LoopingSound
|
- type: LoopingSound
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Constructible/Lighting/light_tube.rsi
|
sprite: Constructible/Lighting/light_tube.rsi
|
||||||
|
layers:
|
||||||
|
- state: on
|
||||||
|
map: ["enum.PoweredLightLayers.Base"]
|
||||||
state: on
|
state: on
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
radius: 8
|
radius: 8
|
||||||
@@ -57,6 +60,10 @@
|
|||||||
- type: PoweredLight
|
- type: PoweredLight
|
||||||
bulb: Tube
|
bulb: Tube
|
||||||
- type: PowerReceiver
|
- type: PowerReceiver
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: PoweredLightVisualizer
|
||||||
|
blinkingSound: "/Audio/Machines/light_tube_on.ogg"
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: PoweredlightEmpty
|
id: PoweredlightEmpty
|
||||||
@@ -122,6 +129,9 @@
|
|||||||
- type: PoweredLight
|
- type: PoweredLight
|
||||||
bulb: Bulb
|
bulb: Bulb
|
||||||
- type: PowerReceiver
|
- type: PowerReceiver
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: PoweredLightVisualizer
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: PoweredSmallLightEmpty
|
id: PoweredSmallLightEmpty
|
||||||
|
|||||||
@@ -41,3 +41,6 @@
|
|||||||
baseSprintSpeed: 14
|
baseSprintSpeed: 14
|
||||||
baseWalkSpeed: 7
|
baseWalkSpeed: 7
|
||||||
- type: MovementIgnoreGravity
|
- type: MovementIgnoreGravity
|
||||||
|
- type: Actions
|
||||||
|
innateActions:
|
||||||
|
- GhostBoo
|
||||||
|
|||||||
Reference in New Issue
Block a user