Cherrypicks 5 (#440)

* Chances of triggering effects (#27056)

* electrocution

* slippery

* flashibg

* Update SlipperyComponent.cs

* Update SlipperySystem.cs

* Flash buff (#25730)

* flash buff

* oops!

* bool

* 3 -> 1.5 seconds

* okay fix

* sluth

* Flash overlay rework and bugfixes (#27369)

* fix mapping door access (#27784)

Co-authored-by: deltanedas <@deltanedas:kde.org>

* - fix: Errors.

* - fix: Incorporeal.

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
This commit is contained in:
Aviu00
2024-07-14 12:26:54 +00:00
committed by GitHub
parent 161b1a92e3
commit e56340dd39
25 changed files with 215 additions and 218 deletions

View File

@@ -179,7 +179,6 @@ namespace Content.Client.Entry
_parallaxManager.LoadDefaultParallax(); _parallaxManager.LoadDefaultParallax();
_overlayManager.AddOverlay(new SingularityOverlay()); _overlayManager.AddOverlay(new SingularityOverlay());
_overlayManager.AddOverlay(new FlashOverlay());
_overlayManager.AddOverlay(new RadiationPulseOverlay()); _overlayManager.AddOverlay(new RadiationPulseOverlay());
// _overlayManager.AddOverlay(new GrainOverlay()); // _overlayManager.AddOverlay(new GrainOverlay());
// _overlayManager.AddOverlay(new AtmOverlay()); // _overlayManager.AddOverlay(new AtmOverlay());

View File

@@ -1,12 +1,11 @@
using System.Numerics; using Content.Shared.Flash;
using Content.Shared.Flash.Components;
using Content.Shared.StatusEffect;
using Content.Client.Viewport; using Content.Client.Viewport;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.State; using Robust.Client.State;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@@ -17,66 +16,87 @@ namespace Content.Client.Flash
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClyde _displayManager = default!; [Dependency] private readonly IClyde _displayManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly StatusEffectsSystem _statusSys;
public override OverlaySpace Space => OverlaySpace.WorldSpace; public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _shader; private readonly ShaderInstance _shader;
private double _startTime = -1; public float PercentComplete = 0.0f;
private double _lastsFor = 1; public Texture? ScreenshotTexture;
private Texture? _screenshotTexture;
public FlashOverlay() public FlashOverlay()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").Instance().Duplicate(); _shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").InstanceUnique();
_statusSys = _entityManager.System<StatusEffectsSystem>();
} }
public void ReceiveFlash(double duration) protected override void FrameUpdate(FrameEventArgs args)
{
var playerEntity = _playerManager.LocalEntity;
if (playerEntity == null)
return;
if (!_entityManager.HasComponent<FlashedComponent>(playerEntity)
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return;
if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status))
return;
var curTime = _timing.CurTime;
var lastsFor = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
var timeDone = (float) (curTime - time.Value.Item1).TotalSeconds;
PercentComplete = timeDone / lastsFor;
}
public void ReceiveFlash()
{ {
if (_stateManager.CurrentState is IMainViewportState state) if (_stateManager.CurrentState is IMainViewportState state)
{ {
// take a screenshot
// note that the callback takes a while and ScreenshotTexture will be null the first few Draws
state.Viewport.Viewport.Screenshot(image => state.Viewport.Viewport.Screenshot(image =>
{ {
var rgba32Image = image.CloneAs<Rgba32>(SixLabors.ImageSharp.Configuration.Default); var rgba32Image = image.CloneAs<Rgba32>(SixLabors.ImageSharp.Configuration.Default);
_screenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); ScreenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image);
}); });
} }
}
_startTime = _gameTiming.CurTime.TotalSeconds; protected override bool BeforeDraw(in OverlayDrawArgs args)
_lastsFor = duration; {
if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp))
return false;
if (args.Viewport.Eye != eyeComp.Eye)
return false;
return PercentComplete < 1.0f;
} }
protected override void Draw(in OverlayDrawArgs args) protected override void Draw(in OverlayDrawArgs args)
{ {
if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp)) if (ScreenshotTexture == null)
return;
if (args.Viewport.Eye != eyeComp.Eye)
return;
var percentComplete = (float) ((_gameTiming.CurTime.TotalSeconds - _startTime) / _lastsFor);
if (percentComplete >= 1.0f)
return; return;
var worldHandle = args.WorldHandle; var worldHandle = args.WorldHandle;
_shader.SetParameter("percentComplete", PercentComplete);
worldHandle.UseShader(_shader); worldHandle.UseShader(_shader);
_shader.SetParameter("percentComplete", percentComplete); worldHandle.DrawTextureRectRegion(ScreenshotTexture, args.WorldBounds);
if (_screenshotTexture != null)
{
worldHandle.DrawTextureRectRegion(_screenshotTexture, args.WorldBounds);
}
worldHandle.UseShader(null); worldHandle.UseShader(null);
} }
protected override void DisposeBehavior() protected override void DisposeBehavior()
{ {
base.DisposeBehavior(); base.DisposeBehavior();
_screenshotTexture = null; ScreenshotTexture = null;
PercentComplete = 1.0f;
} }
} }
} }

