using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Items.Clothing; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Power; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.Verbs; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Interactable { /// /// Component that represents a handheld lightsource which can be toggled on and off. /// [RegisterComponent] internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit { #pragma warning disable 649 [Dependency] private readonly ISharedNotifyManager _notifyManager; [Dependency] private readonly ILocalizationManager _localizationManager; #pragma warning restore 649 [ViewVariables(VVAccess.ReadWrite)] public float Wattage { get; set; } = 10; [ViewVariables] private ContainerSlot _cellContainer; private PointLightComponent _pointLight; private SpriteComponent _spriteComponent; private ClothingComponent _clothingComponent; [ViewVariables] private BatteryComponent Cell { get { if (_cellContainer.ContainedEntity == null) return null; _cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell); return cell; } } /// /// Status of light, whether or not it is emitting light. /// [ViewVariables] public bool Activated { get; private set; } async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { if (!eventArgs.Using.HasComponent()) return false; if (Cell != null) return false; var handsComponent = eventArgs.User.GetComponent(); if (!handsComponent.Drop(eventArgs.Using, _cellContainer)) { return false; } EntitySystem.Get().PlayFromEntity("/Audio/Items/pistol_magin.ogg", Owner); Dirty(); return true; } void IExamine.Examine(FormattedMessage message, bool inDetailsRange) { var loc = IoCManager.Resolve(); if (Activated) { message.AddMarkup(loc.GetString("The light is currently [color=darkgreen]on[/color].")); } } bool IUse.UseEntity(UseEntityEventArgs eventArgs) { return ToggleStatus(eventArgs.User); } public override void Initialize() { base.Initialize(); _pointLight = Owner.GetComponent(); _spriteComponent = Owner.GetComponent(); Owner.TryGetComponent(out _clothingComponent); _cellContainer = ContainerManagerComponent.Ensure("flashlight_cell_container", Owner, out _); Dirty(); } /// /// Illuminates the light if it is not active, extinguishes it if it is active. /// /// True if the light's status was toggled, false otherwise. private bool ToggleStatus(IEntity user) { var item = Owner.GetComponent(); // Update sprite and light states to match the activation. if (Activated) { TurnOff(); item.EquippedPrefix = "off"; } else { TurnOn(user); item.EquippedPrefix = "on"; } // Toggle always succeeds. return true; } private void TurnOff() { if (!Activated) { return; } SetState(false); Activated = false; EntitySystem.Get().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner); } private void TurnOn(IEntity user) { if (Activated) { return; } var cell = Cell; if (cell == null) { EntitySystem.Get().PlayFromEntity("/Audio/Machines/button.ogg", Owner); _notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Cell missing...")); return; } // To prevent having to worry about frame time in here. // Let's just say you need a whole second of charge before you can turn it on. // Simple enough. if (Wattage > cell.CurrentCharge) { EntitySystem.Get().PlayFromEntity("/Audio/Machines/button.ogg", Owner); _notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell...")); return; } Activated = true; SetState(true); EntitySystem.Get().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner); } private void SetState(bool on) { _spriteComponent.LayerSetVisible(1, on); _pointLight.Enabled = on; if (_clothingComponent != null) { _clothingComponent.ClothingEquippedPrefix = on ? "On" : "Off"; } } public void OnUpdate(float frameTime) { if (!Activated) return; var cell = Cell; if (cell == null || !cell.TryUseCharge(Wattage * frameTime)) TurnOff(); Dirty(); } private void EjectCell(IEntity user) { if (Cell == null) { return; } var cell = Cell; if (!_cellContainer.Remove(cell.Owner)) { return; } if (!user.TryGetComponent(out HandsComponent hands)) { return; } if (!hands.PutInHand(cell.Owner.GetComponent())) { cell.Owner.Transform.GridPosition = user.Transform.GridPosition; } EntitySystem.Get().PlayFromEntity("/Audio/Items/pistol_magout.ogg", Owner); } public override ComponentState GetComponentState() { if (Cell == null) { return new HandheldLightComponentState(null); } if (Wattage > Cell.CurrentCharge) { // Practically zero. // This is so the item status works correctly. return new HandheldLightComponentState(0); } return new HandheldLightComponentState(Cell.CurrentCharge / Cell.MaxCharge); } [Verb] public sealed class EjectCellVerb : Verb { protected override void GetData(IEntity user, HandheldLightComponent component, VerbData data) { if (!ActionBlockerSystem.CanInteract(user)) { data.Visibility = VerbVisibility.Invisible; return; } if (component.Cell == null) { data.Text = "Eject cell (cell missing)"; data.Visibility = VerbVisibility.Disabled; } else { data.Text = "Eject cell"; } } protected override void Activate(IEntity user, HandheldLightComponent component) { component.EjectCell(user); } } void IMapInit.MapInit() { if (_cellContainer.ContainedEntity != null) { return; } var cell = Owner.EntityManager.SpawnEntity("PowerCellSmallStandard", Owner.Transform.GridPosition); _cellContainer.Insert(cell); } } }