From 0cfd2f3bb2e830f595d47523ddf02cb6aacc261a Mon Sep 17 00:00:00 2001 From: 20kdc Date: Thu, 21 May 2020 20:08:03 +0100 Subject: [PATCH] Solar Panels (#936) --- .../Power/PowerGeneratorComponent.cs | 2 +- .../Components/Power/SolarPanelComponent.cs | 91 ++++++++++++++++++ .../EntitySystems/PowerSolarSystem.cs | 65 +++++++++++++ .../Prototypes/Entities/Buildings/power.yml | 29 ++++++ .../Buildings/solar_panel.rsi/broken.png | Bin 0 -> 291 bytes .../Buildings/solar_panel.rsi/meta.json | 1 + .../Buildings/solar_panel.rsi/normal.png | Bin 0 -> 886 bytes 7 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs create mode 100644 Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/broken.png create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/meta.json create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/normal.png diff --git a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs index e9285e7541..df10e90df4 100644 --- a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs @@ -65,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Power { _supply = value; var node = Owner.GetComponent(); - node.Parent.UpdateGenerator(this); + node?.Parent?.UpdateGenerator(this); } /// diff --git a/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs new file mode 100644 index 0000000000..4707180c59 --- /dev/null +++ b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs @@ -0,0 +1,91 @@ +using System; +using Content.Server.GameObjects.Components.Damage; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Audio; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Power +{ + + /// + /// This is a solar panel. + /// It generates power from the sun based on coverage. + /// + [RegisterComponent] + public class SolarPanelComponent : Component, IBreakAct + { + public override string Name => "SolarPanel"; + + private PowerGeneratorComponent _powerGenerator; + + /// + /// Maximum supply output by this panel (coverage = 1) + /// + private float _maxSupply = 1500; + [ViewVariables(VVAccess.ReadWrite)] + public float MaxSupply + { + get => _maxSupply; + set { + _maxSupply = value; + UpdateSupply(); + } + } + + /// + /// Current coverage of this panel (from 0 to 1). + /// This is updated by . + /// + private float _coverage = 0; + [ViewVariables] + public float Coverage + { + get => _coverage; + set { + // This gets updated once-per-tick, so avoid updating it if truly unnecessary + if (_coverage != value) { + _coverage = value; + UpdateSupply(); + } + } + } + + private void UpdateSupply() + { + if (_powerGenerator != null) + _powerGenerator.Supply = _maxSupply * _coverage; + } + + public override void Initialize() + { + base.Initialize(); + + _powerGenerator = Owner.GetComponent(); + UpdateSupply(); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _maxSupply, "maxsupply", 1500); + } + + public void OnBreak(BreakageEventArgs args) + { + var sprite = Owner.GetComponent(); + sprite.LayerSetState(0, "broken"); + MaxSupply = 0; + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs new file mode 100644 index 0000000000..4108748e48 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs @@ -0,0 +1,65 @@ +using Content.Server.GameObjects.Components.Power; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Maths; +using System; + +namespace Content.Server.GameObjects.EntitySystems +{ + /// + /// Responsible for maintaining the solar-panel sun angle and updating coverage. + /// + [UsedImplicitly] + public class PowerSolarSystem: EntitySystem + { + /// + /// The current sun angle. + /// + public Angle TowardsSun = Angle.South; + + public override void Initialize() + { + EntityQuery = new TypeEntityQuery(typeof(SolarPanelComponent)); + } + + public override void Update(float frameTime) + { + TowardsSun += Angle.FromDegrees(frameTime / 10); + TowardsSun = TowardsSun.Reduced(); + foreach (var entity in RelevantEntities) + { + // In the 'sunRelative' coordinate system: + // the sun is considered to be an infinite distance directly up. + // this is the rotation of the panel relative to that. + // directly upwards (theta = 0) = coverage 1 + // left/right 90 degrees (abs(theta) = (pi / 2)) = coverage 0 + // directly downwards (abs(theta) = pi) = coverage -1 + // as TowardsSun + = CCW, + // panelRelativeToSun should - = CW + var panelRelativeToSun = entity.Transform.WorldRotation - TowardsSun; + // essentially, given cos = X & sin = Y & Y is 'downwards', + // then for the first 90 degrees of rotation in either direction, + // this plots the lower-right quadrant of a circle. + // now basically assume a line going from the negated X/Y to there, + // and that's the hypothetical solar panel. + // + // since, again, the sun is considered to be an infinite distance upwards, + // this essentially means Cos(panelRelativeToSun) is half of the cross-section, + // and since the full cross-section has a max of 2, effectively-halving it is fine. + // + // as for when it goes negative, it only does that when (abs(theta) > pi) + // and that's expected behavior. + float coverage = (float) Math.Max(0, Math.Cos(panelRelativeToSun)); + + // Would determine occlusion, but that requires raytraces. + // And I'm not sure where those are in the codebase. + // Luckily, auto-rotation isn't in yet, so it won't matter anyway. + + // Total coverage calculated; apply it to the panel. + var panel = entity.GetComponent(); + panel.Coverage = coverage; + } + } + } +} diff --git a/Resources/Prototypes/Entities/Buildings/power.yml b/Resources/Prototypes/Entities/Buildings/power.yml index 5191c4e1f0..a599ba1842 100644 --- a/Resources/Prototypes/Entities/Buildings/power.yml +++ b/Resources/Prototypes/Entities/Buildings/power.yml @@ -62,6 +62,35 @@ - type: SnapGrid offset: Center +- type: entity + id: SolarPanel + name: Solar Panel + description: Generates power from sunlight. Usually used to power replacements for sunlight. Fragile. + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: InteractionOutline + - type: Collidable + shapes: + - !type:PhysShapeAabb + layer: 31 + - type: Sprite + sprite: Buildings/solar_panel.rsi + state: normal + - type: Icon + sprite: Buildings/solar_panel.rsi + state: normal + - type: PowerGenerator + - type: SolarPanel + supply: 1500 + - type: Rotatable + - type: SnapGrid + offset: Center + - type: Damageable + - type: Breakable + thresholdvalue: 100 + - type: entity id: WPPnobattery name: WPPnobattery diff --git a/Resources/Textures/Buildings/solar_panel.rsi/broken.png b/Resources/Textures/Buildings/solar_panel.rsi/broken.png new file mode 100644 index 0000000000000000000000000000000000000000..ded81ca75f5a50eb079b870437dcfd01f34465e0 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)S4AL$!I*&|jh&rcOH0ec z<3B^%|1)U}J9qvs@Jg2iN-~xN`2{mLJiCzw;v{*yyD)UH%6b4fD?MEtLp08>ooLI~ zO&9T{$@ecRM@&0*3z?yy6$>aE$Q*yidBo)u5&V~WaKAorGcM`B(7 zp$D@Yx1N}AYE@rU$@x-K)5~8Zn3-R+ue!i9r!AH3Y}k9jtrmVo?_1h-@d(Y?*y(pK i?y>rwqzV5&UE<%VCn?BuzW*@L(F~rhelF{r5}E+`6>HQ0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/solar_panel.rsi/meta.json b/Resources/Textures/Buildings/solar_panel.rsi/meta.json new file mode 100644 index 0000000000..377fa6ccb7 --- /dev/null +++ b/Resources/Textures/Buildings/solar_panel.rsi/meta.json @@ -0,0 +1 @@ +{"version":1,"license":"CC-BY-SA-3.0","copyright":"Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi and modified.","size":{"x":32,"y":32},"states":[{"name":"normal","select":[],"flags":{},"directions":8},{"name":"broken","select":[],"flags":{},"directions":1}]} diff --git a/Resources/Textures/Buildings/solar_panel.rsi/normal.png b/Resources/Textures/Buildings/solar_panel.rsi/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1c620029d4e29cecd7e67db13e08f4b46c1ff0 GIT binary patch literal 886 zcmV-+1Bv{JP)0$r?00DGTPE!Ct=GbNc0004EOGiWi zhy@);0008{Nkl29!XzW>MFZg%9B1 z^WLPj%{fT~bs^k)7-&19`TL#!{7I7hBekE?XZU*W`f}fvWPSA|-YcMiBT_JF^}7Y^ zfgu4EsNW|9q($_#G0;D&11h=so7I4U|aV%jd?)GeSh;M=x3mG z1VIW69v4vi1i}{NwY+reWFRSmhVuvlOYs>2lmLT(fC0dI0qT0dAAU&Cst5t_)nWa( zfClg!PLy7X5P&|~JH{!3-1JZV1OQsKj0;FhRK-Yu!4~6#s|WzxNLQc<0wWC+cnDGs zE3Z>dz_u&cEf#F%1Yi$L0|FKR^j=FjqX>iyU0@mBR0>zMlu1&aPA%u0olZ(?HMW3z z1Uv!O0qt#(34^Qj5%7Wn;3I&3ZFwt8(98!IX!fGw1dM*#g3bX0=G402;30td9RPX% z=0km_igResXV6-k%WND&OrTV-Joo_M2TfRjpv8lbYBd7L;Icx0v&_6YszE?QJ;11d z4uDIW7y`g9n1EUi3Nx}En`JAaXe0m%6VPVXeE@ShB|ZX_1)T#1fm!c4Fc(9e6(6o0 z2h*Lk3nEMaG$xP>d12UPDQiO)I0T;vfXR))aQ0%7WLUm8=kNm!XLCXT3lPR4jG7Ge zeFQcHkvwKb?tE6g=SnN!fF^TTVo!QFwOK;|Xu98|nuRVY$*bpWyhN~4B)X6^c~9#i7PC$|sj~~WgEJFYry{vEx-ci;A__=JC?-h`2yfge{nfxd97nBSytbq7klK=n! M07*qoM6N<$f)CPawEzGB literal 0 HcmV?d00001