View File

@@ -1,62 +1,67 @@
using Content.Shared.Flash; using Content.Shared.Flash;
using Content.Shared.Flash.Components;
using Content.Shared.StatusEffect;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.GameStates; using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Client.Flash namespace Content.Client.Flash;
public sealed class FlashSystem : SharedFlashSystem
{ {
public sealed class FlashSystem : SharedFlashSystem [Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
private FlashOverlay _overlay = default!;
public override void Initialize()
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!; base.Initialize();
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IOverlayManager _overlayManager = default!;
public override void Initialize() SubscribeLocalEvent<FlashedComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<FlashedComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<FlashedComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<FlashedComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<FlashedComponent, StatusEffectAddedEvent>(OnStatusAdded);
_overlay = new();
}
private void OnPlayerAttached(EntityUid uid, FlashedComponent component, LocalPlayerAttachedEvent args)
{
_overlayMan.AddOverlay(_overlay);
}
private void OnPlayerDetached(EntityUid uid, FlashedComponent component, LocalPlayerDetachedEvent args)
{
_overlay.PercentComplete = 1.0f;
_overlay.ScreenshotTexture = null;
_overlayMan.RemoveOverlay(_overlay);
}
private void OnInit(EntityUid uid, FlashedComponent component, ComponentInit args)
{
if (_player.LocalEntity == uid)
{ {
base.Initialize(); _overlayMan.AddOverlay(_overlay);
SubscribeLocalEvent<FlashableComponent, ComponentHandleState>(OnFlashableHandleState);
} }
}
private void OnFlashableHandleState(EntityUid uid, FlashableComponent component, ref ComponentHandleState args) private void OnShutdown(EntityUid uid, FlashedComponent component, ComponentShutdown args)
{
if (_player.LocalEntity == uid)
{ {
if (args.Current is not FlashableComponentState state) _overlay.PercentComplete = 1.0f;
return; _overlay.ScreenshotTexture = null;
_overlayMan.RemoveOverlay(_overlay);
}
}
// Yes, this code is awful. I'm just porting it to an entity system so don't blame me. private void OnStatusAdded(EntityUid uid, FlashedComponent component, StatusEffectAddedEvent args)
if (_playerManager.LocalEntity != uid) {
{ if (_player.LocalEntity == uid && args.Key == FlashedKey)
return; {
} _overlay.ReceiveFlash();
if (state.Time == default)
{
return;
}
// Few things here:
// 1. If a shorter duration flash is applied then don't do anything
// 2. If the client-side time is later than when the flash should've ended don't do anything
var currentTime = _gameTiming.CurTime.TotalSeconds;
var newEndTime = state.Time.TotalSeconds + state.Duration;
var currentEndTime = component.LastFlash.TotalSeconds + component.Duration;
if (currentEndTime > newEndTime)
{
return;
}
if (currentTime > newEndTime)
{
return;
}
component.LastFlash = state.Time;
component.Duration = state.Duration;
var overlay = _overlayManager.GetOverlay<FlashOverlay>();
overlay.ReceiveFlash(component.Duration);
} }
} }
} }

View File

@@ -92,4 +92,7 @@ public sealed partial class ElectrifiedComponent : Component
public EntityUid? Caster; public EntityUid? Caster;
// WD EDIT END // WD EDIT END
[DataField]
public float Probability = 1f;
} }

View File

