Files
tbd-station-14/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticWeapon.cs

153 lines
5.7 KiB
C#

using Content.Server.GameObjects.Components.Sound;
using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using System;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.IoC;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{
/// <summary>
/// Handles firing projectiles from a contained <see cref="BallisticBulletComponent" />.
/// </summary>
public abstract class BallisticWeaponComponent : BaseProjectileWeaponComponent
{
private Chamber[] _chambers;
/// <summary>
/// Number of chambers created during initialization.
/// </summary>
private int _chamberCount;
[ViewVariables]
private BallisticCaliber _caliber ;
/// <summary>
/// What type of ammo this gun can fire.
/// </summary>
private string _soundGunEmpty;
/// <summary>
/// Sound played when trying to shoot if there is no ammo available.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public string SoundGunEmpty { get => _soundGunEmpty; set => _soundGunEmpty = value; }
private float _spreadStdDevGun;
/// <summary>
/// Increases the standard deviation of the ammo being fired.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float SpreadStdDevGun { get => _spreadStdDevGun; set => _spreadStdDevGun = value; }
private float _evenSpreadAngleGun;
/// <summary>
/// Increases the evenspread of the ammo being fired.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float EvenSpreadAngleGun { get => _evenSpreadAngleGun; set => _evenSpreadAngleGun = value; }
private float _velocityGun;
/// <summary>
/// Increases the velocity of the ammo being fired.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float VelocityGun { get => _velocityGun; set => _velocityGun = value; }
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _soundGunEmpty, "sound_empty", "/Audio/Guns/Empty/empty.ogg");
serializer.DataField(ref _spreadStdDevGun, "spreadstddev", 0);
serializer.DataField(ref _evenSpreadAngleGun, "evenspread", 0);
serializer.DataField(ref _velocityGun, "gunvelocity", 0);
serializer.DataField(ref _caliber, "caliber", BallisticCaliber.Unspecified);
serializer.DataField(ref _chamberCount, "chambers", 1);
}
public override void Initialize()
{
base.Initialize();
Owner.GetComponent<RangedWeaponComponent>().FireHandler = TryShoot;
_chambers = new Chamber[_chamberCount];
for (var i = 0; i < _chambers.Length; i++)
{
var container = ContainerManagerComponent.Ensure<ContainerSlot>($"ballistics_chamber_{i}", Owner);
_chambers[i] = new Chamber(container);
}
}
/// <summary>
/// Fires projectiles based on loaded ammo from entity to a coordinate.
/// </summary>
protected void TryShoot(IEntity user, GridCoordinates clickLocation)
{
var ammo = GetChambered(FirstChamber)?.GetComponent<BallisticBulletComponent>();
CycleChamberedBullet(FirstChamber);
if (ammo == null || ammo?.Spent == true || ammo?.Caliber != _caliber)
{
PlayEmptySound();
return;
}
ammo.Spent = true;
var total_stdev = _spreadStdDevGun + ammo.SpreadStdDev_Ammo;
var final_evenspread = _evenSpreadAngleGun + ammo.EvenSpreadAngle_Ammo;
var final_velocity = _velocityGun + ammo.Velocity_Ammo;
FireAtCoord(user, clickLocation, ammo.ProjectileID, total_stdev, ammo.ProjectilesFired, final_evenspread, final_velocity);
}
protected IEntity GetChambered(int chamber) => _chambers[chamber].Slot.ContainedEntity;
/// <summary>
/// Loads the next ammo casing into the chamber.
/// </summary>
protected virtual void CycleChamberedBullet(int chamber) { }
public IEntity RemoveFromChamber(int chamber)
{
var c = _chambers[chamber];
var loaded = c.Slot.ContainedEntity;
if (loaded != null)
{
c.Slot.Remove(loaded);
}
return loaded;
}
protected bool LoadIntoChamber(int chamber, IEntity bullet)
{
if (!bullet.TryGetComponent(out BallisticBulletComponent component))
{
throw new ArgumentException("entity isn't a bullet.", nameof(bullet));
}
if (component.Caliber != _caliber)
{
throw new ArgumentException("entity is of the wrong caliber.", nameof(bullet));
}
if (GetChambered(chamber) != null)
{
return false;
}
_chambers[chamber].Slot.Insert(bullet);
return true;
}
private void PlayEmptySound() => EntitySystem.Get<AudioSystem>().PlayFromEntity(_soundGunEmpty, Owner);
protected sealed class Chamber
{
public Chamber(ContainerSlot slot)
{
Slot = slot;
}
public ContainerSlot Slot { get; }
}
private const int FirstChamber = 0;
}
}