Skip to content

Commit

Permalink
Merge pull request #587
Browse files Browse the repository at this point in the history
* Energy Guns (#385)

* Update heads.yml

* Update projectiles.yml

* Merge remote-tracking branch 'upstream/master' into laser

* Update license.txt

* Merge branch 'laser' of https://github.com/dvir001/frontier-station-1…

* Move to Sheriff BackSlot
  • Loading branch information
dvir001 authored Dec 10, 2023
1 parent e678b2a commit 7182e2d
Show file tree
Hide file tree
Showing 48 changed files with 567 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Server.DeltaV.Weapons.Ranged.Systems;

namespace Content.Server.DeltaV.Weapons.Ranged.Components;

/// <summary>
/// Allows for energy gun to switch between three modes. This also changes the sprite accordingly.
/// </summary>
/// <remarks>This is BatteryWeaponFireModesSystem with additional changes to allow for different sprites.</remarks>
[RegisterComponent]
[Access(typeof(EnergyGunSystem))]
[AutoGenerateComponentState]
public sealed partial class EnergyGunComponent : Component
{
/// <summary>
/// A list of the different firing modes the energy gun can switch between
/// </summary>
[DataField("fireModes", required: true)]
[AutoNetworkedField]
public List<EnergyWeaponFireMode> FireModes = new();

/// <summary>
/// The currently selected firing mode
/// </summary>
[DataField("currentFireMode")]
[AutoNetworkedField]
public EnergyWeaponFireMode? CurrentFireMode = default!;
}

[DataDefinition]
public sealed partial class EnergyWeaponFireMode
{
/// <summary>
/// The projectile prototype associated with this firing mode
/// </summary>
[DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype = default!;

/// <summary>
/// The battery cost to fire the projectile associated with this firing mode
/// </summary>
[DataField("fireCost")]
public float FireCost = 100;

/// <summary>
/// The name of the selected firemode
/// </summary>
[DataField("name")]
public string Name = string.Empty;

/// <summary>
/// What RsiState we use for that firemode if it needs to change.
/// </summary>
[DataField("state")]
public string State = string.Empty;
}
159 changes: 159 additions & 0 deletions Content.Server/DeltaV/Weapons/Ranged/Systems/EnergyGunSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using Content.Server.Popups;
using Content.Server.DeltaV.Weapons.Ranged.Components;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Verbs;
using Content.Shared.Item;
using Content.Shared.DeltaV.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Shared.Prototypes;
using System.Linq;

namespace Content.Server.DeltaV.Weapons.Ranged.Systems;

public sealed class EnergyGunSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<EnergyGunComponent, ActivateInWorldEvent>(OnInteractHandEvent);
SubscribeLocalEvent<EnergyGunComponent, GetVerbsEvent<Verb>>(OnGetVerb);
SubscribeLocalEvent<EnergyGunComponent, ExaminedEvent>(OnExamined);
}

private void OnExamined(EntityUid uid, EnergyGunComponent component, ExaminedEvent args)
{
if (component.FireModes == null || component.FireModes.Count < 2)
return;

if (component.CurrentFireMode == null)
{
SetFireMode(uid, component, component.FireModes.First());
}

if (component.CurrentFireMode?.Prototype == null)
return;

if (!_prototypeManager.TryIndex<EntityPrototype>(component.CurrentFireMode.Prototype, out var proto))
return;

args.PushMarkup(Loc.GetString("energygun-examine-fire-mode", ("mode", component.CurrentFireMode.Name != string.Empty ? component.CurrentFireMode.Name : proto.Name)));
}

private void OnGetVerb(EntityUid uid, EnergyGunComponent component, GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
return;

if (component.FireModes == null || component.FireModes.Count < 2)
return;

if (component.CurrentFireMode == null)
{
SetFireMode(uid, component, component.FireModes.First());
}

foreach (var fireMode in component.FireModes)
{
var entProto = _prototypeManager.Index<EntityPrototype>(fireMode.Prototype);

var v = new Verb
{
Priority = 1,
Category = VerbCategory.SelectType,
Text = entProto.Name,
Disabled = fireMode == component.CurrentFireMode,
Impact = LogImpact.Low,
DoContactInteraction = true,
Act = () =>
{
SetFireMode(uid, component, fireMode, args.User);
}
};

args.Verbs.Add(v);
}
}

private void OnInteractHandEvent(EntityUid uid, EnergyGunComponent component, ActivateInWorldEvent args)
{
if (component.FireModes == null || component.FireModes.Count < 2)
return;

CycleFireMode(uid, component, args.User);
}

private void CycleFireMode(EntityUid uid, EnergyGunComponent component, EntityUid user)
{
int index = (component.CurrentFireMode != null) ?
Math.Max(component.FireModes.IndexOf(component.CurrentFireMode), 0) + 1 : 1;

EnergyWeaponFireMode? fireMode;

if (index >= component.FireModes.Count)
{
fireMode = component.FireModes.FirstOrDefault();
}

else
{
fireMode = component.FireModes[index];
}

SetFireMode(uid, component, fireMode, user);
}

private void SetFireMode(EntityUid uid, EnergyGunComponent component, EnergyWeaponFireMode? fireMode, EntityUid? user = null)
{
if (fireMode?.Prototype == null)
return;

component.CurrentFireMode = fireMode;

if (TryComp(uid, out ProjectileBatteryAmmoProviderComponent? projectileBatteryAmmoProvider))
{
if (!_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var prototype))
return;

projectileBatteryAmmoProvider.Prototype = fireMode.Prototype;
projectileBatteryAmmoProvider.FireCost = fireMode.FireCost;

if (user != null)
{
_popupSystem.PopupEntity(Loc.GetString("gun-set-fire-mode", ("mode", component.CurrentFireMode.Name != string.Empty ? component.CurrentFireMode.Name : prototype.Name)), uid, user.Value);
}

if (component.CurrentFireMode.State == string.Empty)
return;

if (TryComp<AppearanceComponent>(uid, out var _) && TryComp<ItemComponent>(uid, out var item))
{
_item.SetHeldPrefix(uid, component.CurrentFireMode.State, item);
switch (component.CurrentFireMode.State)
{
case "disabler":
UpdateAppearance(uid, EnergyGunFireModeState.Disabler);
break;
case "lethal":
UpdateAppearance(uid, EnergyGunFireModeState.Lethal);
break;
case "special":
UpdateAppearance(uid, EnergyGunFireModeState.Special);
break;
}
}
}
}

