using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Nutrition.Components; using Content.Server.Power.EntitySystems; using Content.Server.Storage.Components; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Nutrition.Prototypes; using Content.Shared.Power; using Content.Shared.Storage.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.Nutrition.EntitySystems; /// /// This handles logic and interactions relating to /// public sealed partial class FatExtractorSystem : EntitySystem { [Dependency] private IGameTiming _timing = default!; [Dependency] private EmagSystem _emag = default!; [Dependency] private SatiationSystem _satiation = default!; [Dependency] private SharedAppearanceSystem _appearance = default!; [Dependency] private SharedAudioSystem _audio = default!; /// public override void Initialize() { SubscribeLocalEvent(OnGotEmagged); SubscribeLocalEvent(OnClosed); SubscribeLocalEvent(OnOpen); SubscribeLocalEvent(OnPowerChanged); } private void OnGotEmagged(EntityUid uid, FatExtractorComponent component, ref GotEmaggedEvent args) { if (!_emag.CompareFlag(args.Type, EmagType.Interaction)) return; if (_emag.CheckFlag(uid, EmagType.Interaction)) return; args.Handled = true; } private void OnClosed(EntityUid uid, FatExtractorComponent component, ref StorageAfterCloseEvent args) { StartProcessing(uid, component); } private void OnOpen(EntityUid uid, FatExtractorComponent component, ref StorageAfterOpenEvent args) { StopProcessing(uid, component); } private void OnPowerChanged(EntityUid uid, FatExtractorComponent component, ref PowerChangedEvent args) { if (!args.Powered) StopProcessing(uid, component); } public void StartProcessing(EntityUid uid, FatExtractorComponent? component = null, EntityStorageComponent? storage = null) { if (!Resolve(uid, ref component, ref storage)) return; if (component.Processing) return; if (!this.IsPowered(uid, EntityManager)) return; if (!TryGetValidOccupant(uid, out _, component, storage)) return; component.Processing = true; _appearance.SetData(uid, FatExtractorVisuals.Processing, true); component.Stream = _audio.PlayPvs(component.ProcessSound, uid)?.Entity; component.NextUpdate = _timing.CurTime + component.UpdateTime; } public void StopProcessing(EntityUid uid, FatExtractorComponent? component = null) { if (!Resolve(uid, ref component)) return; if (!component.Processing) return; component.Processing = false; _appearance.SetData(uid, FatExtractorVisuals.Processing, false); component.Stream = _audio.Stop(component.Stream); } public bool TryGetValidOccupant(EntityUid uid, [NotNullWhen(true)] out Entity? occupant, FatExtractorComponent? component = null, EntityStorageComponent? storage = null) { occupant = null; if (!Resolve(uid, ref component, ref storage)) return false; var firstEntity = storage.Contents.ContainedEntities.FirstOrDefault(); if (firstEntity is not { Valid: true }) { return false; } if (!TryComp(firstEntity, out var satiation)) return false; Entity entity = (firstEntity, satiation); if (_satiation.GetValueOrNull(entity, SatiationSystem.Hunger) < component.NutritionPerSecond && !_emag.CheckFlag(uid, EmagType.Interaction)) return false; if (_satiation.IsValueInRange(entity, SatiationSystem.Hunger, below: component.MinHungerThreshold) && !HasComp(uid)) return false; occupant = entity; return true; } public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var fat, out var storage)) { if (TryGetValidOccupant(uid, out var occupant, fat, storage)) { if (!fat.Processing) StartProcessing(uid, fat, storage); } else { StopProcessing(uid, fat); continue; } if (!fat.Processing) continue; if (_timing.CurTime < fat.NextUpdate) continue; fat.NextUpdate += fat.UpdateTime; _satiation.ModifyValue(occupant.Value, SatiationSystem.Hunger, -fat.NutritionPerSecond); fat.NutrientAccumulator += fat.NutritionPerSecond; if (fat.NutrientAccumulator >= fat.NutrientPerMeat) { fat.NutrientAccumulator -= fat.NutrientPerMeat; Spawn(fat.MeatPrototype, Transform(uid).Coordinates); } } } }