[Fix] Парад фиксов (#1110)

* fix: thermals and night vision now work

* fix: it has to be this way

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* fix: I hate the way they are separated

* fix: now cult actions close examine menu (#1046)

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* fix: railins and some other things now dont snap to south upon being built (#1029)

* fix: who did this translation wtf

* fix: assball bat can now wideswing (#1030)

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* fix: spend flares are actually spent now (#959)

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* fix: made part exchange system a bit less shitty

I really have no time or interest in it to rewrite it completely rn

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* fix: fixed cult factories timers being broken

Also fixed them being openable by anyone.

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>

* Apply suggestions from code review

Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: RedFoxIV <38788538+RedFoxIV@users.noreply.github.com>

---------

Signed-off-by: Remuchi <RemuchiOfficial@gmail.com>
Co-authored-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: RedFoxIV <38788538+RedFoxIV@users.noreply.github.com>
This commit is contained in:
Remuchi
2026-04-16 14:53:08 +07:00
committed by GitHub
parent 5d329d81aa
commit 4c8c415eed
29 changed files with 397 additions and 424 deletions

View File

@@ -1,48 +0,0 @@
using System.Numerics;
using Content.Shared.Overlays.Switchable;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
namespace Content.Client.Overlays.Switchable;
public sealed class BaseSwitchableOverlay<TComp> : Overlay where TComp : SwitchableOverlayComponent
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _shader;
public TComp? Comp = null;
public bool IsActive = true;
public BaseSwitchableOverlay()
{
IoCManager.InjectDependencies(this);
_shader = _prototype.Index<ShaderPrototype>("NightVision").InstanceUnique();
}
protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture is null || Comp is null || !IsActive)
return;
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_shader.SetParameter("tint", Comp.Tint);
_shader.SetParameter("luminance_threshold", Comp.Strength);
_shader.SetParameter("noise_amount", Comp.Noise);
var worldHandle = args.WorldHandle;
var accumulator = Math.Clamp(Comp.PulseAccumulator, 0f, Comp.PulseTime);
var alpha = Comp.PulseTime <= 0f ? 1f : float.Lerp(1f, 0f, accumulator / Comp.PulseTime);
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(_shader);
worldHandle.DrawRect(args.WorldBounds, Comp.Color.WithAlpha(alpha));
worldHandle.UseShader(null);
}
}

View File

@@ -0,0 +1,73 @@
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Vector3 = Robust.Shared.Maths.Vector3;
namespace Content.Client.Overlays.Switchable;
public sealed class NightVisionOverlay : Overlay
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public bool IsActive = true;
private readonly ProtoId<ShaderPrototype> _shaderProto = new("NightVision");
private readonly ShaderInstance _shader;
private Vector3 _tint = Vector3.One * 0.5f;
private float _strength = 1;
private float _noise = 0.5f;
private Color _color = Color.Red;
private float _pulseTime;
private float _timeAccumulator;
public NightVisionOverlay()
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index(_shaderProto).InstanceUnique();
}
protected override void FrameUpdate(FrameEventArgs args)
{
_timeAccumulator += args.DeltaSeconds;
if (_timeAccumulator >= _pulseTime)
_timeAccumulator = 0;
}
public void SetParams(Vector3 tint, float strength, float noise, Color color, float pulseTime)
{
_tint = tint;
_strength = strength;
_noise = noise;
_color = color;
_pulseTime = pulseTime;
}
protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture is null || !IsActive)
return;
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_shader.SetParameter("tint", _tint);
_shader.SetParameter("luminance_threshold", _strength);
_shader.SetParameter("noise_amount", _noise);
var worldHandle = args.WorldHandle;
var alpha = _pulseTime <= 0f
? 1f
: float.Lerp(1f, 0f, _timeAccumulator / _pulseTime);
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(_shader);
worldHandle.DrawRect(args.WorldBounds, _color.WithAlpha(alpha));
worldHandle.UseShader(null);
}
}

View File