@@ -215,6 +215,9 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
if (!IsPowered(uid, electrified, transform)) if (!IsPowered(uid, electrified, transform))
return false; return false;
if (!_random.Prob(electrified.Probability))
return false;
EnsureComp<ActivatedElectrifiedComponent>(uid); EnsureComp<ActivatedElectrifiedComponent>(uid);
_appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true); _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true);

View File

@@ -153,7 +153,7 @@ namespace Content.Server.Explosion.EntitySystems
private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args) private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args)
{ {
// TODO Make flash durations sane ffs. // TODO Make flash durations sane ffs.
_flashSystem.FlashArea(uid, args.User, component.Range, component.Duration * 1000f); _flashSystem.FlashArea(uid, args.User, component.Range, component.Duration * 1000f, probability: component.Probability);
args.Handled = true; args.Handled = true;
} }

View File

@@ -3,7 +3,6 @@ using Robust.Shared.Prototypes;
namespace Content.Server.Flash.Components; namespace Content.Server.Flash.Components;
// Also needed FlashableComponent on entity to work
[RegisterComponent, Access(typeof(DamagedByFlashingSystem))] [RegisterComponent, Access(typeof(DamagedByFlashingSystem))]
public sealed partial class DamagedByFlashingComponent : Component public sealed partial class DamagedByFlashingComponent : Component
{ {
@@ -11,5 +10,5 @@ public sealed partial class DamagedByFlashingComponent : Component
/// damage from flashing /// damage from flashing
/// </summary> /// </summary>
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)] [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier FlashDamage = new (); public DamageSpecifier FlashDamage = new();
} }

View File

@@ -1,10 +1,13 @@
namespace Content.Server.Flash.Components namespace Content.Server.Flash.Components;
/// <summary>
/// Makes the entity immune to being flashed.
/// When given to clothes in the "head", "eyes" or "mask" slot it protects the wearer.
/// </summary>
[RegisterComponent, Access(typeof(FlashSystem))]
public sealed partial class FlashImmunityComponent : Component
{ {
[RegisterComponent, Access(typeof(FlashSystem))] [ViewVariables(VVAccess.ReadWrite)]
public sealed partial class FlashImmunityComponent : Component [DataField("enabled")]
{ public bool Enabled { get; set; } = true;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("enabled")]
public bool Enabled { get; set; } = true;
}
} }

View File

