using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; 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 class HandheldLightComponent : Component, IUse, IExamine, IAttackBy, IMapInit { public const float Wattage = 10; [ViewVariables] private ContainerSlot _cellContainer; private PointLightComponent _pointLight; private SpriteComponent _spriteComponent; private ClothingComponent _clothingComponent; [ViewVariables] private PowerCellComponent Cell { get { if (_cellContainer.ContainedEntity == null) return null; _cellContainer.ContainedEntity.TryGetComponent(out PowerCellComponent cell); return cell; } } public override string Name => "HandheldLight"; /// /// Status of light, whether or not it is emitting light. /// [ViewVariables] public bool Activated { get; private set; } bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) { if (!eventArgs.AttackWith.HasComponent()) return false; if (Cell != null) return false; var handsComponent = eventArgs.User.GetComponent(); if (!handsComponent.Drop(eventArgs.AttackWith, _cellContainer)) { return false; } if (Owner.TryGetComponent(out SoundComponent soundComponent)) { soundComponent.Play("/Audio/items/weapons/pistol_magin.ogg"); } return true; } void IExamine.Examine(FormattedMessage message) { if (Activated) { message.AddText("The light is currently on."); } } bool IUse.UseEntity(UseEntityEventArgs eventArgs) { return ToggleStatus(); } public override void Initialize() { base.Initialize(); _pointLight = Owner.GetComponent(); _spriteComponent = Owner.GetComponent(); Owner.TryGetComponent(out _clothingComponent); _cellContainer = ContainerManagerComponent.Ensure("flashlight_cell_container", Owner, out var existed); } /// /// Illuminates the light if it is not active, extinguishes it if it is active. /// /// True if the light's status was toggled, false otherwise. public bool ToggleStatus() { // Update sprite and light states to match the activation. if (Activated) { TurnOff(); } else { TurnOn(); } // Toggle always succeeds. return true; } public void TurnOff() { if (!Activated) { return; } SetState(false); Activated = false; if (Owner.TryGetComponent(out SoundComponent soundComponent)) { soundComponent.Play("/Audio/items/flashlight_toggle.ogg"); } } public void TurnOn() { if (Activated) { return; } var cell = Cell; SoundComponent soundComponent; if (cell == null) { if (Owner.TryGetComponent(out soundComponent)) { soundComponent.Play("/Audio/machines/button.ogg"); } 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 (cell.AvailableCharge(1) < Wattage) { if (Owner.TryGetComponent(out soundComponent)) { soundComponent.Play("/Audio/machines/button.ogg"); } return; } Activated = true; SetState(true); if (Owner.TryGetComponent(out soundComponent)) { soundComponent.Play("/Audio/items/flashlight_toggle.ogg"); } } 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.TryDeductWattage(Wattage, frameTime)) TurnOff(); } 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; } if (Owner.TryGetComponent(out SoundComponent soundComponent)) { soundComponent.Play("/Audio/items/weapons/pistol_magout.ogg"); } } [Verb] public sealed class EjectCellVerb : Verb { protected override string GetText(IEntity user, HandheldLightComponent component) { return component.Cell == null ? "Eject cell (cell missing)" : "Eject cell"; } protected override VerbVisibility GetVisibility(IEntity user, HandheldLightComponent component) { return component.Cell == null ? VerbVisibility.Disabled : VerbVisibility.Visible; } protected override void Activate(IEntity user, HandheldLightComponent component) { component.EjectCell(user); } } void IMapInit.MapInit() { if (_cellContainer.ContainedEntity != null) { return; } var cell = Owner.EntityManager.SpawnEntity("PowerCellSmallHyper"); _cellContainer.Insert(cell); } } }