diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index ab04ae7978..e82e38bd97 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -149,6 +149,7 @@
+
@@ -156,15 +157,15 @@
Content.Shared
- {916C5BF0-74BF-485D-A233-C1AC30007119}
+ {B04AAE71-0000-0000-0000-000000000000}
SS14.Server
- {7DC961F2-A45B-4193-BE7F-77622A231943}
+ {93F23A82-00C5-4572-964E-E7C9457726D4}
SS14.Shared.Maths
- {5F161008-6C48-4596-A2DE-5E7B0CEB2AA1}
+ {0529F740-0000-0000-0000-000000000000}
SS14.Shared
diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs
index 96c671a4b3..3f70e845a1 100644
--- a/Content.Server/EntryPoint.cs
+++ b/Content.Server/EntryPoint.cs
@@ -135,6 +135,8 @@ namespace Content.Server
factory.Register();
factory.Register();
+ factory.Register();
+
factory.Register();
factory.RegisterReference();
diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
index ae53d48de9..6e11da5d5d 100644
--- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
@@ -31,6 +31,7 @@ namespace Content.Server.GameObjects.Components.Power
base.DeductCharge(toDeduct);
_updateAppearance();
+ ChargeChanged();
}
public override void AddCharge(float charge)
@@ -38,6 +39,7 @@ namespace Content.Server.GameObjects.Components.Power
base.AddCharge(charge);
_updateAppearance();
+ ChargeChanged();
}
private void _updateAppearance()
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
index d108a76cea..02f42f3019 100644
--- a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
@@ -60,6 +60,7 @@ namespace Content.Server.GameObjects.Components.Power
[ViewVariables]
public bool Full => Charge >= Capacity;
+ public event Action OnChargeChanged;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
@@ -70,6 +71,14 @@ namespace Content.Server.GameObjects.Components.Power
serializer.DataField(ref _distributionRate, "distributionrate", 1000);
}
+ protected virtual void ChargeChanged()
+ {
+ if (OnChargeChanged != null)
+ { //Only fire this event if anyone actually subscribes to it
+ OnChargeChanged.Invoke();
+ }
+ }
+
///
/// Checks if the storage can supply the amount of charge directly requested
///
@@ -88,6 +97,7 @@ namespace Content.Server.GameObjects.Components.Power
_charge = Math.Max(0, Charge - toDeduct);
LastChargeState = ChargeState.Discharging;
LastChargeStateChange = DateTime.Now;
+ ChargeChanged();
}
public virtual void AddCharge(float charge)
@@ -95,6 +105,7 @@ namespace Content.Server.GameObjects.Components.Power
_charge = Math.Min(Capacity, Charge + charge);
LastChargeState = ChargeState.Charging;
LastChargeStateChange = DateTime.Now;
+ ChargeChanged();
}
///
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs
new file mode 100644
index 0000000000..be7ed87dbc
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs
@@ -0,0 +1,50 @@
+using System;
+using Content.Server.GameObjects.Components.Power;
+using SS14.Shared.Serialization;
+
+namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
+{
+ public class HitscanWeaponCapacitorComponent : PowerCellComponent
+ {
+
+ public override string Name => "HitscanWeaponCapacitor";
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+ }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ Charge = Capacity;
+ }
+
+ public float GetChargeFrom(float toDeduct)
+ {
+ //Use this function when you want to shoot even though you don't have enough energy for basecost
+ ChargeChanged();
+ var chargeChangedBy = Math.Min(this.Charge, toDeduct);
+ this.DeductCharge(chargeChangedBy);
+ return chargeChangedBy;
+ }
+
+ public void FillFrom(PowerStorageComponent battery)
+ {
+ var capacitorPowerDeficit = this.Capacity - this.Charge;
+ if (battery.CanDeductCharge(capacitorPowerDeficit))
+ {
+ battery.DeductCharge(capacitorPowerDeficit);
+ this.AddCharge(capacitorPowerDeficit);
+ }
+ else
+ {
+ this.AddCharge(battery.Charge);
+ battery.DeductCharge(battery.Charge);
+ }
+ }
+ }
+
+
+}
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
index b876d4e08c..e4a4b3398f 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
@@ -14,35 +14,74 @@ using SS14.Shared.Serialization;
using System;
using Content.Server.GameObjects.Components.Sound;
using SS14.Shared.GameObjects;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Server.GameObjects.Components.Power;
+using Content.Shared.Interfaces;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
{
- public class HitscanWeaponComponent : Component
+ public class HitscanWeaponComponent : Component, IAttackby
{
private const float MaxLength = 20;
public override string Name => "HitscanWeapon";
- string Spritename = "Objects/laser.png";
- int Damage = 10;
+ string _spritename;
+ private int _damage;
+ private int _baseFireCost;
+ private float _lowerChargeLimit;
+
+ //As this is a component that sits on the weapon rather than a static value
+ //we just declare the field and then use GetComponent later to actually get it.
+ //Do remember to add it in both the .yaml prototype and the factory in EntryPoint.cs
+ //Otherwise you will get errors
+ private HitscanWeaponCapacitorComponent capacitorComponent;
+
+ public int Damage => _damage;
+
+ public int BaseFireCost => _baseFireCost;
+
+ public HitscanWeaponCapacitorComponent CapacitorComponent => capacitorComponent;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
- serializer.DataField(ref Spritename, "sprite", "Objects/laser.png");
- serializer.DataField(ref Damage, "damage", 10);
+ serializer.DataField(ref _spritename, "sprite", "Objects/laser.png");
+ serializer.DataField(ref _damage, "damage", 10);
+ serializer.DataField(ref _baseFireCost, "baseFireCost", 300);
+ serializer.DataField(ref _lowerChargeLimit, "lowerChargeLimit", 10);
}
public override void Initialize()
{
base.Initialize();
-
var rangedWeapon = Owner.GetComponent();
+ capacitorComponent = Owner.GetComponent();
rangedWeapon.FireHandler = Fire;
}
+ public bool Attackby(IEntity user, IEntity attackwith)
+ {
+ if (!attackwith.TryGetComponent(out PowerStorageComponent component))
+ {
+ return false;
+ }
+ if (capacitorComponent.Full)
+ {
+ Owner.PopupMessage(user, "Capacitor at max charge");
+ return false;
+ }
+ capacitorComponent.FillFrom(component);
+ return true;
+ }
+
private void Fire(IEntity user, GridCoordinates clickLocation)
{
+ if (capacitorComponent.Charge < _lowerChargeLimit)
+ {//If capacitor has less energy than the lower limit, do nothing
+ return;
+ }
+ float energyModifier = capacitorComponent.GetChargeFrom(_baseFireCost) / _baseFireCost;
var userPosition = user.Transform.WorldPosition; //Remember world positions are ephemeral and can only be used instantaneously
var angle = new Angle(clickLocation.Position - userPosition);
@@ -50,26 +89,28 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
var rayCastResults = IoCManager.Resolve().IntersectRay(ray, MaxLength,
Owner.Transform.GetMapTransform().Owner);
- Hit(rayCastResults);
- AfterEffects(user, rayCastResults, angle);
+ Hit(rayCastResults, energyModifier);
+ AfterEffects(user, rayCastResults, angle, energyModifier);
}
- protected virtual void Hit(RayCastResults ray)
+ protected virtual void Hit(RayCastResults ray, float damageModifier)
{
if (ray.HitEntity != null && ray.HitEntity.TryGetComponent(out DamageableComponent damage))
{
- damage.TakeDamage(DamageType.Heat, Damage);
+ damage.TakeDamage(DamageType.Heat, (int)Math.Round(_damage * damageModifier, MidpointRounding.AwayFromZero));
+ //I used Math.Round over Convert.toInt32, as toInt32 always rounds to
+ //even numbers if halfway between two numbers, rather than rounding to nearest
}
}
- protected virtual void AfterEffects(IEntity user, RayCastResults ray, Angle angle)
+ protected virtual void AfterEffects(IEntity user, RayCastResults ray, Angle angle, float energyModifier)
{
var time = IoCManager.Resolve().CurTime;
var dist = ray.DidHitObject ? ray.Distance : MaxLength;
var offset = angle.ToVec() * dist / 2;
var message = new EffectSystemMessage
{
- EffectSprite = Spritename,
+ EffectSprite = _spritename,
Born = time,
DeathTime = time + TimeSpan.FromSeconds(1),
Size = new Vector2(dist, 1f),
@@ -77,7 +118,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
//Rotated from east facing
Rotation = (float) angle.Theta,
ColorDelta = new Vector4(0, 0, 0, -1500f),
- Color = new Vector4(255, 255, 255, 750),
+ Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), energyModifier),
+
Shaded = false
};
var mgr = IoCManager.Resolve();
diff --git a/Resources/Prototypes/Entities/Weapons.yml b/Resources/Prototypes/Entities/Weapons.yml
index e7432c623b..9c3caf8aea 100644
--- a/Resources/Prototypes/Entities/Weapons.yml
+++ b/Resources/Prototypes/Entities/Weapons.yml
@@ -1,25 +1,3 @@
-- type: entity
- name: Laser Gun
- parent: BaseItem
- id: LaserItem
- description: A weapon using light amplified by the stimulated emission of radiation
- components:
- - type: Sprite
- sprite: Objects/laser_retro.rsi
- state: 100
- - type: Icon
- sprite: Objects/laser_retro.rsi
- state: 100
- - type: RangedWeapon
- - type: HitscanWeapon
- damage: 30
- sprite: "Objects/laser.png"
- - type: Item
- Size: 24
- sprite: Objects/laser_retro.rsi
- prefix: 100
- - type: Sound
-
- type: entity
name: Spear
parent: BaseItem
diff --git a/Resources/Prototypes/Entities/weapons/laserguns.yml b/Resources/Prototypes/Entities/weapons/laserguns.yml
new file mode 100644
index 0000000000..f26657c244
--- /dev/null
+++ b/Resources/Prototypes/Entities/weapons/laserguns.yml
@@ -0,0 +1,24 @@
+- type: entity
+ name: Laser Gun
+ parent: BaseItem
+ id: LaserItem
+ description: A weapon using light amplified by the stimulated emission of radiation
+ components:
+ - type: Sprite
+ sprite: Objects/laser_retro.rsi
+ state: 100
+ - type: Icon
+ sprite: Objects/laser_retro.rsi
+ state: 100
+ - type: RangedWeapon
+ - type: HitscanWeapon
+ damage: 30
+ sprite: "Objects/laser.png"
+ lowerDischargeLimit: 10
+ - type: HitscanWeaponCapacitor
+ capacity: 1000
+ - type: Item
+ Size: 24
+ sprite: Objects/laser_retro.rsi
+ prefix: 100
+ - type: Sound
\ No newline at end of file