@@ -9,17 +9,17 @@ using Content.Shared.Charges.Systems;
using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Flash; using Content.Shared.Flash;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Events;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.Physics;
using Content.Shared.Tag; using Content.Shared.Tag;
using Content.Shared.Traits.Assorted; using Content.Shared.Traits.Assorted;
using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Melee.Events;
using Content.Shared.StatusEffect;
using Content.Shared.Examine;
using Robust.Server.Audio; using Robust.Server.Audio;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Timing; using Robust.Shared.Random;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent; using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
namespace Content.Server.Flash namespace Content.Server.Flash
@@ -30,13 +30,14 @@ namespace Content.Server.Flash
[Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly SharedChargesSystem _charges = default!; [Dependency] private readonly SharedChargesSystem _charges = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly StunSystem _stun = default!; [Dependency] private readonly StunSystem _stun = default!;
[Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -44,7 +45,7 @@ namespace Content.Server.Flash
SubscribeLocalEvent<FlashComponent, MeleeHitEvent>(OnFlashMeleeHit); SubscribeLocalEvent<FlashComponent, MeleeHitEvent>(OnFlashMeleeHit);
// ran before toggling light for extra-bright lantern // ran before toggling light for extra-bright lantern
SubscribeLocalEvent<FlashComponent, UseInHandEvent>(OnFlashUseInHand, before: new []{ typeof(HandheldLightSystem) }); SubscribeLocalEvent<FlashComponent, UseInHandEvent>(OnFlashUseInHand, before: new[] { typeof(HandheldLightSystem) });
SubscribeLocalEvent<InventoryComponent, FlashAttemptEvent>(OnInventoryFlashAttempt); SubscribeLocalEvent<InventoryComponent, FlashAttemptEvent>(OnInventoryFlashAttempt);
SubscribeLocalEvent<FlashImmunityComponent, FlashAttemptEvent>(OnFlashImmunityFlashAttempt); SubscribeLocalEvent<FlashImmunityComponent, FlashAttemptEvent>(OnFlashImmunityFlashAttempt);
SubscribeLocalEvent<PermanentBlindnessComponent, FlashAttemptEvent>(OnPermanentBlindnessFlashAttempt); SubscribeLocalEvent<PermanentBlindnessComponent, FlashAttemptEvent>(OnPermanentBlindnessFlashAttempt);
@@ -63,7 +64,7 @@ namespace Content.Server.Flash
args.Handled = true; args.Handled = true;
foreach (var e in args.HitEntities) foreach (var e in args.HitEntities)
{ {
Flash(e, args.User, uid, comp.FlashDuration, comp.SlowTo, melee: true); Flash(e, args.User, uid, comp.FlashDuration, comp.SlowTo, melee: true, stunDuration: comp.MeleeStunDuration);
} }
} }
@@ -73,7 +74,7 @@ namespace Content.Server.Flash
return; return;
args.Handled = true; args.Handled = true;
FlashArea(uid, args.User, comp.Range, comp.AoeFlashDuration, comp.SlowTo, true); FlashArea(uid, args.User, comp.Range, comp.AoeFlashDuration, comp.SlowTo, true, comp.Probability);
} }
private bool UseFlash(EntityUid uid, FlashComponent comp, EntityUid user) private bool UseFlash(EntityUid uid, FlashComponent comp, EntityUid user)
@@ -112,18 +113,35 @@ namespace Content.Server.Flash
float flashDuration, float flashDuration,
float slowTo, float slowTo,
bool displayPopup = true, bool displayPopup = true,
FlashableComponent? flashable = null, bool melee = false,
bool melee = false) TimeSpan? stunDuration = null)
{ {
if (!Resolve(target, ref flashable, false))
return;
var attempt = new FlashAttemptEvent(target, user, used); var attempt = new FlashAttemptEvent(target, user, used);
RaiseLocalEvent(target, attempt, true); RaiseLocalEvent(target, attempt, true);
if (attempt.Cancelled) if (attempt.Cancelled)
return; return;
// don't paralyze, slowdown or convert to rev if the target is immune to flashes
if (!_statusEffectsSystem.TryAddStatusEffect<FlashedComponent>(target, FlashedKey, TimeSpan.FromSeconds(flashDuration / 1000f), true))
return;
if (stunDuration != null)
{
_stun.TryParalyze(target, stunDuration.Value, true);
}
else
{
_stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration / 1000f), true,
slowTo, slowTo);
}
if (displayPopup && user != null && target != user && Exists(user.Value))
{
_popup.PopupEntity(Loc.GetString("flash-component-user-blinds-you",
("user", Identity.Entity(user.Value, EntityManager))), target, target);
}
if (melee) if (melee)
{ {
var ev = new AfterFlashedEvent(target, user, used); var ev = new AfterFlashedEvent(target, user, used);
@@ -132,46 +150,34 @@ namespace Content.Server.Flash
if (used != null) if (used != null)
RaiseLocalEvent(used.Value, ref ev); RaiseLocalEvent(used.Value, ref ev);
} }
flashable.LastFlash = _timing.CurTime;
flashable.Duration = flashDuration / 1000f; // TODO: Make this sane...
Dirty(target, flashable);
_stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration/1000f), true,
slowTo, slowTo);
if (displayPopup && user != null && target != user && Exists(user.Value))
{
_popup.PopupEntity(Loc.GetString("flash-component-user-blinds-you",
("user", Identity.Entity(user.Value, EntityManager))), target, target);
}
} }
public void FlashArea(EntityUid source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, SoundSpecifier? sound = null) public void FlashArea(Entity<FlashComponent?> source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null)
{ {
var transform = EntityManager.GetComponent<TransformComponent>(source); var transform = Transform(source);
var mapPosition = _transform.GetMapCoordinates(transform); var mapPosition = _transform.GetMapCoordinates(transform);
var flashableQuery = GetEntityQuery<FlashableComponent>(); var statusEffectsQuery = GetEntityQuery<StatusEffectsComponent>();
var damagedByFlashingQuery = GetEntityQuery<DamagedByFlashingComponent>();
foreach (var entity in _entityLookup.GetEntitiesInRange(transform.Coordinates, range)) foreach (var entity in _entityLookup.GetEntitiesInRange(transform.Coordinates, range))
{ {
if (!flashableQuery.TryGetComponent(entity, out var flashable)) if (!_random.Prob(probability))
continue; continue;
// Is the entity affected by the flash either through status effects or by taking damage?
if (!statusEffectsQuery.HasComponent(entity) && !damagedByFlashingQuery.HasComponent(entity))
continue;
// Check for unobstructed entities while ignoring the mobs with flashable components. // Check for entites in view
if (!_interaction.InRangeUnobstructed(entity, mapPosition, range, flashable.CollisionGroup, (e) => e == source)) // put damagedByFlashingComponent in the predicate because shadow anomalies block vision.
if (!_examine.InRangeUnOccluded(entity, mapPosition, range, predicate: (e) => damagedByFlashingQuery.HasComponent(e)))
continue; continue;
// They shouldn't have flash removed in between right? // They shouldn't have flash removed in between right?
Flash(entity, user, source, duration, slowTo, displayPopup, flashableQuery.GetComponent(entity)); Flash(entity, user, source, duration, slowTo, displayPopup);
} }
if (sound != null) _audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f));
{
_audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f));
}
} }
private void OnInventoryFlashAttempt(EntityUid uid, InventoryComponent component, FlashAttemptEvent args) private void OnInventoryFlashAttempt(EntityUid uid, InventoryComponent component, FlashAttemptEvent args)
@@ -187,7 +193,7 @@ namespace Content.Server.Flash
private void OnFlashImmunityFlashAttempt(EntityUid uid, FlashImmunityComponent component, FlashAttemptEvent args) private void OnFlashImmunityFlashAttempt(EntityUid uid, FlashImmunityComponent component, FlashAttemptEvent args)
{ {
if(component.Enabled) if (component.Enabled)
args.Cancel(); args.Cancel();
} }
@@ -202,6 +208,10 @@ namespace Content.Server.Flash
} }
} }
/// <summary>
/// Called before a flash is used to check if the attempt is cancelled by blindness, items or FlashImmunityComponent.
/// Raised on the target hit by the flash, the user of the flash and the flash used.
/// </summary>
public sealed class FlashAttemptEvent : CancellableEntityEventArgs public sealed class FlashAttemptEvent : CancellableEntityEventArgs
{ {
public readonly EntityUid Target; public readonly EntityUid Target;
@@ -216,8 +226,8 @@ namespace Content.Server.Flash
} }
} }
/// <summary> /// <summary>
/// Called after a flash is used via melee on another person to check for rev conversion. /// Called after a flash is used via melee on another person to check for rev conversion.
/// Raised on the user of the flash, the target hit by the flash, and the flash used. /// Raised on the target hit by the flash, the user of the flash and the flash used.
/// </summary> /// </summary>
[ByRefEvent] [ByRefEvent]
public readonly struct AfterFlashedEvent public readonly struct AfterFlashedEvent
@@ -233,6 +243,4 @@ namespace Content.Server.Flash
Used = used; Used = used;
} }
} }
} }

