[feat] Egun
@@ -30,4 +30,6 @@ public enum GunVisualLayers : byte
|
|||||||
BaseUnshaded,
|
BaseUnshaded,
|
||||||
Mag,
|
Mag,
|
||||||
MagUnshaded,
|
MagUnshaded,
|
||||||
|
TwoModeFirst,
|
||||||
|
TwoModeSecond
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,14 +251,19 @@ public sealed partial class GunSystem
|
|||||||
_ammoCount.Visible = true;
|
_ammoCount.Visible = true;
|
||||||
|
|
||||||
_ammoCount.Text = $"x{count:00}";
|
_ammoCount.Text = $"x{count:00}";
|
||||||
max = Math.Min(max, 8);
|
float step = 1;
|
||||||
FillBulletRow(_bulletsList, count, max);
|
if (max > 8)
|
||||||
|
{
|
||||||
|
step = ((float)max / 8);
|
||||||
|
}
|
||||||
|
FillBulletRow(_bulletsList, count, max, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillBulletRow(Control container, int count, int capacity)
|
private static void FillBulletRow(Control container, int count, int capacity, float step = 1)
|
||||||
{
|
{
|
||||||
var colorGone = Color.FromHex("#000000");
|
var colorGone = Color.FromHex("#000000");
|
||||||
var color = Color.FromHex("#E00000");
|
var color = Color.FromHex("#E00000");
|
||||||
|
int emptyNumber = 0;
|
||||||
|
|
||||||
// Draw the empty ones
|
// Draw the empty ones
|
||||||
for (var i = count; i < capacity; i++)
|
for (var i = count; i < capacity; i++)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ public sealed partial class GunSystem
|
|||||||
// Projectile
|
// Projectile
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, AmmoCounterControlEvent>(OnControl);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, AmmoCounterControlEvent>(OnControl);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, UpdateAmmoCounterEvent>(OnAmmoCountUpdate);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, UpdateAmmoCounterEvent>(OnAmmoCountUpdate);
|
||||||
|
|
||||||
|
// TwoModeEnergy
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, AmmoCounterControlEvent>(OnControl);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, UpdateAmmoCounterEvent>(OnAmmoCountUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAmmoCountUpdate(EntityUid uid, BatteryAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
private void OnAmmoCountUpdate(EntityUid uid, BatteryAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||||
|
|||||||
@@ -28,6 +28,18 @@ public sealed partial class GunSystem
|
|||||||
sprite.LayerSetState(GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{component.MagSteps - 1}");
|
sprite.LayerSetState(GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{component.MagSteps - 1}");
|
||||||
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeFirst, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(GunVisualLayers.TwoModeFirst, $"{component.MagState}-twomode1-{component.MagSteps - 1}");
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeFirst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeSecond, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(GunVisualLayers.TwoModeSecond, $"{component.MagState}-twomode2-{component.MagSteps - 1}");
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeSecond, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMagazineVisualsChange(EntityUid uid, MagazineVisualsComponent component, ref AppearanceChangeEvent args)
|
private void OnMagazineVisualsChange(EntityUid uid, MagazineVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
@@ -67,6 +79,16 @@ public sealed partial class GunSystem
|
|||||||
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeFirst, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeFirst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeSecond, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeSecond, false);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +103,27 @@ public sealed partial class GunSystem
|
|||||||
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, true);
|
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, true);
|
||||||
sprite.LayerSetState(GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{step}");
|
sprite.LayerSetState(GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{step}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!args.AppearanceData.TryGetValue(AmmoVisuals.InStun, out var inStun) || inStun is true)
|
||||||
|
{
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeFirst, out var _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeSecond, false);
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeFirst, true);
|
||||||
|
sprite.LayerSetState(GunVisualLayers.TwoModeFirst, $"{component.MagState}-twomode1-{step}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (inStun is false)
|
||||||
|
{
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeSecond, out var _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeFirst, false);
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeSecond, true);
|
||||||
|
sprite.LayerSetState(GunVisualLayers.TwoModeSecond, $"{component.MagState}-twomode2-{step}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -93,6 +136,16 @@ public sealed partial class GunSystem
|
|||||||
{
|
{
|
||||||
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
sprite.LayerSetVisible(GunVisualLayers.MagUnshaded, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeFirst, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeFirst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(GunVisualLayers.TwoModeSecond, out _))
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(GunVisualLayers.TwoModeSecond, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Events;
|
using Content.Shared.Damage.Events;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Projectiles;
|
using Content.Shared.Projectiles;
|
||||||
using Content.Shared.Weapons.Ranged;
|
using Content.Shared.Weapons.Ranged;
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
@@ -11,6 +12,8 @@ namespace Content.Server.Weapons.Ranged.Systems;
|
|||||||
|
|
||||||
public sealed partial class GunSystem
|
public sealed partial class GunSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
||||||
protected override void InitializeBattery()
|
protected override void InitializeBattery()
|
||||||
{
|
{
|
||||||
base.InitializeBattery();
|
base.InitializeBattery();
|
||||||
@@ -24,6 +27,41 @@ public sealed partial class GunSystem
|
|||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
||||||
|
|
||||||
|
//TwoModeEnergy
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
||||||
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, UseInHandEvent>(OnBatteryModeChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBatteryModeChange(EntityUid uid, TwoModeEnergyAmmoProviderComponent component, UseInHandEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<GunComponent>(uid, out var gun))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.CurrentMode == EnergyModes.Stun)
|
||||||
|
{
|
||||||
|
component.InStun = false;
|
||||||
|
gun.SoundGunshot = component.HitscanSound;
|
||||||
|
component.CurrentMode = EnergyModes.Laser;
|
||||||
|
component.FireCost = component.HitscanFireCost;
|
||||||
|
_audio.PlayPvs(component.ToggleSound, args.User);
|
||||||
|
}
|
||||||
|
else if (component.CurrentMode == EnergyModes.Laser)
|
||||||
|
{
|
||||||
|
component.InStun = true;
|
||||||
|
gun.SoundGunshot = component.ProjSound;
|
||||||
|
component.CurrentMode = EnergyModes.Stun;
|
||||||
|
component.FireCost = component.ProjFireCost;
|
||||||
|
_audio.PlayPvs(component.ToggleSound, args.User);
|
||||||
|
}
|
||||||
|
UpdateShots(uid, component);
|
||||||
|
UpdateTwoModeAppearance(uid, component);
|
||||||
|
UpdateBatteryAppearance(uid, component);
|
||||||
|
UpdateAmmoCount(uid);
|
||||||
|
Dirty(gun);
|
||||||
|
Dirty(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args)
|
private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args)
|
||||||
@@ -66,12 +104,24 @@ public sealed partial class GunSystem
|
|||||||
if (damageSpec == null)
|
if (damageSpec == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var damageType = component switch
|
string? damageType;
|
||||||
|
switch (component)
|
||||||
{
|
{
|
||||||
HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
|
case HitscanBatteryAmmoProviderComponent:
|
||||||
ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
|
damageType = Loc.GetString("damage-hitscan");
|
||||||
_ => throw new ArgumentOutOfRangeException(),
|
break;
|
||||||
};
|
case ProjectileBatteryAmmoProviderComponent:
|
||||||
|
damageType = Loc.GetString("damage-projectile");
|
||||||
|
break;
|
||||||
|
case TwoModeEnergyAmmoProviderComponent twoMode:
|
||||||
|
if (twoMode.CurrentMode == EnergyModes.Stun)
|
||||||
|
damageType = Loc.GetString("damage-projectile");
|
||||||
|
else
|
||||||
|
damageType = Loc.GetString("damage-hitscan");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
_damageExamine.AddDamageExamine(args.Message, damageSpec, damageType);
|
_damageExamine.AddDamageExamine(args.Message, damageSpec, damageType);
|
||||||
}
|
}
|
||||||
@@ -99,6 +149,25 @@ public sealed partial class GunSystem
|
|||||||
return ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
|
return ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component is TwoModeEnergyAmmoProviderComponent twoMode)
|
||||||
|
{
|
||||||
|
if (twoMode.CurrentMode == EnergyModes.Stun)
|
||||||
|
{
|
||||||
|
if (ProtoManager.Index<EntityPrototype>(twoMode.ProjectilePrototype).Components
|
||||||
|
.TryGetValue(_factory.GetComponentName(typeof(ProjectileComponent)), out var projectile))
|
||||||
|
{
|
||||||
|
var p = (ProjectileComponent) projectile.Component;
|
||||||
|
|
||||||
|
if (p.Damage.Total > FixedPoint2.Zero)
|
||||||
|
{
|
||||||
|
return p.Damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ProtoManager.Index<HitscanPrototype>(twoMode.HitscanPrototype).Damage;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public partial class GunComponent : Component
|
|||||||
#region Sound
|
#region Sound
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundGunshot")]
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundGunshot")]
|
||||||
public SoundSpecifier? SoundGunshot = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/smg.ogg");
|
public SoundSpecifier? SoundGunshot { get; set; } = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/smg.ogg");
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundEmpty")]
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundEmpty")]
|
||||||
public SoundSpecifier? SoundEmpty = new SoundPathSpecifier("/Audio/Weapons/Guns/Empty/empty.ogg");
|
public SoundSpecifier? SoundEmpty = new SoundPathSpecifier("/Audio/Weapons/Guns/Empty/empty.ogg");
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Weapons.Ranged.Components;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed class TwoModeEnergyAmmoProviderComponent : BatteryAmmoProviderComponent
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadOnly),
|
||||||
|
DataField("projProto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string ProjectilePrototype = default!;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly),
|
||||||
|
DataField("hitscanProto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<HitscanPrototype>))]
|
||||||
|
public string HitscanPrototype = default!;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), DataField("projFireCost")]
|
||||||
|
public float ProjFireCost = 50;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), DataField("hitscanFireCost")]
|
||||||
|
public float HitscanFireCost = 100;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), DataField("currentMode")]
|
||||||
|
public EnergyModes CurrentMode { get; set; } = EnergyModes.Stun;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), DataField("projSound")]
|
||||||
|
public SoundSpecifier? ProjSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/taser2.ogg");
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), DataField("hitscanSound")]
|
||||||
|
public SoundSpecifier? HitscanSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/laser_cannon.ogg");
|
||||||
|
|
||||||
|
public SoundSpecifier? ToggleSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Misc/egun_toggle.ogg");
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)] public bool InStun = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EnergyModes
|
||||||
|
{
|
||||||
|
Stun,
|
||||||
|
Laser
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Content.Shared.Weapons.Ranged.Events;
|
using Content.Shared.Weapons.Ranged.Events;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -9,6 +10,8 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
|||||||
|
|
||||||
public abstract partial class SharedGunSystem
|
public abstract partial class SharedGunSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||||
|
|
||||||
protected virtual void InitializeBattery()
|
protected virtual void InitializeBattery()
|
||||||
{
|
{
|
||||||
// Trying to dump comp references hence the below
|
// Trying to dump comp references hence the below
|
||||||
@@ -25,6 +28,62 @@ public abstract partial class SharedGunSystem
|
|||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
||||||
|
|
||||||
|
// TwoModeEnergy
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ComponentInit>(OnTwoModeInit);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ComponentGetState>(OnBatteryTwoModeGetState);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ComponentHandleState>(OnBatteryTwoModeHandleState);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
||||||
|
SubscribeLocalEvent<TwoModeEnergyAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnTwoModeInit(EntityUid uid, TwoModeEnergyAmmoProviderComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(component.Owner, out var appearance)) return;
|
||||||
|
|
||||||
|
Appearance.SetData(appearance.Owner, AmmoVisuals.InStun, component.InStun, appearance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBatteryTwoModeHandleState(EntityUid uid, TwoModeEnergyAmmoProviderComponent component, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not TwoModeComponentState state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.Shots = state.Shots;
|
||||||
|
component.Capacity = state.MaxShots;
|
||||||
|
component.FireCost = state.FireCost;
|
||||||
|
component.CurrentMode = state.CurrentMode;
|
||||||
|
component.InStun = state.InStun;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBatteryTwoModeGetState(EntityUid uid, TwoModeEnergyAmmoProviderComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new TwoModeComponentState()
|
||||||
|
{
|
||||||
|
Shots = component.Shots,
|
||||||
|
MaxShots = component.Capacity,
|
||||||
|
FireCost = component.FireCost,
|
||||||
|
CurrentMode = component.CurrentMode,
|
||||||
|
InStun = component.InStun
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateTwoModeAppearance(EntityUid uid, TwoModeEnergyAmmoProviderComponent component)
|
||||||
|
{
|
||||||
|
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||||
|
return;
|
||||||
|
if (!TryComp<ItemComponent?>(uid, out var item))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.InStun)
|
||||||
|
_item.SetHeldPrefix(uid, null, item);
|
||||||
|
else
|
||||||
|
_item.SetHeldPrefix(uid, "laser", item);
|
||||||
|
|
||||||
|
|
||||||
|
Appearance.SetData(uid, AmmoVisuals.InStun, component.InStun, appearance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
|
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
|
||||||
@@ -101,6 +160,13 @@ public abstract partial class SharedGunSystem
|
|||||||
return (ent, EnsureShootable(ent));
|
return (ent, EnsureShootable(ent));
|
||||||
case HitscanBatteryAmmoProviderComponent hitscan:
|
case HitscanBatteryAmmoProviderComponent hitscan:
|
||||||
return (null, ProtoManager.Index<HitscanPrototype>(hitscan.Prototype));
|
return (null, ProtoManager.Index<HitscanPrototype>(hitscan.Prototype));
|
||||||
|
case TwoModeEnergyAmmoProviderComponent twoMode:
|
||||||
|
if (twoMode.CurrentMode == EnergyModes.Stun)
|
||||||
|
{
|
||||||
|
var projEnt = Spawn(twoMode.ProjectilePrototype, coordinates);
|
||||||
|
return (projEnt, EnsureComp<AmmoComponent>(projEnt));
|
||||||
|
}
|
||||||
|
return (null, ProtoManager.Index<HitscanPrototype>(twoMode.HitscanPrototype));
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
@@ -113,4 +179,14 @@ public abstract partial class SharedGunSystem
|
|||||||
public int MaxShots;
|
public int MaxShots;
|
||||||
public float FireCost;
|
public float FireCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class TwoModeComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public EnergyModes CurrentMode { get; init; }
|
||||||
|
public int Shots;
|
||||||
|
public int MaxShots;
|
||||||
|
public float FireCost;
|
||||||
|
public bool InStun;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,20 @@ public abstract partial class SharedGunSystem
|
|||||||
("mode", GetLocSelector(component.SelectedMode))));
|
("mode", GetLocSelector(component.SelectedMode))));
|
||||||
args.PushMarkup(Loc.GetString("gun-fire-rate-examine", ("color", FireRateExamineColor),
|
args.PushMarkup(Loc.GetString("gun-fire-rate-examine", ("color", FireRateExamineColor),
|
||||||
("fireRate", $"{component.FireRate:0.0}")));
|
("fireRate", $"{component.FireRate:0.0}")));
|
||||||
|
|
||||||
|
if (!TryComp<TwoModeEnergyAmmoProviderComponent>(uid, out var comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString("gun-twomode-mode-examine", ("color", TwoModeExamineColor),
|
||||||
|
("mode", GetLocMode(comp.CurrentMode))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object GetLocMode(EnergyModes mode)
|
||||||
|
{
|
||||||
|
return Loc.GetString($"gun-twomode-{mode.ToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
private string GetLocSelector(SelectiveFire mode)
|
private string GetLocSelector(SelectiveFire mode)
|
||||||
{
|
{
|
||||||
return Loc.GetString($"gun-{mode.ToString()}");
|
return Loc.GetString($"gun-{mode.ToString()}");
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||||||
protected const string AmmoExamineColor = "yellow";
|
protected const string AmmoExamineColor = "yellow";
|
||||||
protected const string FireRateExamineColor = "yellow";
|
protected const string FireRateExamineColor = "yellow";
|
||||||
protected const string ModeExamineColor = "cyan";
|
protected const string ModeExamineColor = "cyan";
|
||||||
|
protected const string TwoModeExamineColor = "red";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -501,4 +502,5 @@ public enum AmmoVisuals : byte
|
|||||||
HasAmmo, // used for generic visualizers. c# stuff can just check ammocount != 0
|
HasAmmo, // used for generic visualizers. c# stuff can just check ammocount != 0
|
||||||
MagLoaded,
|
MagLoaded,
|
||||||
BoltClosed,
|
BoltClosed,
|
||||||
|
InStun
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Resources/Audio/Weapons/Guns/Misc/egun_toggle.ogg
Normal file
@@ -57,3 +57,13 @@
|
|||||||
cost: 5200
|
cost: 5200
|
||||||
category: Armory
|
category: Armory
|
||||||
group: market
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: ArmoryEgun
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Weapons/Guns/Battery/egun.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateArmoryEgun
|
||||||
|
cost: 2500
|
||||||
|
category: Armory
|
||||||
|
group: market
|
||||||
|
|||||||
@@ -57,3 +57,12 @@
|
|||||||
amount: 2
|
amount: 2
|
||||||
- id: MagazinePistol
|
- id: MagazinePistol
|
||||||
amount: 4
|
amount: 4
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateArmoryEgun
|
||||||
|
parent: CrateWeaponSecure
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: WeaponEgun
|
||||||
|
amount: 3
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
- id: CaptainIDCard
|
- id: CaptainIDCard
|
||||||
- id: ClothingOuterHardsuitCap
|
- id: ClothingOuterHardsuitCap
|
||||||
- id: ClothingMaskGasCaptain
|
- id: ClothingMaskGasCaptain
|
||||||
- id: WeaponDisabler
|
- id: WeaponEgun
|
||||||
- id: CommsComputerCircuitboard
|
- id: CommsComputerCircuitboard
|
||||||
- id: ClothingHeadsetAltCommand
|
- id: ClothingHeadsetAltCommand
|
||||||
- id: SpaceCash1000
|
- id: SpaceCash1000
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
- id: BoxID
|
- id: BoxID
|
||||||
- id: BoxHeadset
|
- id: BoxHeadset
|
||||||
- id: IDComputerCircuitboard
|
- id: IDComputerCircuitboard
|
||||||
- id: WeaponDisabler
|
- id: WeaponEgun
|
||||||
- id: CigarGoldCase
|
- id: CigarGoldCase
|
||||||
prob: 0.25
|
prob: 0.25
|
||||||
# Fuck the HoP they don't deserve fucking cigars.
|
# Fuck the HoP they don't deserve fucking cigars.
|
||||||
@@ -258,7 +258,10 @@
|
|||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
- id: ClothingEyesHudSecurity
|
- id: ClothingEyesHudSecurity
|
||||||
- id: WeaponDisabler
|
- id: WeaponEgun
|
||||||
|
- id: ClothingHeadHatBeretHoS
|
||||||
|
- id: ClothingHeadHatHoshat
|
||||||
|
- id: ClothingNeckCloakHos
|
||||||
- id: ClothingOuterCoatHoSTrench
|
- id: ClothingOuterCoatHoSTrench
|
||||||
- id: ClothingBeltSecurityFilled
|
- id: ClothingBeltSecurityFilled
|
||||||
- id: ClothingHeadsetAltSecurity
|
- id: ClothingHeadsetAltSecurity
|
||||||
|
|||||||
@@ -30,8 +30,9 @@
|
|||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
- id: FlashlightSeclite
|
- id: FlashlightSeclite
|
||||||
- id: WeaponDisabler
|
- id: WeaponEgun
|
||||||
prob: 0.3
|
- id: ClothingHeadHatWarden
|
||||||
|
- id: ClothingHeadHatBeretWarden
|
||||||
- id: ClothingBeltSecurityFilled
|
- id: ClothingBeltSecurityFilled
|
||||||
- id: Flash
|
- id: Flash
|
||||||
- id: ClothingEyesGlassesSunglasses
|
- id: ClothingEyesGlassesSunglasses
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
- id: WeaponMeleeNeedle
|
- id: WeaponMeleeNeedle
|
||||||
prob: 0.1
|
prob: 0.1
|
||||||
- id: ClothingEyesHudSecurity
|
- id: ClothingEyesHudSecurity
|
||||||
|
- id: WeaponEgun
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: LockerBrigmedicFilled
|
id: LockerBrigmedicFilled
|
||||||
@@ -103,6 +105,7 @@
|
|||||||
prob: 0.7
|
prob: 0.7
|
||||||
- id: ClothingNeckCloakMoth #bzzz Moth-pocalypse
|
- id: ClothingNeckCloakMoth #bzzz Moth-pocalypse
|
||||||
prob: 0.15
|
prob: 0.15
|
||||||
|
- id: WeaponEgun
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: LockerDetectiveFilled
|
id: LockerDetectiveFilled
|
||||||
|
|||||||
@@ -355,7 +355,7 @@
|
|||||||
walkModifier: 0.6
|
walkModifier: 0.6
|
||||||
sprintModifier: 0.6
|
sprintModifier: 0.6
|
||||||
- type: HeldSpeedModifier
|
- type: HeldSpeedModifier
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Weapons/Guns/Battery/particle_decelerator.rsi
|
sprite: Objects/Weapons/Guns/Battery/particle_decelerator.rsi
|
||||||
layers:
|
layers:
|
||||||
- state: base
|
- state: base
|
||||||
@@ -695,3 +695,41 @@
|
|||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 750
|
price: 750
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: egun
|
||||||
|
parent: BaseWeaponBattery
|
||||||
|
id: WeaponEgun
|
||||||
|
description: Egun
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Weapons/Guns/Battery/egun.rsi
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
map: ["enum.GunVisualLayers.Base"]
|
||||||
|
- state: mag-twomode1-4
|
||||||
|
map: ["enum.GunVisualLayers.TwoModeFirst"]
|
||||||
|
shader: unshaded
|
||||||
|
- state: mag-twomode2-4
|
||||||
|
map: ["enum.GunVisualLayers.TwoModeSecond"]
|
||||||
|
shader: unshaded
|
||||||
|
- type: Clothing
|
||||||
|
sprite: Objects/Weapons/Guns/Battery/egun.rsi
|
||||||
|
- type: Gun
|
||||||
|
soundGunshot:
|
||||||
|
path: /Audio/Weapons/Guns/Gunshots/taser2.ogg
|
||||||
|
- type: TwoModeEnergyAmmoProvider
|
||||||
|
projProto: BulletDisabler
|
||||||
|
fireCost: 50
|
||||||
|
projFireCost: 50
|
||||||
|
hitscanProto: RedLaser
|
||||||
|
hitscanFireCost: 100
|
||||||
|
projSound: "/Audio/Weapons/Guns/Gunshots/taser2.ogg"
|
||||||
|
hitscanSound: "/Audio/Weapons/Guns/Gunshots/laser_cannon.ogg"
|
||||||
|
- type: MagazineVisuals
|
||||||
|
magState: mag
|
||||||
|
steps: 5
|
||||||
|
zeroVisible: true
|
||||||
|
- type: Appearance
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 800
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
- HitscanBatteryAmmoProvider
|
- HitscanBatteryAmmoProvider
|
||||||
- ProjectileBatteryAmmoProvider
|
- ProjectileBatteryAmmoProvider
|
||||||
- Stunbaton
|
- Stunbaton
|
||||||
|
- TwoModeEnergyAmmoProvider
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseItemRecharger
|
parent: BaseItemRecharger
|
||||||
@@ -125,6 +126,7 @@
|
|||||||
- type: WallMount
|
- type: WallMount
|
||||||
- type: Charger
|
- type: Charger
|
||||||
chargeRate: 25
|
chargeRate: 25
|
||||||
|
slotId: charger_slot
|
||||||
- type: ItemSlots
|
- type: ItemSlots
|
||||||
slots:
|
slots:
|
||||||
charger_slot:
|
charger_slot:
|
||||||
@@ -134,6 +136,7 @@
|
|||||||
- HitscanBatteryAmmoProvider
|
- HitscanBatteryAmmoProvider
|
||||||
- ProjectileBatteryAmmoProvider
|
- ProjectileBatteryAmmoProvider
|
||||||
- Stunbaton
|
- Stunbaton
|
||||||
|
- TwoModeEnergyAmmoProvider
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseRecharger
|
parent: BaseRecharger
|
||||||
|
|||||||
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1012 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 115 B |
|
After Width: | Height: | Size: 117 B |
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 115 B |
|
After Width: | Height: | Size: 117 B |
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "Taken from White at https://github.com/frosty-dev/white",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode1-0",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.3,
|
||||||
|
0.3
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode1-1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode1-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode1-3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode1-4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode2-0",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.3,
|
||||||
|
0.3
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode2-1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode2-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode2-3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mag-twomode2-4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "inhand-left",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "inhand-right",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "laser-inhand-left",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "laser-inhand-right",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "equipped-BACKPACK",
|
||||||
|
"directions": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||