private void UpdateAppearance(EntityUid uid, EnergyGunFireModeState state)
{
_appearance.SetData(uid, EnergyGunFireModeVisuals.State, state);
}
}
17 changes: 17 additions & 0 deletions Content.Shared/DeltaV/Weapons/Ranged/EnergyGunFireModeVisuals.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Robust.Shared.Serialization;

namespace Content.Shared.DeltaV.Weapons.Ranged;

[Serializable, NetSerializable]
public enum EnergyGunFireModeVisuals : byte
{
State
}

[Serializable, NetSerializable]
public enum EnergyGunFireModeState : byte
{
Disabler,
Lethal,
Special
}
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions Resources/Audio/DeltaV/license.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
typewriter.ogg is modified from https://www.freesoundslibrary.com/typewriter-sound/ which is licensed under the CC BY 4.0 License. This modified file follows the same license.
dry_fire.ogg from tgstation at https://github.com/tgstation/tgstation/blob/master/sound/weapons/gun/general/dry_fire.ogg which is licensed under the CC-BY-SA 3.0
laser.ogg from tgstation at https://github.com/tgstation/tgstation/blob/master/sound/weapons/laser.ogg which is licensed under the CC-BY-SA 3.0
1 change: 1 addition & 0 deletions Resources/Locale/en-US/deltav/weapons/ranged/energygun.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
energygun-examine-fire-mode = The firemode is set to {$mode}
5 changes: 4 additions & 1 deletion Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
- id: NitrogenTankFilled # Frontier
- id: JetpackMiniFilled # Frontier
- id: HandheldGPSBasic # Frontier
- id: WeaponEnergyGunMultiphase # DeltaV - HoS Energy Gun

- type: entity
id: LockerCaptainFilled
Expand Down Expand Up @@ -343,7 +344,7 @@
- id: JetpackSecurityFilled # Frontier
- id: HandheldGPSBasic # Frontier
- id: ClothingShoesBootsMagCombatFilled # Frontier