View File

@@ -247,7 +247,6 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleCo
_npcFaction.AddFaction(ev.Target, RevolutionaryNpcFaction); _npcFaction.AddFaction(ev.Target, RevolutionaryNpcFaction);
var revComp = EnsureComp<RevolutionaryComponent>(ev.Target); var revComp = EnsureComp<RevolutionaryComponent>(ev.Target);
_stun.TryParalyze(ev.Target, comp.StunTime, true);
if (ev.User != null) if (ev.User != null)
{ {

View File

@@ -153,7 +153,7 @@ public sealed class AccessReaderSystem : EntitySystem
return IsAllowedInternal(access, stationKeys, reader); return IsAllowedInternal(access, stationKeys, reader);
if (!_containerSystem.TryGetContainer(target, reader.ContainerAccessProvider, out var container)) if (!_containerSystem.TryGetContainer(target, reader.ContainerAccessProvider, out var container))
return false; return Paused(target); // when mapping, containers with electronics arent spawned
foreach (var entity in container.ContainedEntities) foreach (var entity in container.ContainedEntities)
{ {

View File

@@ -1,6 +1,6 @@
using Content.Shared.Flash;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Flash.Components namespace Content.Shared.Flash.Components
{ {
@@ -12,6 +12,13 @@ namespace Content.Shared.Flash.Components
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public int FlashDuration { get; set; } = 5000; public int FlashDuration { get; set; } = 5000;
/// <summary>
/// How long a target is stunned when a melee flash is used.
/// If null, melee flashes will not stun at all
/// </summary>
[DataField]
public TimeSpan? MeleeStunDuration = TimeSpan.FromSeconds(1.5);
[DataField("range")] [DataField("range")]
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public float Range { get; set; } = 7f; public float Range { get; set; } = 7f;
@@ -32,5 +39,17 @@ namespace Content.Shared.Flash.Components
}; };
public bool Flashing; public bool Flashing;
[DataField]
public float Probability = 1f;
}
[Serializable, NetSerializable]
public enum FlashVisuals : byte
{
BaseLayer,
LightLayer,
Burnt,
Flashing,
} }
} }

