Add ESwords (now Inventory refactor compliant!) (#6000)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
@@ -332,7 +332,8 @@ namespace Content.Client.Entry
|
||||
"ArtifactGasTrigger",
|
||||
"ArtifactInteractionTrigger",
|
||||
"Artifact",
|
||||
"RandomArtifactSprite"
|
||||
"RandomArtifactSprite",
|
||||
"EnergySword",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
96
Content.Client/Weapons/Melee/EnergySwordVisualizer.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.Weapons.Melee;
|
||||
|
||||
public class EnergySwordVisualizer : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
component.TryGetData(EnergySwordVisuals.State, out EnergySwordStatus? status);
|
||||
status ??= EnergySwordStatus.Off;
|
||||
component.TryGetData(EnergySwordVisuals.Color, out Color? color);
|
||||
color ??= Color.DodgerBlue;
|
||||
entManager.TryGetComponent(component.Owner, out SpriteComponent? spriteComponent);
|
||||
|
||||
if ((status & EnergySwordStatus.On) != 0x0)
|
||||
{
|
||||
TurnOn(component, status.Value, color.Value, entManager, spriteComponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOff(component, status.Value, entManager, spriteComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private void TurnOn(
|
||||
AppearanceComponent component,
|
||||
EnergySwordStatus status,
|
||||
Color color,
|
||||
IEntityManager entManager,
|
||||
SpriteComponent? spriteComponent = null)
|
||||
{
|
||||
if ((status & EnergySwordStatus.Hacked) != 0x0)
|
||||
{
|
||||
if (entManager.TryGetComponent(component.Owner, out SharedItemComponent? itemComponent))
|
||||
{
|
||||
itemComponent.EquippedPrefix = "on-rainbow";
|
||||
}
|
||||
|
||||
//todo: figure out how to use the RGBLightControllerSystem to phase out the rainbow sprite AND add lights.
|
||||
spriteComponent?.LayerSetColor(1, Color.White);
|
||||
spriteComponent?.LayerSetVisible(1, false);
|
||||
spriteComponent?.LayerSetState(0, "e_sword_rainbow_on");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entManager.TryGetComponent(component.Owner, out SharedItemComponent? itemComponent))
|
||||
{
|
||||
itemComponent.EquippedPrefix = "on";
|
||||
itemComponent.Color = color;
|
||||
}
|
||||
|
||||
spriteComponent?.LayerSetColor(1, color);
|
||||
spriteComponent?.LayerSetVisible(1, true);
|
||||
|
||||
if (entManager.TryGetComponent(component.Owner, out PointLightComponent? pointLightComponent))
|
||||
{
|
||||
pointLightComponent.Color = color;
|
||||
pointLightComponent.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TurnOff(
|
||||
AppearanceComponent component,
|
||||
EnergySwordStatus status,
|
||||
IEntityManager entManager,
|
||||
SpriteComponent? spriteComponent = null)
|
||||
{
|
||||
if (entManager.TryGetComponent(component.Owner, out SharedItemComponent? itemComponent))
|
||||
{
|
||||
itemComponent.EquippedPrefix = "off";
|
||||
}
|
||||
|
||||
if ((status & EnergySwordStatus.Hacked) != 0x0)
|
||||
{
|
||||
spriteComponent?.LayerSetState(0, "e_sword");
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteComponent?.LayerSetVisible(1, false);
|
||||
}
|
||||
|
||||
if (entManager.TryGetComponent(component.Owner, out PointLightComponent? pointLightComponent))
|
||||
{
|
||||
pointLightComponent.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Weapon.Melee.EnergySword
|
||||
{
|
||||
[RegisterComponent, ComponentProtoName("EnergySword")]
|
||||
internal class EnergySwordComponent : Component
|
||||
{
|
||||
public Color BladeColor = Color.DodgerBlue;
|
||||
|
||||
public bool Hacked = false;
|
||||
|
||||
public bool Activated = false;
|
||||
[DataField("hitSound")]
|
||||
public SoundSpecifier HitSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/eblade1.ogg");
|
||||
|
||||
[DataField("activateSound")]
|
||||
public SoundSpecifier ActivateSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/ebladeon.ogg");
|
||||
|
||||
[DataField("deActivateSound")]
|
||||
public SoundSpecifier DeActivateSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/ebladeoff.ogg");
|
||||
|
||||
[DataField("colorOptions")]
|
||||
public List<Color> ColorOptions = new()
|
||||
{
|
||||
Color.Tomato,
|
||||
Color.DodgerBlue,
|
||||
Color.Aqua,
|
||||
Color.MediumSpringGreen,
|
||||
Color.MediumOrchid
|
||||
};
|
||||
|
||||
[DataField("litDamageBonus", required: true)]
|
||||
public DamageSpecifier LitDamageBonus = default!;
|
||||
}
|
||||
}
|
||||
130
Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Content.Server.Tools.Components;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Weapon.Melee.EnergySword
|
||||
{
|
||||
internal class EnergySwordSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ActionBlockerSystem _blockerSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<EnergySwordComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<EnergySwordComponent, MeleeHitEvent>(OnMeleeHit);
|
||||
SubscribeLocalEvent<EnergySwordComponent, UseInHandEvent>(OnUseInHand);
|
||||
SubscribeLocalEvent<EnergySwordComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, EnergySwordComponent comp, MapInitEvent args)
|
||||
{
|
||||
if (comp.ColorOptions.Count != 0)
|
||||
comp.BladeColor = _random.Pick(comp.ColorOptions);
|
||||
}
|
||||
|
||||
private void OnMeleeHit(EntityUid uid, EnergySwordComponent comp, MeleeHitEvent args)
|
||||
{
|
||||
if (!comp.Activated) return;
|
||||
|
||||
if (args.Handled) return;
|
||||
|
||||
args.Handled = true;
|
||||
// Overrides basic blunt damage with burn+slash as set in yaml
|
||||
args.BonusDamage = comp.LitDamageBonus;
|
||||
args.HitSoundOverride = comp.HitSound;
|
||||
}
|
||||
|
||||
private void OnUseInHand(EntityUid uid, EnergySwordComponent comp, UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
|
||||
if (!_blockerSystem.CanUse(args.User))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
if (comp.Activated)
|
||||
{
|
||||
TurnOff(comp);
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOn(comp);
|
||||
}
|
||||
}
|
||||
|
||||
private void TurnOff(EnergySwordComponent comp)
|
||||
{
|
||||
if (!comp.Activated)
|
||||
return;
|
||||
|
||||
if (TryComp(comp.Owner, out SharedItemComponent? item))
|
||||
{
|
||||
item.Size = 5;
|
||||
}
|
||||
|
||||
SoundSystem.Play(Filter.Pvs(comp.Owner), comp.DeActivateSound.GetSound(), comp.Owner);
|
||||
|
||||
comp.Activated = false;
|
||||
UpdateAppearance(comp, item);
|
||||
}
|
||||
|
||||
private void TurnOn(EnergySwordComponent comp)
|
||||
{
|
||||
if (comp.Activated)
|
||||
return;
|
||||
|
||||
if (TryComp(comp.Owner, out SharedItemComponent? item))
|
||||
{
|
||||
item.Size = 9999;
|
||||
}
|
||||
|
||||
SoundSystem.Play(Filter.Pvs(comp.Owner), comp.ActivateSound.GetSound(), comp.Owner);
|
||||
|
||||
comp.Activated = true;
|
||||
UpdateAppearance(comp, item);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EnergySwordComponent component, SharedItemComponent? itemComponent = null)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComponent)) return;
|
||||
|
||||
appearanceComponent.SetData(EnergySwordVisuals.Color, component.BladeColor);
|
||||
|
||||
var status = component.Activated ? EnergySwordStatus.On : EnergySwordStatus.Off;
|
||||
if (component.Hacked)
|
||||
status |= EnergySwordStatus.Hacked;
|
||||
|
||||
appearanceComponent.SetData(EnergySwordVisuals.State, status);
|
||||
// wew itemcomp
|
||||
if (Resolve(component.Owner, ref itemComponent, false))
|
||||
{
|
||||
itemComponent.EquippedPrefix = component.Activated ? "on" : "off";
|
||||
itemComponent.Color = component.BladeColor;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractUsing(EntityUid uid, EnergySwordComponent comp, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
|
||||
if (comp.Hacked || !_blockerSystem.CanInteract(args.User))
|
||||
return;
|
||||
|
||||
if (!TryComp(args.Used, out ToolComponent? tool) || !tool.Qualities.ContainsAny("Pulsing")) return;
|
||||
|
||||
args.Handled = true;
|
||||
comp.Hacked = true;
|
||||
UpdateAppearance(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Cooldown;
|
||||
using Content.Server.Weapon.Melee.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Sound;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -107,7 +109,14 @@ namespace Content.Server.Weapon.Melee
|
||||
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(args.Target.Value):target} using {ToPrettyString(args.Used):used} and dealt {damageResult.Total:damage} damage");
|
||||
}
|
||||
|
||||
SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), target);
|
||||
if (hitEvent.HitSoundOverride != null)
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(owner), hitEvent.HitSoundOverride.GetSound(), target, AudioHelpers.WithVariation(0.25f));
|
||||
}
|
||||
else
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -320,6 +329,12 @@ namespace Content.Server.Weapon.Melee
|
||||
/// </summary>
|
||||
public IEnumerable<EntityUid> HitEntities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to define a new hit sound in case you want to override the default GenericHit.
|
||||
/// Also gets a pitch modifier added to it.
|
||||
/// </summary>
|
||||
public SoundSpecifier? HitSoundOverride {get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// The user who attacked with the melee weapon.
|
||||
/// </summary>
|
||||
|
||||
20
Content.Shared/Weapons/Melee/SharedEnergySwordComponent.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Weapons.Melee;
|
||||
|
||||
|
||||
[Serializable, NetSerializable, Flags]
|
||||
public enum EnergySwordStatus : byte
|
||||
{
|
||||
Off = 0,
|
||||
On = 1 << 0,
|
||||
Hacked = 1 << 1,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum EnergySwordVisuals : byte
|
||||
{
|
||||
State,
|
||||
Color,
|
||||
}
|
||||
BIN
Resources/Audio/Weapons/eblade1.ogg
Normal file
BIN
Resources/Audio/Weapons/ebladeoff.ogg
Normal file
BIN
Resources/Audio/Weapons/ebladeon.ogg
Normal file
@@ -31,12 +31,14 @@
|
||||
# itemId: CrossbowEnergyMini
|
||||
# price: 8
|
||||
|
||||
# bug swept to make
|
||||
#- type: uplinkListing
|
||||
# id: UplinkESword
|
||||
# category: Weapons
|
||||
# itemId: ESword
|
||||
# price: 8
|
||||
|
||||
- type: uplinkListing
|
||||
id: UplinkEsword
|
||||
category: Weapons
|
||||
itemId: EnergySword
|
||||
listingName: Energy Sword
|
||||
description: A very dangerous energy sword. Can be stored in pockets when turned off. Makes a lot of noise when used or turned on.
|
||||
price: 8
|
||||
|
||||
# bug swept to make
|
||||
#- type: uplinkListing
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
- type: entity
|
||||
name: energy sword
|
||||
parent: BaseItem
|
||||
id: EnergySword
|
||||
description: A very dangerous energy sword. Can be stored in pockets when turned off. Makes a lot of noise when used or turned on.
|
||||
components:
|
||||
- type: EnergySword
|
||||
litDamageBonus:
|
||||
types:
|
||||
Slash: 12.5
|
||||
Heat: 12.5
|
||||
Blunt: -7
|
||||
- type: Sprite
|
||||
sprite: Objects/Weapons/Melee/e_sword.rsi
|
||||
layers:
|
||||
- state: e_sword
|
||||
- state: e_sword_blade
|
||||
color: "#FFFFFF"
|
||||
visible: false
|
||||
shader: unshaded
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
types:
|
||||
Blunt: 7
|
||||
- type: Item
|
||||
size: 5
|
||||
sprite: Objects/Weapons/Melee/e_sword.rsi
|
||||
- type: UseDelay
|
||||
delay: 1.0
|
||||
- type: PointLight
|
||||
netsync: false
|
||||
enabled: false
|
||||
radius: 2
|
||||
energy: 2
|
||||
color: white
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: EnergySwordVisualizer
|
||||
BIN
Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword.png
Normal file
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 826 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 1.5 KiB |
227
Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/meta.json
Normal file
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "e_sword"
|
||||
},
|
||||
{
|
||||
"name": "off-inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "off-inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "e_sword_rainbow_on",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "e_sword_on",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "e_sword_blade",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "on-inhand-left",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "on-inhand-right",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "on-rainbow-inhand-left",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "on-rainbow-inhand-right",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 984 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |