diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 8bbad8b1ad..add0962dca 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -332,7 +332,8 @@ namespace Content.Client.Entry "ArtifactGasTrigger", "ArtifactInteractionTrigger", "Artifact", - "RandomArtifactSprite" + "RandomArtifactSprite", + "EnergySword", }; } } diff --git a/Content.Client/Weapons/Melee/EnergySwordVisualizer.cs b/Content.Client/Weapons/Melee/EnergySwordVisualizer.cs new file mode 100644 index 0000000000..323bbeaedd --- /dev/null +++ b/Content.Client/Weapons/Melee/EnergySwordVisualizer.cs @@ -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(); + + 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; + } + } +} diff --git a/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs b/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs new file mode 100644 index 0000000000..4950fee69d --- /dev/null +++ b/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs @@ -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 ColorOptions = new() + { + Color.Tomato, + Color.DodgerBlue, + Color.Aqua, + Color.MediumSpringGreen, + Color.MediumOrchid + }; + + [DataField("litDamageBonus", required: true)] + public DamageSpecifier LitDamageBonus = default!; + } +} diff --git a/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs new file mode 100644 index 0000000000..e48032aebb --- /dev/null +++ b/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs @@ -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(OnMapInit); + SubscribeLocalEvent(OnMeleeHit); + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(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); + } + } +} diff --git a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs index 14e8d78330..ba1e2cc048 100644 --- a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs @@ -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 /// public IEnumerable HitEntities { get; } + /// + /// Used to define a new hit sound in case you want to override the default GenericHit. + /// Also gets a pitch modifier added to it. + /// + public SoundSpecifier? HitSoundOverride {get; set;} + /// /// The user who attacked with the melee weapon. /// diff --git a/Content.Shared/Weapons/Melee/SharedEnergySwordComponent.cs b/Content.Shared/Weapons/Melee/SharedEnergySwordComponent.cs new file mode 100644 index 0000000000..45fd78d689 --- /dev/null +++ b/Content.Shared/Weapons/Melee/SharedEnergySwordComponent.cs @@ -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, +} diff --git a/Resources/Audio/Weapons/eblade1.ogg b/Resources/Audio/Weapons/eblade1.ogg new file mode 100644 index 0000000000..583fbf19e8 Binary files /dev/null and b/Resources/Audio/Weapons/eblade1.ogg differ diff --git a/Resources/Audio/Weapons/ebladeoff.ogg b/Resources/Audio/Weapons/ebladeoff.ogg new file mode 100644 index 0000000000..d805414bdc Binary files /dev/null and b/Resources/Audio/Weapons/ebladeoff.ogg differ diff --git a/Resources/Audio/Weapons/ebladeon.ogg b/Resources/Audio/Weapons/ebladeon.ogg new file mode 100644 index 0000000000..c5d2217edd Binary files /dev/null and b/Resources/Audio/Weapons/ebladeon.ogg differ diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 63dcc04d03..1c713441de 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml new file mode 100644 index 0000000000..aa75f3c4a6 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -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 diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword.png new file mode 100644 index 0000000000..c231db05b3 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_blade.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_blade.png new file mode 100644 index 0000000000..28e0ec67a8 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_blade.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_on.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_on.png new file mode 100644 index 0000000000..521324817e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_rainbow_on.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_rainbow_on.png new file mode 100644 index 0000000000..02326c8999 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/e_sword_rainbow_on.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/meta.json new file mode 100644 index 0000000000..5aae86289b --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/meta.json @@ -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 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-left.png new file mode 100644 index 0000000000..6e5fe94f81 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-right.png new file mode 100644 index 0000000000..b82aed42c0 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/off-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-left.png new file mode 100644 index 0000000000..b0c4c24359 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-right.png new file mode 100644 index 0000000000..6585cdc73d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-left.png new file mode 100644 index 0000000000..974889d984 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-right.png new file mode 100644 index 0000000000..432c057f4b Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/e_sword.rsi/on-rainbow-inhand-right.png differ