View File

@@ -9,4 +9,5 @@ public sealed partial class FlashOnTriggerComponent : Component
{ {
[DataField] public float Range = 1.0f; [DataField] public float Range = 1.0f;
[DataField] public float Duration = 8.0f; [DataField] public float Duration = 8.0f;
[DataField] public float Probability = 1.0f;
} }

View File

@@ -0,0 +1,9 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Flash.Components;
/// <summary>
/// Exists for use as a status effect. Adds a shader to the client that obstructs vision.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class FlashedComponent : Component { }

View File

@@ -1,40 +0,0 @@
using Content.Shared.Physics;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Flash
{
[RegisterComponent, NetworkedComponent]
public sealed partial class FlashableComponent : Component
{
public float Duration;
public TimeSpan LastFlash;
[DataField]
public CollisionGroup CollisionGroup = CollisionGroup.Opaque;
public override bool SendOnlyToOwner => true;
}
[Serializable, NetSerializable]
public sealed class FlashableComponentState : ComponentState
{
public float Duration { get; }
public TimeSpan Time { get; }
public FlashableComponentState(float duration, TimeSpan time)
{
Duration = duration;
Time = time;
}
}
[Serializable, NetSerializable]
public enum FlashVisuals : byte
{
BaseLayer,
LightLayer,
Burnt,
Flashing,
}
}

View File

@@ -1,19 +1,10 @@
using Robust.Shared.GameStates; using Content.Shared.StatusEffect;
namespace Content.Shared.Flash namespace Content.Shared.Flash
{ {
public abstract class SharedFlashSystem : EntitySystem public abstract class SharedFlashSystem : EntitySystem
{ {
public override void Initialize() [ValidatePrototypeId<StatusEffectPrototype>]
{ public const string FlashedKey = "Flashed";
base.Initialize();
SubscribeLocalEvent<FlashableComponent, ComponentGetState>(OnFlashableGetState);
}
private static void OnFlashableGetState(EntityUid uid, FlashableComponent component, ref ComponentGetState args)
{
args.State = new FlashableComponentState(component.Duration, component.LastFlash);
}
} }
} }

View File

@@ -125,6 +125,7 @@
- Stun - Stun
- KnockedDown - KnockedDown
- SlowedDown - SlowedDown
- Flashed
- type: TypingIndicator - type: TypingIndicator
proto: robot proto: robot
- type: Speech - type: Speech
@@ -143,7 +144,6 @@
locked: true locked: true
- type: ActivatableUIRequiresLock - type: ActivatableUIRequiresLock
- type: LockedWiresPanel - type: LockedWiresPanel
- type: Flashable
- type: Damageable - type: Damageable
damageContainer: Silicon damageContainer: Silicon
- type: Destructible - type: Destructible

View File

@@ -48,7 +48,6 @@
sprite: Mobs/Effects/onfire.rsi sprite: Mobs/Effects/onfire.rsi
normalState: Generic_mob_burning normalState: Generic_mob_burning
- type: Climbing - type: Climbing
- type: Flashable
- type: NameIdentifier - type: NameIdentifier
group: GenericNumber group: GenericNumber

View File

@@ -780,7 +780,6 @@
amount: 3 amount: 3
- id: DrinkTequilaBottleFull - id: DrinkTequilaBottleFull
amount: 1 amount: 1
- type: Flashable
- type: Tag - type: Tag
tags: tags:
- CannotSuicide - CannotSuicide
@@ -807,7 +806,6 @@
# name: ghost-role-information-tropico-name # name: ghost-role-information-tropico-name
# description: ghost-role-information-tropico-description # description: ghost-role-information-tropico-description
# - type: GhostTakeoverAvailable # - type: GhostTakeoverAvailable
# - type: Flashable
- type: Tag - type: Tag
tags: tags:
- VimPilot - VimPilot
@@ -861,7 +859,6 @@
raffle: raffle:
settings: short settings: short
- type: GhostTakeoverAvailable - type: GhostTakeoverAvailable
- type: Flashable
- type: Tag - type: Tag
tags: tags:
- CannotSuicide - CannotSuicide

