CatStation/Content.Server/PowerSink/PowerSinkSystem.cs
Samuka 4c65a777a8
Xenoborg crystal (#45105)
* verb category

* voltage toggle comp

* move stuff

* add simple prototype

* implement verb action

* switch expression

* fixed the node not updating

* charge the battery

* fixed battery not charging

* spawn on battery level system

* finally works

* swap commentary position

* can only anchor the extractor on the station

* popup message for trying to anchor outside of station

* default placement for unanchored version

* ops

* fix body type

* commentary

* update visuals of power consumer

* add custom sprite

* fix light layer not changing

* xenoborg circuit

* fix xenoborg circuit

* add tag

* add hand to hold xenoborg circuits

* move to material

* add xenoborg circuit material

* add recipe to mothership core

* add a hand to hold circuits to the mothership core

* to not confuse

* update

* ops

* another ops

* update mothership

* update guidebook

* update values

* more info

* fix stack

* can store xenoborg circuits

* description

* also update description

* circuit -> crytal

* not modified from anything

* update description

* Revert "update mothership"

This reverts commit 84974c56afadac2a99ed2a166244a668d83fff48.

* update empty label

* small update to sprite

* not necessary code

* remove empty line

* color

* make it explode when destroyed

* change values

* update sprite

* update sprite

* make it eletrified

* flavor text

* simplify to only use charge

* subscribe to event

* new line

* remove popup

* no need for the setter

* no longer networked

* feedback popups

* Minor tweaks

* better to understand

* better now?

* double the amount of power per crystal

* ajust power levels

* make modules cost more

* update guidebook with new values

* add popup back

* i love solving merge issues

* remove readonly

* use Transform

* predict verb

* only do stuff if both comps are present

* newline

* fix popup

* remove string.empty

* better voltage comment

* remove indentation from comment

* comment

* break the extractor

* fix comp

* change to protected

* add a client system

* make the component with the biggest name ever

* fix the anchor fail message popup

* kill this thing

* update the proto

* revert changes to PowerNetSystem

* ops

* make it spawn some gas when it explodes

* can't discharge

* comment was wrong

* swap order of components

* set examinable to false

* examine text

* rename AnchorableSystem to SharedAnchorableSystem

* rename file and make it abstract

* server side anchor system

* ops

* client anchor system

* use server anchorable system in server

* use battery visuals

* use a helper method

* revert changes to anchorable system

* new system

* new line

* ops, not used

* ops

* fix battery visuals

* set CableDeviceNode as not enabled

* set setting on map init

* enough feedback for the mothership

* new line

* locale changes

* locale changes to SharedPowerNetworkBatteryChargerVoltageTogglerSystem

* change name (again)

* update comments

* add event

* raise a event

* use events

* use a method instead of just raising the event

* more subscriptions to the voltage change event

* update locale stuff

* upgrade voltage toggler system with stuff from the power switch system

* replace power switch with voltage toggle in generator window

* replace power switch with voltage toggle in SharedPortableGeneratorSystem

* replace power switch with voltage toggle in power sensor

* KILL POWER SWITCHABLE COMPONENT AND SYSTEM

* replace power switch with voltage toggle in PortableGeneratorSystem

* replace all PowerSwitchable for VoltageToggler in the prototypes

* nullable switch text

* not required anymore

* mistake with the yml

* fix some issues with locale

* opposite

* i don't have words

* only use delay if it has the delay comp

* revert this change

* revert this change

* revert this change

* revert this change

* add color

* comment

* use another component

* fix the alert not showing

* generic comp for powernetwork battery and power consumer

* rename events

* fix proto

* make it less efficient

* change how it displays the rogue power thingy

* Comp is evil

* comment

* use resolve

* loc id

* error

* one line

* move this stuff to the voltage toggler system

* revert changes to PowerNetConnector

* revert changes to NodeContainerSystem

* revert changes that mess with PowerSupplierComponent

* revert changes to SharedBatterySystem

* revert changes to server BatterySystem

* revert changes to PowerMonitoringConsoleSystem

* remove whitespace

* guess it was 2 lines

* remove this from PowerNetworkBatteryComponent

* PowerConsumerBatteryCharger

* remove charging behavior from power sink system

* add new component to power sink

* extractor now uses power consumer comp

* update PowerDeviceVisuals.Powered for power consumers that are recieving power

* use PowerDeviceVisuals.Powered instead of BatteryVisuals.Charging

* PowerConsumerBatteryChargerEfficiencyVoltageTogglerComponent

* change values

* Orks micro balance

* me when i forget to change the actual value

* change values in the guidebook

* use a event

* move efficiency to the powerconsumer component

* ops

* revert this random change

* remove mapinit

* move to one line

* remove try comp

* update event

* this is important

* use a entity table

* only one line

* use the entity table

* use the current body crusher proto

* update guidebook

* say that it changes the efficiency

* Improve guidebook wording.xml

Co-authored-by: korczoczek <danielkorczok@gmail.com>

* remove random whitespace

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* style stuff

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* make AnchorOnlyOnStationComponent networked

* better wording

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* Prettier

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* fix stack text

* give option to be anchored on any station member

* use 4 spaces

* use stuff from the other PR

* revert this change

* remove power toggle things

* idk

* use a update loop

* revert locale changes about the voltage toggler

* remove mentions of voltage toggling

* ops

* fix proto

* remove white line

* revert this

* move efficiency to PowerConsumerBatteryCharger

* revert rider suggestion

* custom sprite for extractor flatpack

* use a new enum

* make it destructible

* cleanup

---------

Co-authored-by: beck-thompson <beck314159@hotmail.com>
Co-authored-by: korczoczek <danielkorczok@gmail.com>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
2026-08-13 00:49:37 +00:00

135 lines
5.2 KiB
C#

using Content.Server.Chat.Systems;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Systems;
using Content.Shared.Examine;
using Content.Shared.Power.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.PowerSink
{
public sealed partial class PowerSinkSystem : EntitySystem
{
/// <summary>
/// Percentage of battery full to trigger the announcement warning at.
/// </summary>
private const float WarningMessageThreshold = 0.70f;
private readonly float[] _warningSoundThresholds = new[] { .80f, .90f, .95f, .98f };
/// <summary>
/// Length of time to delay explosion from battery full state -- this is used to play
/// a brief SFX winding up the explosion.
/// </summary>
/// <returns></returns>
private readonly TimeSpan _explosionDelayTime = TimeSpan.FromSeconds(1.465);
[Dependency] private IGameTiming _gameTiming = default!;
[Dependency] private ChatSystem _chat = default!;
[Dependency] private ExplosionSystem _explosionSystem = default!;
[Dependency] private SharedAudioSystem _audio = default!;
[Dependency] private StationSystem _station = default!;
[Dependency] private BatterySystem _battery = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PowerSinkComponent, ExaminedEvent>(OnExamine);
}
private void OnExamine(EntityUid uid, PowerSinkComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange || !TryComp<PowerConsumerComponent>(uid, out var consumer))
return;
var drainAmount = (int) consumer.NetworkLoad.ReceivingPower / 1000;
args.PushMarkup(
Loc.GetString(
"powersink-examine-drain-amount",
("amount", drainAmount),
("markupDrainColor", "orange"))
);
}
public override void Update(float frameTime)
{
var toRemove = new RemQueue<(EntityUid Entity, PowerSinkComponent Sink)>();
var query = EntityQueryEnumerator<PowerSinkComponent, BatteryComponent, TransformComponent>();
// Realistically it's gonna be like <5 per station.
while (query.MoveNext(out var entity, out var component, out var battery, out var transform))
{
if (!transform.Anchored)
continue;
var currentBatteryThreshold = _battery.GetChargeLevel((entity, battery));
// Check for warning message threshold
if (!component.SentImminentExplosionWarningMessage &&
currentBatteryThreshold >= WarningMessageThreshold)
{
NotifyStationOfImminentExplosion(entity, component);
}
// Check for warning sound threshold
foreach (var testThreshold in _warningSoundThresholds)
{
if (currentBatteryThreshold >= testThreshold &&
testThreshold > component.HighestWarningSoundThreshold)
{
component.HighestWarningSoundThreshold = currentBatteryThreshold; // Don't re-play in future until next threshold hit
_audio.PlayPvs(component.ElectricSound, entity); // Play SFX
break;
}
}
// Check for explosion
if (!_battery.IsFull((entity, battery)))
continue;
if (component.ExplosionTime == null)
{
// Set explosion sequence to start soon
component.ExplosionTime = _gameTiming.CurTime.Add(_explosionDelayTime);
// Wind-up SFX
_audio.PlayPvs(component.ChargeFireSound, entity); // Play SFX
}
else if (_gameTiming.CurTime >= component.ExplosionTime)
{
// Explode!
toRemove.Add((entity, component));
}
}
foreach (var (entity, component) in toRemove)
{
_explosionSystem.QueueExplosion(entity, "PowerSink", 2000f, 4f, 20f, canCreateVacuum: true);
RemComp(entity, component);
}
}
private void NotifyStationOfImminentExplosion(EntityUid uid, PowerSinkComponent powerSinkComponent)
{
if (powerSinkComponent.SentImminentExplosionWarningMessage)
return;
powerSinkComponent.SentImminentExplosionWarningMessage = true;
var station = _station.GetOwningStation(uid);
if (station == null)
return;
_chat.DispatchStationAnnouncement(
station.Value,
Loc.GetString("powersink-imminent-explosion-announcement"),
playDefaultSound: true,
colorOverride: Color.Yellow
);
}
}
}