- type: entity
id: LockerHeadOfSecurityFilled
suffix: Filled
Expand Down Expand Up @@ -373,3 +374,5 @@
- id: BoxEncryptionKeySecurity
- id: HoloprojectorSecurity
# - id: BookSecretDocuments # Frontier
- id: ClothingNeckMantleHOS # Frontier
- id: ClothingOuterWinterHoS # Frontier
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
- type: entity
name: energy gun
parent: BaseWeaponBattery
id: WeaponEnergyGun
description: "A basic hybrid energy gun with two settings: disable and kill."
components:
- type: Sprite
sprite: DeltaV/Objects/Weapons/Guns/Battery/energygun.rsi
layers:
- state: base
map: ["enum.GunVisualLayers.Base"]
- state: mode-disabler
shader: unshaded
map: [ "Firemode" ]
- state: mag-unshaded-4
map: ["enum.GunVisualLayers.MagUnshaded"]
shader: unshaded
- type: Clothing
quickEquip: false # Frontier
slots: # Frontier
- Back # Frontier
- suitStorage # Frontier
sprite: DeltaV/Objects/Weapons/Guns/Battery/energygun.rsi
- type: Gun
soundGunshot:
path: /Audio/DeltaV/Weapons/Guns/Gunshots/laser.ogg
soundEmpty:
path: /Audio/DeltaV/Weapons/Guns/Empty/dry_fire.ogg
- type: Battery
maxCharge: 2000
startingCharge: 2000
- type: ProjectileBatteryAmmoProvider
proto: BulletDisabler
fireCost: 100
- type: EnergyGun
fireModes:
- proto: BulletDisabler
fireCost: 100
name: disable
state: disabler
- proto: BulletEnergyGunLaser
fireCost: 200
name: kill
state: lethal
- type: MagazineVisuals
magState: mag
steps: 5
zeroVisible: true
- type: Appearance
- type: GenericVisualizer
visuals:
enum.EnergyGunFireModeVisuals.State:
Firemode:
Disabler: { state: mode-disabler }
Lethal: { state: mode-lethal }
Special: { state: mode-stun } # Unused

- type: entity
name: x-01 multiphase energy gun
parent: BaseWeaponBatterySmall
id: WeaponEnergyGunMultiphase
description: This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time.
components:
- type: Sprite
sprite: DeltaV/Objects/Weapons/Guns/Battery/multiphase_energygun.rsi
layers:
- state: base
map: ["enum.GunVisualLayers.Base"]
- state: mode-disabler
shader: unshaded
map: [ "Firemode" ]
- state: mag-unshaded-4
map: ["enum.GunVisualLayers.MagUnshaded"]
shader: unshaded
- type: Clothing
quickEquip: false # Frontier
slots: # Frontier
- Back # Frontier
- suitStorage # Frontier
sprite: DeltaV/Objects/Weapons/Guns/Battery/multiphase_energygun.rsi
- type: Gun
soundGunshot:
path: /Audio/DeltaV/Weapons/Guns/Gunshots/laser.ogg
soundEmpty:
path: /Audio/DeltaV/Weapons/Guns/Empty/dry_fire.ogg
- type: Battery
maxCharge: 2000
startingCharge: 2000
- type: ProjectileBatteryAmmoProvider
proto: BulletDisabler
fireCost: 100
- type: EnergyGun
fireModes:
- proto: BulletDisabler
fireCost: 100
name: disable
state: disabler
- proto: BulletEnergyGunLaser
fireCost: 200
name: lethal
state: lethal
# - proto: BulletEnergyGunIon
# fireCost: 500
# name: ion
# state: special
- type: MagazineVisuals
magState: mag
steps: 5
zeroVisible: true
- type: Appearance
- type: GenericVisualizer
visuals:
enum.EnergyGunFireModeVisuals.State:
Firemode:
Disabler: { state: mode-disabler }
Lethal: { state: mode-lethal }
Special: { state: mode-ion }
- type: Tag
tags:
- HighRiskItem
- Sidearm
- type: StaticPrice
price: 750
Loading

0 comments on commit 7182e2d

Please sign in to comment.