@@ -1,7 +1,7 @@
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Overlays.Switchable;
using Robust.Client.Graphics;
using Robust.Shared.Timing;
namespace Content.Client.Overlays.Switchable;
@@ -9,8 +9,9 @@ public sealed class NightVisionSystem : EquipmentHudSystem<NightVisionComponent>
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly ILightManager _lightManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private BaseSwitchableOverlay<NightVisionComponent> _overlay = default!;
private NightVisionOverlay _overlay = default!;
public override void Initialize()
{
@@ -18,40 +19,30 @@ public sealed class NightVisionSystem : EquipmentHudSystem<NightVisionComponent>
SubscribeLocalEvent<NightVisionComponent, SwitchableOverlayToggledEvent>(OnToggle);
_overlay = new BaseSwitchableOverlay<NightVisionComponent>();
_overlay = new()
{
IsActive = false
};
_overlayMan.AddOverlay(_overlay);
}
protected override void OnRefreshComponentHud(
Entity<NightVisionComponent> ent,
ref RefreshEquipmentHudEvent<NightVisionComponent> args
)
public override void Shutdown()
{
if (ent.Comp.IsEquipment)
return;
base.OnRefreshComponentHud(ent, ref args);
}
protected override void OnRefreshEquipmentHud(
Entity<NightVisionComponent> ent,
ref InventoryRelayedEvent<RefreshEquipmentHudEvent<NightVisionComponent>> args
)
{
if (!ent.Comp.IsEquipment)
return;
base.OnRefreshEquipmentHud(ent, ref args);
base.Shutdown();
_overlayMan.RemoveOverlay(_overlay);
}
private void OnToggle(Entity<NightVisionComponent> ent, ref SwitchableOverlayToggledEvent args)
{
if (!_gameTiming.IsFirstTimePredicted)
return;
_overlay.SetParams(ent.Comp.Tint, ent.Comp.Strength, ent.Comp.Noise, ent.Comp.Color, ent.Comp.PulseTime);
RefreshOverlay();
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<NightVisionComponent> args)
{
base.UpdateInternal(args);
var active = false;
NightVisionComponent? nvComp = null;
foreach (var comp in args.Components)
@@ -60,11 +51,10 @@ public sealed class NightVisionSystem : EquipmentHudSystem<NightVisionComponent>
active = true;
else
continue;
if (comp.DrawOverlay)
{
if (nvComp == null)
nvComp = comp;
else if (nvComp.PulseTime > 0f && comp.PulseTime <= 0f)
if (nvComp == null || nvComp.PulseTime > 0f && comp.PulseTime <= 0f)
nvComp = comp;
}
@@ -73,37 +63,13 @@ public sealed class NightVisionSystem : EquipmentHudSystem<NightVisionComponent>
}
UpdateNightVision(active);
UpdateOverlay(nvComp);
}
protected override void DeactivateInternal()
{
base.DeactivateInternal();
UpdateNightVision(false);
UpdateOverlay(null);
}
protected override void DeactivateInternal() => UpdateNightVision(false);
private void UpdateNightVision(bool active)
{
_lightManager.DrawLighting = !active;
}
private void UpdateOverlay(NightVisionComponent? nvComp)
{
_overlay.Comp = nvComp;
switch (nvComp)
{
case not null when !_overlayMan.HasOverlay<BaseSwitchableOverlay<NightVisionComponent>>():
_overlayMan.AddOverlay(_overlay);
break;
case null:
_overlayMan.RemoveOverlay(_overlay);
break;
}
if (_overlayMan.TryGetOverlay<BaseSwitchableOverlay<ThermalVisionComponent>>(out var overlay))
overlay.IsActive = nvComp == null;
_overlay.IsActive = active;
}
}

View File

@@ -1,16 +1,16 @@
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Overlays.Switchable;
using Robust.Client.Graphics;
using Robust.Shared.Timing;
namespace Content.Client.Overlays.Switchable;
public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionComponent>
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private ThermalVisionOverlay _thermalOverlay = default!;
private BaseSwitchableOverlay<ThermalVisionComponent> _overlay = default!;
public override void Initialize()
{
@@ -18,35 +18,13 @@ public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionCompon
SubscribeLocalEvent<ThermalVisionComponent, SwitchableOverlayToggledEvent>(OnToggle);
_thermalOverlay = new ThermalVisionOverlay();
_overlay = new BaseSwitchableOverlay<ThermalVisionComponent>();
}
protected override void OnRefreshComponentHud(
Entity<ThermalVisionComponent> ent,
ref RefreshEquipmentHudEvent<ThermalVisionComponent> args
)
{
if (ent.Comp.IsEquipment)
return;
base.OnRefreshComponentHud(ent, ref args);
}
protected override void OnRefreshEquipmentHud(
Entity<ThermalVisionComponent> ent,
ref InventoryRelayedEvent<RefreshEquipmentHudEvent<ThermalVisionComponent>> args
)
{
if (!ent.Comp.IsEquipment)
return;
base.OnRefreshEquipmentHud(ent, ref args);
_thermalOverlay = new();
}
private void OnToggle(Entity<ThermalVisionComponent> ent, ref SwitchableOverlayToggledEvent args)
{
RefreshOverlay();
if (_gameTiming.IsFirstTimePredicted)
RefreshOverlay();
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ThermalVisionComponent> args)
@@ -70,7 +48,6 @@ public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionCompon
}
UpdateThermalOverlay(tvComp, lightRadius);
UpdateOverlay(tvComp);
}
protected override void DeactivateInternal()
@@ -78,7 +55,6 @@ public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionCompon
base.DeactivateInternal();
_thermalOverlay.ResetLight(false);
UpdateOverlay(null);
UpdateThermalOverlay(null, 0f);
}
@@ -99,21 +75,4 @@ public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionCompon
}
}
private void UpdateOverlay(ThermalVisionComponent? tvComp)
{
_overlay.Comp = tvComp;
switch (tvComp)
{
case { DrawOverlay: true } when !_overlayMan.HasOverlay<BaseSwitchableOverlay<ThermalVisionComponent>>():
_overlayMan.AddOverlay(_overlay);
break;
case null or { DrawOverlay: false }:
_overlayMan.RemoveOverlay(_overlay);
break;
}
// Night vision overlay is prioritized
_overlay.IsActive = !_overlayMan.HasOverlay<BaseSwitchableOverlay<NightVisionComponent>>();
}
}

