CatStation/Content.Server/StationEvents/Events/SolarFlareRule.cs
qwerltaz e39cd127d9
fix some station events targeting off-station grids (#45813)
* fix vent critters spawning off station

* I polish the code

* add utility to get entities ONLY on the station. use in vent critters rule.

* fix station events affecting outside grids

* better argument names for GetEntitiesWithComponentOnStation

* BreakerFlipRule

* \n

* fix doc in GetEntitiesWithComponentOnStation

* keep the comments

* remove BreakerFlipRuleComponent Blacklist

* minor cleanup

* review

* format

---------

Co-authored-by: Pok245 <113675512+Pok27@users.noreply.github.com>
2026-10-03 19:17:59 +00:00

93 lines
3.3 KiB
C#

using System.Linq;
using Content.Server.Light.EntitySystems;
using Content.Server.StationEvents.Components;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.GameTicking.Components;
using Content.Shared.Light.Components;
using Content.Shared.Radio;
using Content.Shared.Radio.Components;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
/// <summary>
/// Handler for events that cause a solar flare for some amount of time.
/// </summary>
/// <remarks>
/// When a solar flare is active, radio communications are disabled on a random set of channels,
/// doors can randomly open and close, and lights can explode.
/// </remarks>
/// <seealso cref="SolarFlareRuleComponent"/>
public sealed partial class SolarFlareRule : StationEventSystem<SolarFlareRuleComponent>
{
[Dependency] private PoweredLightSystem _poweredLight = default!;
[Dependency] private SharedDoorSystem _door = default!;
[Dependency] private EntityQuery<HeadsetComponent> _headsetQuery;
private float _effectTimer;
protected override void Started(Entity<SolarFlareRuleComponent, GameRuleComponent> ent, ref GameRuleStartedEvent args)
{
base.Started(ent, ref args);
for (var i = 0; i < ent.Comp1.ExtraCount; i++)
{
var channel = RobustRandom.Pick(ent.Comp1.ExtraChannels);
ent.Comp1.AffectedChannels.Add(channel);
}
ent.Comp1.AffectedLights = Station.GetEntitiesWithComponentOnStation<PoweredLightComponent>(true)
.Select(e => (e.Owner, e.Comp))
.ToHashSet();
ent.Comp1.AffectedAirlocks = Station.GetEntitiesWithComponentOnStation<AirlockComponent>(true)
.Select(e => (e.Owner, e.Comp))
.ToHashSet();
}
protected override void ActiveTick(EntityUid uid, SolarFlareRuleComponent component, GameRuleComponent gameRule, float frameTime)
{
base.ActiveTick(uid, component, gameRule, frameTime);
_effectTimer -= frameTime;
if (!(_effectTimer < 0))
return;
_effectTimer += 1;
foreach (var light in component.AffectedLights)
{
if (RobustRandom.Prob(component.LightBreakChancePerSecond))
_poweredLight.TryDestroyBulb(light.Item1, light.Item2);
}
foreach (var airlockEnt in component.AffectedAirlocks)
{
if (airlockEnt.Item2.AutoClose && RobustRandom.Prob(component.DoorToggleChancePerSecond))
_door.TryToggleDoor(airlockEnt.Item1);
}
}
[SubscribeLocalEvent]
private void OnRadioReceiveAttempt(ref RadioReceiveAttemptEvent args)
{
if (args.Cancelled)
return;
var query = EntityQueryEnumerator<SolarFlareRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var flare, out var gameRule))
{
if (!GameTicker.IsGameRuleActive((uid, gameRule)))
continue;
if (!flare.AffectedChannels.Contains(args.Channel.ID))
continue;
if (!flare.OnlyJamHeadsets || _headsetQuery.HasComp(args.RadioReceiver) || _headsetQuery.HasComp(args.RadioSource))
{
args.Cancelled = true;
return;
}
}
}
}