diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 67ac7871d1..79820211c8 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -86,6 +86,7 @@ + diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 96353380fc..8016d35a2f 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -86,6 +86,7 @@ namespace Content.Server factory.RegisterReference(); factory.Register(); factory.Register(); + factory.Register(); //Tools factory.Register(); diff --git a/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs new file mode 100644 index 0000000000..1ff15d0223 --- /dev/null +++ b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs @@ -0,0 +1,71 @@ +using System; +using SS14.Server.GameObjects; +using SS14.Shared.Enums; +using SS14.Shared.GameObjects; +using SS14.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Power +{ + public enum LightBulbState + { + Normal, + Broken, + Burned, + } + + public enum LightBulbType + { + Tube, + } + + /// + /// Component that represents a light bulb. Can be broken, or burned, which turns them mostly useless. + /// + public class LightBulbComponent : Component + { + + /// + /// Invoked whenever the state of the light bulb changes. + /// + public event EventHandler OnLightBulbStateChange; + + public override string Name => "LightBulb"; + + public LightBulbType Type = LightBulbType.Tube; + + /// + /// The current state of the light bulb. Invokes the OnLightBulbStateChange event when set. + /// It also updates the bulb's sprite accordingly. + /// + public LightBulbState State + { + get { return _state; } + set + { + var sprite = Owner.GetComponent(); + OnLightBulbStateChange?.Invoke(this, EventArgs.Empty); + _state = value; + switch (value) + { + case LightBulbState.Normal: + sprite.LayerSetState(0, "normal"); + break; + case LightBulbState.Broken: + sprite.LayerSetState(0, "broken"); + break; + case LightBulbState.Burned: + sprite.LayerSetState(0, "burned"); + break; + } + } + } + + private LightBulbState _state = LightBulbState.Normal; + + public override void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(ref Type, "bulb", LightBulbType.Tube); + } + + } +} diff --git a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs index db0e8b861b..dddbae410b 100644 --- a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs @@ -1,5 +1,10 @@ using System; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects; +using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Inventory; using SS14.Server.GameObjects; +using SS14.Server.GameObjects.Components.Container; using SS14.Server.GameObjects.EntitySystems; using SS14.Shared.Audio; using SS14.Shared.Enums; @@ -7,10 +12,17 @@ using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Interfaces.Timing; using SS14.Shared.IoC; +using SS14.Shared.Log; +using SS14.Shared.Map; +using SS14.Shared.Serialization; +using SS14.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Power { - public class PoweredLightComponent : Component + /// + /// Component that represents a wall light. It has a light bulb that can be replaced when broken. + /// + public class PoweredLightComponent : Component, IAttackHand, IAttackby { public override string Name => "PoweredLight"; @@ -18,32 +30,154 @@ namespace Content.Server.GameObjects.Components.Power private TimeSpan _lastThunk; + private LightBulbType BulbType = LightBulbType.Tube; + + [ViewVariables] private float Load = 40; + + [ViewVariables] private ContainerSlot LightBulbContainer; + + [ViewVariables] + private LightBulbComponent LightBulb + { + get + { + if (LightBulbContainer.ContainedEntity == null) return null; + + LightBulbContainer.ContainedEntity.TryGetComponent(out LightBulbComponent bulb); + + return bulb; + } + } + + bool IAttackby.Attackby(IEntity user, IEntity attackwith) + { + if (!attackwith.HasComponent()) return false; + + if (LightBulb != null) return false; + + user.GetComponent().Drop(attackwith, LightBulbContainer); + + var inserted = LightBulbContainer.Insert(attackwith); + + UpdateLight(); + + return inserted; + } + + bool IAttackHand.Attackhand(IEntity user) + { + if (user.GetComponent().GetSlotItem(EquipmentSlotDefines.Slots.GLOVES) != null) + { + EjectBulb(user); + UpdateLight(); + return true; + } + else + { + if (!user.TryGetComponent(out DamageableComponent damageableComponent)) return false; + damageableComponent.TakeDamage(DamageType.Heat, 20); + } + + UpdateLight(); + + return false; + } + + /// + /// Ejects the bulb to a mob's hand if possible. + /// + private void EjectBulb(IEntity user) + { + if (LightBulb == null) return; + + var bulb = LightBulb; + + if (!LightBulbContainer.Remove(bulb.Owner)) return; + + if (!user.TryGetComponent(out HandsComponent hands) + || !hands.PutInHand(bulb.Owner.GetComponent())) + bulb.Owner.Transform.GridPosition = user.Transform.GridPosition; + } + + public override void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(ref Load, "load", 40); + serializer.DataField(ref BulbType, "bulb", LightBulbType.Tube); + } + + /// + /// For attaching UpdateLight() to events. + /// + public void UpdateLight(object sender, EventArgs e) + { + UpdateLight(); + } + + /// + /// Updates the light's power drain, sprite and actual light state. + /// + public void UpdateLight() + { + var device = Owner.GetComponent(); + var sprite = Owner.GetComponent(); + var light = Owner.GetComponent(); + if (LightBulb == null) // No light bulb. + { + device.Load = 0; + sprite.LayerSetState(0, "empty"); + light.State = LightState.Off; + return; + } + + switch (LightBulb.State) + { + case LightBulbState.Normal: + if (device.Powered) + { + device.Load = Load; + sprite.LayerSetState(0, "on"); + light.State = LightState.On; + var time = IoCManager.Resolve().CurTime; + if (time > _lastThunk + _thunkDelay) + { + IoCManager.Resolve().GetEntitySystem() + .Play("/Audio/machines/light_tube_on.ogg", Owner, AudioParams.Default.WithVolume(-10f)); + } + } + else + { + device.Load = 0; + sprite.LayerSetState(0, "off"); + light.State = LightState.Off; + } + + break; + case LightBulbState.Broken: + device.Load = 0; + sprite.LayerSetState(0, "broken"); + light.State = LightState.Off; + break; + case LightBulbState.Burned: + device.Load = 0; + sprite.LayerSetState(0, "burned"); + light.State = LightState.Off; + break; + } + } + public override void Initialize() { base.Initialize(); var device = Owner.GetComponent(); - var sprite = Owner.GetComponent(); - var light = Owner.GetComponent(); - device.OnPowerStateChanged += (sender, args) => + device.OnPowerStateChanged += UpdateLight; + + LightBulbContainer = ContainerManagerComponent.Ensure("light_bulb", Owner, out var existed); + + if (!existed) // Insert a light tube if there wasn't any. { - if (args.Powered) - { - sprite.LayerSetState(0, "on"); - light.State = LightState.On; - var time = IoCManager.Resolve().CurTime; - if (time > _lastThunk + _thunkDelay) - { - IoCManager.Resolve().GetEntitySystem() - .Play("/Audio/machines/light_tube_on.ogg", Owner, AudioParams.Default.WithVolume(-10f)); - } - } - else - { - sprite.LayerSetState(0, "off"); - light.State = LightState.Off; - } - }; + LightBulbContainer.Insert(Owner.EntityManager.SpawnEntity("LightTube")); + } } } } diff --git a/Resources/Prototypes/Entities/Lights.yml b/Resources/Prototypes/Entities/Lights.yml index 599ef10734..c93e9463e3 100644 --- a/Resources/Prototypes/Entities/Lights.yml +++ b/Resources/Prototypes/Entities/Lights.yml @@ -3,7 +3,6 @@ name: "Unpowered Light" components: - type: Clickable - # So we can click on it for deletion. - type: BoundingBox - type: Sprite sprite: Buildings/light_tube.rsi @@ -28,6 +27,8 @@ id: poweredlight parent: wall_light components: + - type: Clickable + - type: BoundingBox - type: Sprite sprite: Buildings/light_tube.rsi state: off @@ -40,7 +41,31 @@ state: Off - type: PowerDevice - load: 50 priority: Low - type: PoweredLight + load: 40 + bulb: Tube + +- type: entity + parent: BaseItem + name: BaseLightbulb + id: BaseLightbulb + components: + - type: LightBulb + +- type: entity + parent: BaseLightbulb + name: Light Tube + id: LightTube + components: + - type: LightBulb + bulb: Tube + + - type: Sprite + sprite: Objects/light_tube.rsi + state: normal + + - type: Icon + sprite: Objects/light_tube.rsi + state: normal \ No newline at end of file diff --git a/Resources/Textures/Objects/light_tube.rsi/broken.png b/Resources/Textures/Objects/light_tube.rsi/broken.png new file mode 100644 index 0000000000..5df9e7166e Binary files /dev/null and b/Resources/Textures/Objects/light_tube.rsi/broken.png differ diff --git a/Resources/Textures/Objects/light_tube.rsi/burned.png b/Resources/Textures/Objects/light_tube.rsi/burned.png new file mode 100644 index 0000000000..d79b43f72f Binary files /dev/null and b/Resources/Textures/Objects/light_tube.rsi/burned.png differ diff --git a/Resources/Textures/Objects/light_tube.rsi/meta.json b/Resources/Textures/Objects/light_tube.rsi/meta.json new file mode 100644 index 0000000000..e5ffb23a14 --- /dev/null +++ b/Resources/Textures/Objects/light_tube.rsi/meta.json @@ -0,0 +1,44 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit ad7c8621e5567b1b3b2b609f699b3b80cca785f2", + "states": [ + { + "name": "normal", + "select": [], + "flags": {}, + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "burned", + "select": [], + "flags": {}, + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "broken", + "select": [], + "flags": {}, + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/light_tube.rsi/normal.png b/Resources/Textures/Objects/light_tube.rsi/normal.png new file mode 100644 index 0000000000..981a403783 Binary files /dev/null and b/Resources/Textures/Objects/light_tube.rsi/normal.png differ