View File

@@ -1,5 +1,4 @@
using Content.Client._White.RadialSelector;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Controls;
using Content.Shared.RadialSelector;
using JetBrains.Annotations;
using Robust.Client.Graphics;

View File

@@ -11,8 +11,9 @@ using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
// ReSharper disable InconsistentNaming
// White Dream Code but moved to general folder for consistency
namespace Content.Client._White.RadialSelector;
namespace Content.Client.RadialSelector;
public abstract class BasedRadialSelectorMenuBUI : BoundUserInterface
{

View File

@@ -3,8 +3,9 @@ using Content.Shared._White.RadialSelector;
using JetBrains.Annotations;
// ReSharper disable InconsistentNaming
// White Dream Code but moved to general folder for consistency
namespace Content.Client._White.RadialSelector;
namespace Content.Client.RadialSelector;
[UsedImplicitly]
public sealed class TrackedRadialSelectorMenuBUI(EntityUid owner, Enum uiKey) : BasedRadialSelectorMenuBUI(owner, uiKey)

View File

@@ -376,6 +376,11 @@ namespace Content.Server.Administration.Managers
private async void LoginAdminMaybe(ICommonSession session)
{
// Not an admin.
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (session is null)
return;
var adminDat = await LoadAdminData(session);
if (adminDat == null)
{

View File

@@ -1,3 +1,5 @@
// Updated by WhiteDream by fckmoth
using System.Linq;
using Content.Server.Construction.Components;
using Content.Server.Storage.EntitySystems;
@@ -30,46 +32,87 @@ public sealed class PartExchangerSystem : EntitySystem
SubscribeLocalEvent<PartExchangerComponent, ExchangerDoAfterEvent>(OnDoAfter);
}
private void OnDoAfter(EntityUid uid, PartExchangerComponent component, DoAfterEvent args)
private void OnAfterInteract(Entity<PartExchangerComponent> ent, ref AfterInteractEvent args)
{
if (args.Cancelled)
if (ent.Comp.DoDistanceCheck && !args.CanReach || !args.Target.HasValue
|| !HasComp<MachineComponent>(args.Target) && !HasComp<MachineFrameComponent>(args.Target))
{
component.AudioStream = _audio.Stop(component.AudioStream);
args.Handled = false;
return;
}
if (args.Handled || args.Args.Target == null || !TryComp<StorageComponent>(uid, out var storage))
if (TryComp<WiresPanelComponent>(args.Target, out var panel) && !panel.Open)
{
_popup.PopupEntity(Loc.GetString("construction-step-condition-wire-panel-open"), args.Target.Value);
args.Handled = false;
return;
}
if (!TryComp<StorageComponent>(ent, out var storage) || storage.Container.Count == 0)
{
_popup.PopupEntity(Loc.GetString("rped-container-empty"), args.Target.Value);
args.Handled = false;
return;
}
args.Handled = true;
var doAfter = new DoAfterArgs(
EntityManager,
args.User,
ent.Comp.ExchangeDuration,
new ExchangerDoAfterEvent(),
ent,
target: args.Target,
used: ent)
{
BreakOnDamage = true,
BreakOnMove = true
};
_doAfter.TryStartDoAfter(doAfter);
}
private void OnDoAfter(EntityUid uid, PartExchangerComponent component, DoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Target == null ||
!TryComp<StorageComponent>(uid, out var storage))
return;
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var machineParts = new List<Entity<MachinePartComponent>>();
foreach (var item in storage.Container.ContainedEntities) //get parts in RPED
{
if (machinePartQuery.TryGetComponent(item, out var part))
if (TryComp(item, out MachinePartComponent? part))
machineParts.Add((item, part));
}
TryExchangeMachineParts(args.Args.Target.Value, uid, machineParts);
TryConstructMachineParts(args.Args.Target.Value, uid, machineParts);
if (machineParts.Count == 0)
return;
args.Handled = true;
if (TryExchangeMachineParts(args.Args.Target.Value, uid, machineParts) ||
TryConstructMachineParts(args.Args.Target.Value, uid, machineParts))
component.AudioStream = _audio.PlayPvs(component.ExchangeSound, uid)?.Entity;
}
private void TryExchangeMachineParts(EntityUid uid, EntityUid storageUid, List<Entity<MachinePartComponent>> machineParts)
private bool TryExchangeMachineParts(
EntityUid uid,
EntityUid storageUid,
List<Entity<MachinePartComponent>> machineParts
)
{
if (!TryComp<MachineComponent>(uid, out var machine))
return;
return false;
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var board = machine.BoardContainer.ContainedEntities.FirstOrNull();
if (!TryComp<MachineBoardComponent>(board, out var macBoardComp))
return;
return false;
foreach (var item in new ValueList<EntityUid>(machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
//clone so don't modify during enumeration
foreach (var item in new ValueList<EntityUid>(machine.PartContainer.ContainedEntities))
{
if (!machinePartQuery.TryGetComponent(item, out var part))
if (!TryComp(item, out MachinePartComponent? part))
continue;
machineParts.Add((item, part));
@@ -77,6 +120,7 @@ public sealed class PartExchangerSystem : EntitySystem
}
machineParts.Sort((x, y) => x.Comp.Rating.CompareTo(y.Comp.Rating));
machineParts.Reverse();
var updatedParts = new List<Entity<MachinePartComponent>>();
foreach (var (machinePartId, amount) in macBoardComp.MachinePartRequirements)
@@ -96,22 +140,28 @@ public sealed class PartExchangerSystem : EntitySystem
_storage.Insert(storageUid, unused, out _, playSound: false);
_construction.RefreshParts(uid, machine);
return true;
}
private void TryConstructMachineParts(EntityUid uid, EntityUid storageEnt, List<Entity<MachinePartComponent>> machineParts)
private bool TryConstructMachineParts(
EntityUid uid,
EntityUid storageEnt,
List<Entity<MachinePartComponent>> machineParts
)
{
if (!TryComp<MachineFrameComponent>(uid, out var machine))
return;
return false;
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var board = machine.BoardContainer.ContainedEntities.FirstOrNull();
if (!TryComp<MachineBoardComponent>(board, out var macBoardComp))
return;
return false;
foreach (var item in new ValueList<EntityUid>(machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
foreach (var item in
new ValueList<EntityUid>(
machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
{
if (!machinePartQuery.TryGetComponent(item, out var part))
if (!TryComp(item, out MachinePartComponent? part))
continue;
machineParts.Add((item, part));
@@ -128,49 +178,20 @@ public sealed class PartExchangerSystem : EntitySystem
updatedParts.AddRange(target);
}
foreach (var pair in updatedParts)
foreach (var part in updatedParts)
{
if (!machine.MachinePartRequirements.ContainsKey(pair.Comp.PartType))
if (!machine.MachinePartRequirements.ContainsKey(part.Comp.PartType))
continue;
_container.Insert(pair.Owner, machine.PartContainer);
machine.MachinePartProgress[pair.Comp.PartType]++;
machineParts.Remove(pair);
_container.Insert(part.Owner, machine.PartContainer);
machine.MachinePartProgress[part.Comp.PartType]++;
machineParts.Remove(part);
}
//put the unused parts back into rped. (this also does the "swapping")
foreach (var (unused, _) in machineParts)
_storage.Insert(storageEnt, unused, out _, playSound: false);
}
private void OnAfterInteract(EntityUid uid, PartExchangerComponent component, AfterInteractEvent args)
{
if (component.DoDistanceCheck && !args.CanReach
|| args.Target == null
|| !HasComp<MachineComponent>(args.Target) && !HasComp<MachineFrameComponent>(args.Target))
return;
if (TryComp<WiresPanelComponent>(args.Target, out var panel) && !panel.Open)
{
_popup.PopupEntity(Loc.GetString("construction-step-condition-wire-panel-open"), args.Target.Value);
return;
}
component.AudioStream = _audio.PlayPvs(component.ExchangeSound, uid)?.Entity;
var doAfter = new DoAfterArgs(
EntityManager,
args.User,
component.ExchangeDuration,
new ExchangerDoAfterEvent(),
uid,
target: args.Target,
used: uid)
{
BreakOnDamage = true,
BreakOnMove = true
};
_doAfter.TryStartDoAfter(doAfter);
return true;
}
}

View File

@@ -1,3 +1,5 @@
// Updated by White Dream by FckMoth
using Content.Server.Light.Components;
using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems;
@@ -7,200 +9,181 @@ using Content.Shared.Light.Components;
using Content.Shared.Tag;
using Content.Shared.Temperature;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Ranged.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Utility;
namespace Content.Server.Light.EntitySystems
namespace Content.Server.Light.EntitySystems;
[UsedImplicitly]
public sealed class ExpendableLightSystem : EntitySystem
{
[UsedImplicitly]
public sealed class ExpendableLightSystem : EntitySystem
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
public override void Initialize()
{
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
base.Initialize();
public override void Initialize()
SubscribeLocalEvent<ExpendableLightComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ExpendableLightComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<ExpendableLightComponent, GetVerbsEvent<ActivationVerb>>(OnGetVerbs);
}
public override void Update(float frameTime)
{
var query = EntityQueryEnumerator<ActiveExpendableLightComponent>();
while (query.MoveNext(out var uid, out _))
{
base.Initialize();
SubscribeLocalEvent<ExpendableLightComponent, ComponentInit>(OnExpLightInit);
SubscribeLocalEvent<ExpendableLightComponent, UseInHandEvent>(OnExpLightUse);
SubscribeLocalEvent<ExpendableLightComponent, GetVerbsEvent<ActivationVerb>>(AddIgniteVerb);
}
public override void Update(float frameTime)
{
var query = EntityQueryEnumerator<ActiveExpendableLightComponent>();
while (query.MoveNext(out var uid, out var _))
if (!TryComp(uid, out ExpendableLightComponent? light))
{
if (!TryComp(uid, out ExpendableLightComponent? light))
{
RemCompDeferred<ActiveExpendableLightComponent>(uid);
continue;
}
UpdateLight((uid, light), frameTime);
}
}
private void UpdateLight(Entity<ExpendableLightComponent> ent, float frameTime)
{
var component = ent.Comp;
component.StateExpiryTime -= frameTime;
if (component.StateExpiryTime <= 0f)
{
switch (component.CurrentState)
{
case ExpendableLightState.Lit:
component.CurrentState = ExpendableLightState.Fading;
component.StateExpiryTime = component.FadeOutDuration;
UpdateVisualizer(ent);
break;
default:
case ExpendableLightState.Fading:
component.CurrentState = ExpendableLightState.Dead;
var meta = MetaData(ent);
_metaData.SetEntityName(ent, Loc.GetString(component.SpentName), meta);
_metaData.SetEntityDescription(ent, Loc.GetString(component.SpentDesc), meta);
_tagSystem.AddTag(ent, "Trash");
UpdateSounds(ent);
UpdateVisualizer(ent);
if (TryComp<ItemComponent>(ent, out var item))
{
_item.SetHeldPrefix(ent, "unlit", component: item);
}
RemCompDeferred<ActiveExpendableLightComponent>(ent);
break;
}
}
}
/// <summary>
/// Enables the light if it is not active. Once active it cannot be turned off.
/// </summary>
public bool TryActivate(Entity<ExpendableLightComponent> ent)
{
var component = ent.Comp;
if (!component.Activated && component.CurrentState == ExpendableLightState.BrandNew)
{
if (TryComp<ItemComponent>(ent, out var item))
{
_item.SetHeldPrefix(ent, "lit", component: item);
}
var isHotEvent = new IsHotEvent() { IsHot = true };
RaiseLocalEvent(ent, isHotEvent);
component.CurrentState = ExpendableLightState.Lit;
component.StateExpiryTime = component.GlowDuration;
UpdateSounds(ent);
UpdateVisualizer(ent);
EnsureComp<ActiveExpendableLightComponent>(ent);
return true;
RemCompDeferred<ActiveExpendableLightComponent>(uid);
continue;
}
return false;
}
light.StateExpiryTime -= frameTime;
if (light.StateExpiryTime > 0f)
continue;
private void UpdateVisualizer(Entity<ExpendableLightComponent> ent, AppearanceComponent? appearance = null)
{
var component = ent.Comp;
if (!Resolve(ent, ref appearance, false))
return;
_appearance.SetData(ent, ExpendableLightVisuals.State, component.CurrentState, appearance);
switch (component.CurrentState)
{
case ExpendableLightState.Lit:
_appearance.SetData(ent, ExpendableLightVisuals.Behavior, component.TurnOnBehaviourID, appearance);
break;
case ExpendableLightState.Fading:
_appearance.SetData(ent, ExpendableLightVisuals.Behavior, component.FadeOutBehaviourID, appearance);
break;
case ExpendableLightState.Dead:
_appearance.SetData(ent, ExpendableLightVisuals.Behavior, string.Empty, appearance);
var isHotEvent = new IsHotEvent() { IsHot = true };
RaiseLocalEvent(ent, isHotEvent);
break;
}
}
private void UpdateSounds(Entity<ExpendableLightComponent> ent)
{
var component = ent.Comp;
switch (component.CurrentState)
{
case ExpendableLightState.Lit:
_audio.PlayPvs(component.LitSound, ent);
break;
case ExpendableLightState.Fading:
break;
default:
_audio.PlayPvs(component.DieSound, ent);
break;
}
if (TryComp<ClothingComponent>(ent, out var clothing))
{
_clothing.SetEquippedPrefix(ent, component.Activated ? "Activated" : string.Empty, clothing);
}
}
private void OnExpLightInit(EntityUid uid, ExpendableLightComponent component, ComponentInit args)
{
if (TryComp<ItemComponent>(uid, out var item))
{
_item.SetHeldPrefix(uid, "unlit", component: item);
}
component.CurrentState = ExpendableLightState.BrandNew;
EntityManager.EnsureComponent<PointLightComponent>(uid);
}
private void OnExpLightUse(Entity<ExpendableLightComponent> ent, ref UseInHandEvent args)
{
if (args.Handled)
return;
if (TryActivate(ent))
args.Handled = true;
}
private void AddIgniteVerb(Entity<ExpendableLightComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
if (ent.Comp.CurrentState != ExpendableLightState.BrandNew)
return;
// Ignite the flare or make the glowstick glow.
// Also hot damn, those are some shitty glowsticks, we need to get a refund.
ActivationVerb verb = new()
{
Text = Loc.GetString("expendable-light-start-verb"),
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/light.svg.192dpi.png")),
Act = () => TryActivate(ent)
};
args.Verbs.Add(verb);
UpdateLight((uid, light));
}
}
private void OnInit(EntityUid uid, ExpendableLightComponent component, ComponentInit args)
{
if (TryComp<ItemComponent>(uid, out var item))
_item.SetHeldPrefix(uid, "unlit", component: item);
component.CurrentState = ExpendableLightState.BrandNew;
EntityManager.EnsureComponent<PointLightComponent>(uid);
}
private void OnUseInHand(Entity<ExpendableLightComponent> ent, ref UseInHandEvent args)
{
if (!args.Handled && TryActivate(ent))
args.Handled = true;
}
private void OnGetVerbs(Entity<ExpendableLightComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract || ent.Comp.CurrentState != ExpendableLightState.BrandNew)
return;
// Ignite the flare or make the glowstick glow.
// Also hot damn, those are some shitty glowsticks, we need to get a refund.
ActivationVerb verb = new()
{
Text = Loc.GetString("expendable-light-start-verb"),
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/light.svg.192dpi.png")),
Act = () => TryActivate(ent)
};
args.Verbs.Add(verb);
}
/// <summary>
/// Enables the light if it is not active. Once active it cannot be turned off.
/// </summary>
[UsedImplicitly]
public bool TryActivate(Entity<ExpendableLightComponent> ent)
{
var component = ent.Comp;
if (component is not { Activated: false, CurrentState: ExpendableLightState.BrandNew, })
return false;
if (TryComp(ent, out ItemComponent? item))
_item.SetHeldPrefix(ent, "lit", component: item);
var isHotEvent = new IsHotEvent { IsHot = true, };
RaiseLocalEvent(ent, isHotEvent);
component.CurrentState = ExpendableLightState.Lit;
component.StateExpiryTime = component.GlowDuration;
UpdateSounds(ent);
UpdateVisualizer(ent);
EnsureComp<ActiveExpendableLightComponent>(ent);
return true;
}
private void UpdateLight(Entity<ExpendableLightComponent> ent)
{
switch (ent.Comp.CurrentState)
{
case ExpendableLightState.Lit:
ent.Comp.CurrentState = ExpendableLightState.Fading;
ent.Comp.StateExpiryTime = ent.Comp.FadeOutDuration;
UpdateVisualizer(ent);
break;
case ExpendableLightState.Fading:
ent.Comp.CurrentState = ExpendableLightState.Dead;
UpdateSounds(ent);
UpdateVisualizer(ent);
var meta = MetaData(ent);
_metaData.SetEntityName(ent, Loc.GetString(ent.Comp.SpentName), meta);
_metaData.SetEntityDescription(ent, Loc.GetString(ent.Comp.SpentDesc), meta);
_tagSystem.AddTag(ent, "Trash");
if (TryComp(ent, out ItemComponent? item))
_item.SetHeldPrefix(ent, "unlit", component: item);
if (TryComp(ent, out CartridgeAmmoComponent? ammo))
ammo.Spent = true;
var isHotEvent = new IsHotEvent { IsHot = false, };
RaiseLocalEvent(ent, isHotEvent);
RemCompDeferred<ActiveExpendableLightComponent>(ent);
break;
case ExpendableLightState.Dead:
case ExpendableLightState.BrandNew:
default:
break;
}
}
private void UpdateVisualizer(Entity<ExpendableLightComponent> ent)
{
if (!TryComp(ent, out AppearanceComponent? appearance))
return;
var expendableLight = ent.Comp;
_appearance.SetData(ent, ExpendableLightVisuals.State, expendableLight.CurrentState, appearance);
var behaviorState = expendableLight.CurrentState switch
{
ExpendableLightState.Lit => expendableLight.TurnOnBehaviourID,
ExpendableLightState.Fading => expendableLight.FadeOutBehaviourID,
_ => string.Empty
};
_appearance.SetData(ent, ExpendableLightVisuals.Behavior, behaviorState, appearance);
}
private void UpdateSounds(Entity<ExpendableLightComponent> ent)
{
switch (ent.Comp.CurrentState)
{
case ExpendableLightState.Lit:
_audio.PlayPvs(ent.Comp.LitSound, ent);
break;
case ExpendableLightState.Dead:
_audio.PlayPvs(ent.Comp.DieSound, ent);
break;
case ExpendableLightState.BrandNew:
case ExpendableLightState.Fading:
default:
break;
}
if (TryComp<ClothingComponent>(ent, out var clothing))
_clothing.SetEquippedPrefix(ent, ent.Comp.Activated ? "Activated" : string.Empty, clothing);
}
}

View File

@@ -99,6 +99,7 @@ public sealed class BloodCultSpellsSystem : EntitySystem
Category = VerbCategory.BloodSpells,
Text = Loc.GetString("blood-cult-select-spells-verb"),
Priority = 1,
CloseMenu = true,
Act = () => SelectBloodSpells(cultist)
};
var removeVerb = new ExamineVerb
@@ -106,6 +107,7 @@ public sealed class BloodCultSpellsSystem : EntitySystem
Category = VerbCategory.BloodSpells,
Text = Loc.GetString("blood-cult-remove-spells-verb"),
Priority = 0,
CloseMenu = true,
Act = () => RemoveBloodSpells(cultist)
};

View File

@@ -1,13 +1,15 @@
using Content.Shared.Actions;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Overlays.Switchable;
[RegisterComponent, NetworkedComponent]
public sealed partial class NightVisionComponent : SwitchableOverlayComponent
{
public override string? ToggleAction { get; set; } = "ToggleNightVision";
public override EntProtoId? ToggleAction { get; set; } = new EntProtoId("ToggleNightVision");
[DataField]
public override Color Color { get; set; } = Color.FromHex("#98FB98");
}

View File

@@ -6,7 +6,7 @@ namespace Content.Shared.Overlays.Switchable;
public abstract partial class SwitchableOverlayComponent : BaseOverlayComponent
{
[DataField, AutoNetworkedField]
[DataField]
public virtual bool IsActive { get; set; }
[DataField]
@@ -39,7 +39,7 @@ public abstract partial class SwitchableOverlayComponent : BaseOverlayComponent
new SoundPathSpecifier("/Audio/Items/Goggles/deactivate.ogg");
[DataField]
public virtual string? ToggleAction { get; set; }
public virtual EntProtoId? ToggleAction { get; set; }
[ViewVariables]
public EntityUid? ToggleActionEntity;

View File

@@ -1,12 +1,13 @@
using Content.Shared.Actions;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Overlays.Switchable;
[RegisterComponent, NetworkedComponent]
public sealed partial class ThermalVisionComponent : SwitchableOverlayComponent
{
public override string? ToggleAction { get; set; } = "ToggleThermalVision";
public override EntProtoId? ToggleAction { get; set; } = new("ToggleThermalVision");
public override Color Color { get; set; } = Color.FromHex("#F84742");

View File

@@ -147,6 +147,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
if (component.RequiredItems != null)
return;
if (_whitelistSystem.IsWhitelistFail(component.UserWhitelist, args.User))
return;
args.Handled = InteractUI(args.User, uid, component);
}
@@ -161,6 +164,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
if (component.RequiredItems != null)
return;
if (_whitelistSystem.IsWhitelistFail(component.UserWhitelist, args.User))
return;
args.Handled = InteractUI(args.User, uid, component);
}
@@ -173,7 +179,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
return;
if (_whitelistSystem.IsWhitelistFailOrNull(component.RequiredItems, args.Used) ||
!_whitelistSystem.IsWhitelistFail(component.UserWhitelist, args.User))
_whitelistSystem.IsWhitelistFail(component.UserWhitelist, args.User))
return;
args.Handled = InteractUI(args.User, uid, component);

View File

@@ -1,19 +1,20 @@
using Content.Shared.RadialSelector;
using Robust.Shared.GameStates;
namespace Content.Shared._White.BloodCult.TimedFactory;
[RegisterComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
public sealed partial class TimedFactoryComponent : Component
{
[DataField]
[DataField, AutoNetworkedField]
public bool Active = true;
[DataField(required: true)]
public List<RadialSelectorEntry> Entries = new();
[DataField]
public TimeSpan Cooldown = TimeSpan.FromSeconds(240);
public float Cooldown = 240;
[ViewVariables(VVAccess.ReadOnly)]
public TimeSpan CooldownIn = TimeSpan.Zero;
[ViewVariables(VVAccess.ReadOnly), AutoNetworkedField]
public float CooldownRemain = 0;
}

View File

@@ -4,13 +4,11 @@ using Content.Shared.Popups;
using Content.Shared.RadialSelector;
using Content.Shared.UserInterface;
using Robust.Shared.Network;
using Robust.Shared.Timing;
namespace Content.Shared._White.BloodCult.TimedFactory;
public sealed class TimedFactorySystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
@@ -33,7 +31,12 @@ public sealed class TimedFactorySystem : EntitySystem
var factoryQuery = EntityQueryEnumerator<TimedFactoryComponent>();
while (factoryQuery.MoveNext(out var uid, out var factory))
{
if (factory.Active || factory.CooldownIn > _gameTiming.CurTime)
if (factory.Active)
return;
factory.CooldownRemain -= frameTime;
Dirty(uid, factory);
if (factory.CooldownRemain > 0)
return;
factory.Active = true;
@@ -45,7 +48,9 @@ public sealed class TimedFactorySystem : EntitySystem
{
if (!factory.Comp.Active)
{
_popup.PopupClient(Loc.GetString("timed-factory-cooldown", ("cooldown", (int) (factory.Comp.CooldownIn - _gameTiming.CurTime).TotalSeconds)), factory, args.User);
_popup.PopupClient(Loc.GetString("timed-factory-cooldown", ("cooldown", (int) factory.Comp.CooldownRemain)),
factory,
args.User);
args.Cancel();
return;
}
@@ -59,7 +64,7 @@ public sealed class TimedFactorySystem : EntitySystem
return;
factory.Comp.Active = false;
factory.Comp.CooldownIn = _gameTiming.CurTime + factory.Comp.Cooldown;
factory.Comp.CooldownRemain = factory.Comp.Cooldown;
_appearance.SetData(factory, GenericCultVisuals.State, false);
_ui.CloseUi(factory.Owner, RadialSelectorUiKey.Key);

View File

@@ -5,3 +5,7 @@ construction-system-construct-no-materials = You don't have the materials to bui
construction-system-already-building = You are already building that!
construction-system-inside-container = You can't build while you're there!
construction-system-cannot-start = You cannot craft this!
## Rped
rped-container-empty = RPED is empty!

View File

@@ -7060,7 +7060,7 @@ ent-MaterialHideCorgi = шкура корги
ent-MaterialPyrotton = пироттон
ent-MaterialWebSilk = паутина
ent-MaterialWebSilk = шелк
.desc = Липкий материал из паутины.
@@ -8933,7 +8933,7 @@ ent-WindoorSecureUranium = укреплённая урановая стекло
.desc = Настолько неоново-зелёная, что кажется, будто пахнет лаймом. Не нюхай.
ent-WebBed = паутина-кровать
ent-WebBed = кровать из паутины
.desc = Попался. Ты теперь мебель.
@@ -8976,7 +8976,7 @@ ent-TableBrass = латунный стол
.desc = Блестит и не ржавеет. Чистый стимпанк.
ent-TableWeb = паутинный стол
ent-TableWeb = стол из паутины
.desc = Удивительно гладкий и прочный. Пауки знают толк в дизайне.

View File

@@ -1,3 +1,3 @@
spider-web-action-name = Паутина
spider-web-action-name = Создать паутину
spider-web-action-description = Создает паутину, которая замедляет вашу добычу.

View File

@@ -1,4 +1,4 @@
ent-ActionSpiderWeb = Паутина
ent-ActionSpiderWeb = Создать паутину
.desc = Создает паутину, которая замедляет вашу добычу.
ent-ActionSericulture = Ткать шёлк

View File

@@ -18,7 +18,7 @@ ent-MaterialDurathread1 = { ent-MaterialDurathread }
.suffix = Одна
.desc = { ent-MaterialDurathread.desc }
ent-MaterialWoodPlank = древесина
ent-MaterialWoodPlank = доски
.suffix = Полный
.desc = { ent-MaterialBase.desc }

View File

@@ -4,4 +4,8 @@ construction-system-construct-cannot-start-another-construction = Сейчас
construction-system-construct-no-materials = Недостаточно материалов для создания!
construction-system-already-building = Вы уже строите это!
construction-system-inside-container = Вы не можете строить, пока находитесь там!
construction-system-cannot-start = You cannot craft this!
construction-system-cannot-start = Вы не можете это собрать!
## Rped
rped-container-empty = РПЗД пуст!

View File

@@ -403,6 +403,7 @@
sprite: Clothing/Eyes/Goggles/nightvision.rsi
state: icon
event: !type:ToggleNightVisionEvent
useDelay: 4
- type: entity
id: ToggleThermalVision

View File

@@ -31,8 +31,6 @@
- type: CartridgeAmmo
proto: PelletShotgunFlare
deleteOnSpawn: true
- type: Sprite
sprite: Objects/Misc/flare.rsi
layers:

View File

@@ -9,7 +9,6 @@
- to: straight
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 5
@@ -17,7 +16,6 @@
- to: corner
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 5
@@ -25,7 +23,6 @@
- to: end
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 5
@@ -33,7 +30,6 @@
- to: gate
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 5

View File

@@ -140,7 +140,6 @@
doAfter: 0.25
completed:
- !type:SnapToGrid
southRotation: true
- node: FirelockGlassFrame
edges:
@@ -173,7 +172,6 @@
doAfter: 1
completed:
- !type:SnapToGrid
southRotation: true
- node: FirelockEdge
entity: FirelockEdge

View File

@@ -7,7 +7,6 @@
- to: railing
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 1
@@ -15,7 +14,6 @@
- to: railingCorner
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 2
@@ -23,7 +21,6 @@
- to: railingCornerSmall
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 1
@@ -31,7 +28,6 @@
- to: railingRound
completed:
- !type:SnapToGrid
southRotation: true
steps:
- material: MetalRod
amount: 2

View File

@@ -7,7 +7,6 @@
animationRotation: -45
wideAnimationRotation: -135
attackRate: 2
canHeavyAttack: false
range: 1.6
damage:
types:
@@ -28,7 +27,7 @@
speed: 10
distance: 0.05
- type: AnimateOnHit
applyToUser: false
applyToUser: true
whitelist:
components:
- MobState