Co-authored-by: mirrorcult <lunarautomaton6@gmail.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
128 lines
3.9 KiB
C#
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,
|
|
}
|
|
}
|