View File

@@ -28,6 +28,7 @@
- Pacified - Pacified
- RadiationProtection - RadiationProtection
- Drowsiness - Drowsiness
- Flashed
- type: Buckle - type: Buckle
- type: StandingState - type: StandingState
- type: Tag - type: Tag
@@ -108,6 +109,7 @@
- StaminaModifier - StaminaModifier
- RadiationProtection - RadiationProtection
- Drowsiness - Drowsiness
- Flashed
- type: Bloodstream - type: Bloodstream
bloodMaxVolume: 150 bloodMaxVolume: 150
- type: MobPrice - type: MobPrice

View File

@@ -119,7 +119,6 @@
thresholds: thresholds:
0: Alive 0: Alive
60: Dead 60: Dead
- type: Flashable
- type: NoSlip - type: NoSlip
- type: StatusEffects - type: StatusEffects
allowed: allowed:

View File

@@ -146,6 +146,7 @@
- StaminaModifier - StaminaModifier
- RadiationProtection - RadiationProtection
- Drowsiness - Drowsiness
- Flashed
- type: Reflect - type: Reflect
enabled: false enabled: false
reflectProb: 0 reflectProb: 0
@@ -271,7 +272,6 @@
id: BaseMobSpeciesOrganic id: BaseMobSpeciesOrganic
abstract: true abstract: true
components: components:
- type: Flashable
- type: Barotrauma - type: Barotrauma
damage: damage:
types: types:
@@ -286,26 +286,6 @@
Heat: -0.07 Heat: -0.07
groups: groups:
Brute: -0.07 Brute: -0.07
# Organs
- type: StatusEffects
allowed:
- Stun
- KnockedDown
- SlowedDown
- Stutter
- BloodLoss
- SeeingRainbows
- Electrocution
- ForcedSleep
- TemporaryBlindness
- Drunk
- SlurredSpeech
- RatvarianLanguage
- PressureImmunity
- Muted
- Pacified
- StaminaModifier
- Incorporeal
- type: Blindable - type: Blindable
# Other # Other
- type: Temperature - type: Temperature

View File

@@ -15,9 +15,6 @@
path: /Audio/Items/hiss.ogg path: /Audio/Items/hiss.ogg
params: params:
variation: 0.08 variation: 0.08
- type: Flashable
collisionGroup:
- None
- type: DamagedByFlashing - type: DamagedByFlashing
flashDamage: flashDamage:
types: types:

View File

@@ -1,4 +1,4 @@
# Status effect prototypes. # Status effect prototypes.
# Holds no actual logic, just some basic data about the effect. # Holds no actual logic, just some basic data about the effect.
- type: statusEffect - type: statusEffect
@@ -74,9 +74,13 @@
- type: statusEffect - type: statusEffect
id: Drowsiness #blurs your vision and makes you randomly fall asleep id: Drowsiness #blurs your vision and makes you randomly fall asleep
- type: statusEffect
id: Flashed
# WD EDIT # WD EDIT
- type: statusEffect - type: statusEffect
id: Incorporeal id: Incorporeal
alwaysAllowed: true
- type: statusEffect - type: statusEffect
id: BloodLoss id: BloodLoss

View File

@@ -11,7 +11,7 @@ void fragment() {
highp vec4 textureMix = mix(tex1, tex2, 0.5); highp vec4 textureMix = mix(tex1, tex2, 0.5);
// Gradually mixes between the texture mix and a full-white texture, causing the "blinding" effect // Gradually mixes between the texture mix and a full-black texture, causing the "blinding" effect
highp vec4 mixed = mix(vec4(0.0, 0.0, 0.0, 1.0), textureMix, percentComplete); highp vec4 mixed = mix(vec4(0.0, 0.0, 0.0, 1.0), textureMix, percentComplete);
COLOR = vec4(mixed.rgb, remaining); COLOR = vec4(mixed.rgb, remaining);