Files
tbd-station-14/Content.Server/Weapon/Ranged/Ammunition/Components/AmmoComponent.cs
T-Stalker f88fe48a6a Adds Onestar mech ghost-role enemy (#6943)
Co-authored-by: mirrorcult <lunarautomaton6@gmail.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2022-03-12 16:14:17 -07:00

128 lines
3.9 KiB
C#

using System;
using Content.Shared.Examine;
using Content.Shared.Sound;
using Content.Shared.Weapons.Ranged.Barrels.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Weapon.Ranged.Ammunition.Components
{
/// <summary>
/// Allows this entity to be loaded into a ranged weapon (if the caliber matches)
/// Generally used for bullets but can be used for other things like bananas
/// </summary>
[RegisterComponent]
[Friend(typeof(GunSystem))]
public sealed class AmmoComponent : Component, ISerializationHooks
{
[DataField("caliber")]
public BallisticCaliber Caliber { get; } = BallisticCaliber.Unspecified;
public bool Spent
{
get
{
if (AmmoIsProjectile)
{
return false;
}
return _spent;
}
set => _spent = value;
}
private bool _spent;
// TODO: Make it so null projectile = dis
/// <summary>
/// Used for anything without a case that fires itself
/// </summary>
[DataField("isProjectile")] public bool AmmoIsProjectile;
/// <summary>
/// Used for something that is deleted when the projectile is retrieved
/// </summary>
[DataField("caseless")]
public bool Caseless { get; }
// Rather than managing bullet / case state seemed easier to just have 2 toggles
// ammoIsProjectile being for a beanbag for example and caseless being for ClRifle rounds
/// <summary>
/// For shotguns where they might shoot multiple entities
/// </summary>
[DataField("projectilesFired")]
public int ProjectilesFired { get; } = 1;
[DataField("projectile", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? ProjectileId;
// How far apart each entity is if multiple are shot
[DataField("ammoSpread")]
public float EvenSpreadAngle { get; } = default;
/// <summary>
/// How fast the shot entities travel
/// </summary>
[DataField("ammoVelocity")]
public float Velocity { get; } = 20f;
[DataField("muzzleFlash")]
public ResourcePath? MuzzleFlashSprite = new("Objects/Weapons/Guns/Projectiles/bullet_muzzle.png");
[DataField("soundCollectionEject")]
public SoundSpecifier SoundCollectionEject { get; } = new SoundCollectionSpecifier("CasingEject");
void ISerializationHooks.AfterDeserialization()
{
// Being both caseless and shooting yourself doesn't make sense
DebugTools.Assert(!(AmmoIsProjectile && Caseless));
if (ProjectilesFired < 1)
{
Logger.Error("Ammo can't have less than 1 projectile");
}
if (EvenSpreadAngle > 0 && ProjectilesFired == 1)
{
Logger.Error("Can't have an even spread if only 1 projectile is fired");
throw new InvalidOperationException();
}
}
}
public enum BallisticCaliber
{
Unspecified = 0,
A357, // Placeholder?
ClRifle,
SRifle,
Pistol,
A35, // Placeholder?
LRifle,
HRifle,
Magnum,
AntiMaterial,
Shotgun,
Cap,
Rocket,
Dart, // Placeholder
Grenade,
Energy,
}
}