ECS guns (#6229)
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
This commit is contained in:
228
Content.Server/Weapon/Ranged/GunSystem.Revolvers.cs
Normal file
228
Content.Server/Weapon/Ranged/GunSystem.Revolvers.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using Content.Server.Weapon.Ranged.Ammunition.Components;
|
||||
using Content.Server.Weapon.Ranged.Barrels.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Weapons.Ranged.Barrels.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Weapon.Ranged;
|
||||
|
||||
public sealed partial class GunSystem
|
||||
{
|
||||
private void OnRevolverUse(EntityUid uid, RevolverBarrelComponent component, UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
|
||||
EjectAllSlots(component);
|
||||
component.Dirty(EntityManager);
|
||||
UpdateRevolverAppearance(component);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRevolverInteractUsing(EntityUid uid, RevolverBarrelComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
|
||||
if (TryInsertBullet(args.User, args.Used, component))
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public bool TryInsertBullet(EntityUid user, EntityUid entity, RevolverBarrelComponent component)
|
||||
{
|
||||
if (!TryComp(entity, out AmmoComponent? ammoComponent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ammoComponent.Caliber != component.Caliber)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("revolver-barrel-component-try-insert-bullet-wrong-caliber"), component.Owner, Filter.Entities(user));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Functions like a stack
|
||||
// These are inserted in reverse order but then when fired Cycle will go through in order
|
||||
// The reason we don't just use an actual stack is because spin can select a random slot to point at
|
||||
for (var i = component.AmmoSlots.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var slot = component.AmmoSlots[i];
|
||||
if (slot == default)
|
||||
{
|
||||
component.CurrentSlot = i;
|
||||
component.AmmoSlots[i] = entity;
|
||||
component.AmmoContainer.Insert(entity);
|
||||
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundInsert.GetSound(), component.Owner, AudioParams.Default.WithVolume(-2));
|
||||
|
||||
component.Dirty(EntityManager);
|
||||
UpdateRevolverAppearance(component);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("revolver-barrel-component-try-insert-bullet-ammo-full"), ammoComponent.Owner, Filter.Entities(user));
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Russian Roulette
|
||||
/// </summary>
|
||||
public void SpinRevolver(RevolverBarrelComponent component)
|
||||
{
|
||||
var random = _random.Next(component.AmmoSlots.Length - 1);
|
||||
component.CurrentSlot = random;
|
||||
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundSpin.GetSound(), component.Owner, AudioParams.Default.WithVolume(-2));
|
||||
component.Dirty(EntityManager);
|
||||
}
|
||||
|
||||
public void CycleRevolver(RevolverBarrelComponent component)
|
||||
{
|
||||
// Move up a slot
|
||||
component.CurrentSlot = (component.CurrentSlot + 1) % component.AmmoSlots.Length;
|
||||
component.Dirty(EntityManager);
|
||||
UpdateRevolverAppearance(component);
|
||||
}
|
||||
|
||||
private void EjectAllSlots(RevolverBarrelComponent component)
|
||||
{
|
||||
for (var i = 0; i < component.AmmoSlots.Length; i++)
|
||||
{
|
||||
var entity = component.AmmoSlots[i];
|
||||
if (entity == null) continue;
|
||||
|
||||
component.AmmoContainer.Remove(entity.Value);
|
||||
EjectCasing(entity.Value);
|
||||
component.AmmoSlots[i] = null;
|
||||
}
|
||||
|
||||
if (component.AmmoContainer.ContainedEntities.Count > 0)
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundEject.GetSound(), component.Owner, AudioParams.Default.WithVolume(-1));
|
||||
}
|
||||
|
||||
// May as well point back at the end?
|
||||
component.CurrentSlot = component.AmmoSlots.Length - 1;
|
||||
}
|
||||
|
||||
private void OnRevolverGetState(EntityUid uid, RevolverBarrelComponent component, ref ComponentGetState args)
|
||||
{
|
||||
var slotsSpent = new bool?[component.Capacity];
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
{
|
||||
slotsSpent[i] = null;
|
||||
var ammoEntity = component.AmmoSlots[i];
|
||||
if (ammoEntity != default && TryComp(ammoEntity, out AmmoComponent? ammo))
|
||||
{
|
||||
slotsSpent[i] = ammo.Spent;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: make yaml var to not sent currentSlot/UI? (for russian roulette)
|
||||
args.State = new RevolverBarrelComponentState(
|
||||
component.CurrentSlot,
|
||||
component.FireRateSelector,
|
||||
slotsSpent,
|
||||
component.SoundGunshot.GetSound());
|
||||
}
|
||||
|
||||
private void OnRevolverMapInit(EntityUid uid, RevolverBarrelComponent component, MapInitEvent args)
|
||||
{
|
||||
component.UnspawnedCount = component.Capacity;
|
||||
var idx = 0;
|
||||
component.AmmoContainer = component.Owner.EnsureContainer<Container>($"{component.GetType()}-ammoContainer", out var existing);
|
||||
if (existing)
|
||||
{
|
||||
foreach (var entity in component.AmmoContainer.ContainedEntities)
|
||||
{
|
||||
component.UnspawnedCount--;
|
||||
component.AmmoSlots[idx] = entity;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Revolvers should also defer spawning T B H
|
||||
var xform = EntityManager.GetComponent<TransformComponent>(uid);
|
||||
|
||||
for (var i = 0; i < component.UnspawnedCount; i++)
|
||||
{
|
||||
var entity = EntityManager.SpawnEntity(component.FillPrototype, xform.Coordinates);
|
||||
component.AmmoSlots[idx] = entity;
|
||||
component.AmmoContainer.Insert(entity);
|
||||
idx++;
|
||||
}
|
||||
|
||||
UpdateRevolverAppearance(component);
|
||||
component.Dirty(EntityManager);
|
||||
}
|
||||
|
||||
private void UpdateRevolverAppearance(RevolverBarrelComponent component)
|
||||
{
|
||||
if (!TryComp(component.Owner, out AppearanceComponent? appearance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Placeholder, at this stage it's just here for the RPG
|
||||
appearance.SetData(MagazineBarrelVisuals.MagLoaded, component.ShotsLeft > 0);
|
||||
appearance.SetData(AmmoVisuals.AmmoCount, component.ShotsLeft);
|
||||
appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity);
|
||||
}
|
||||
|
||||
private void AddSpinVerb(EntityUid uid, RevolverBarrelComponent component, GetAlternativeVerbsEvent args)
|
||||
{
|
||||
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
if (component.Capacity <= 1 || component.ShotsLeft == 0)
|
||||
return;
|
||||
|
||||
Verb verb = new()
|
||||
{
|
||||
Text = Loc.GetString("spin-revolver-verb-get-data-text"),
|
||||
IconTexture = "/Textures/Interface/VerbIcons/refresh.svg.192dpi.png",
|
||||
Act = () =>
|
||||
{
|
||||
SpinRevolver(component);
|
||||
component.Owner.PopupMessage(args.User, Loc.GetString("spin-revolver-verb-on-activate"));
|
||||
}
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public EntityUid? PeekAmmo(RevolverBarrelComponent component)
|
||||
{
|
||||
return component.AmmoSlots[component.CurrentSlot];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a projectile out if possible
|
||||
/// IEnumerable just to make supporting shotguns saner
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public EntityUid? TakeProjectile(RevolverBarrelComponent component, EntityCoordinates spawnAt)
|
||||
{
|
||||
var ammo = component.AmmoSlots[component.CurrentSlot];
|
||||
EntityUid? bullet = null;
|
||||
if (ammo != null)
|
||||
{
|
||||
var ammoComponent = EntityManager.GetComponent<AmmoComponent>(ammo.Value);
|
||||
bullet = TakeBullet(ammoComponent, spawnAt);
|
||||
if (ammoComponent.Caseless)
|
||||
{
|
||||
component.AmmoSlots[component.CurrentSlot] = null;
|
||||
component.AmmoContainer.Remove(ammo.Value);
|
||||
}
|
||||
}
|
||||
CycleRevolver(component);
|
||||
UpdateRevolverAppearance(component);
|
||||
return bullet;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user