diff --git a/Content.Client/_White/Animations/FlipOnHitSystem.cs b/Content.Client/_White/Animations/FlipOnHitSystem.cs new file mode 100644 index 0000000000..d501bd75fe --- /dev/null +++ b/Content.Client/_White/Animations/FlipOnHitSystem.cs @@ -0,0 +1,75 @@ +using Content.Shared._White.Animations; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Shared.Animations; +using Robust.Shared.Timing; + +namespace Content.Client._White.Animations; + +public sealed class FlipOnHitSystem : SharedFlipOnHitSystem +{ + [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAnimationComplete); + SubscribeAllEvent(ev => PlayAnimation(GetEntity(ev.User))); + } + + private void OnAnimationComplete(Entity ent, ref AnimationCompletedEvent args) + { + if (args.Key != FlippingComponent.AnimationKey) + return; + + PlayAnimation(ent); + } + + protected override void PlayAnimation(EntityUid user) + { + if (!_timing.IsFirstTimePredicted) + return; + + if (TerminatingOrDeleted(user)) + return; + + if (_animationSystem.HasRunningAnimation(user, FlippingComponent.AnimationKey)) + { + EnsureComp(user); + return; + } + + RemComp(user); + + var baseAngle = Angle.Zero; + if (EntityManager.TryGetComponent(user, out SpriteComponent? sprite)) + baseAngle = sprite.Rotation; + + var degrees = baseAngle.Degrees; + + var animation = new Animation + { + Length = TimeSpan.FromMilliseconds(400), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Rotation), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(degrees - 10), 0f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(degrees + 180), 0.2f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(degrees + 360), 0.2f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(degrees), 0f) + } + } + } + }; + + _animationSystem.Play(user, animation, FlippingComponent.AnimationKey); + } +} diff --git a/Content.Client/_White/Animations/FlippingComponent.cs b/Content.Client/_White/Animations/FlippingComponent.cs new file mode 100644 index 0000000000..504c5f7938 --- /dev/null +++ b/Content.Client/_White/Animations/FlippingComponent.cs @@ -0,0 +1,7 @@ +namespace Content.Client._White.Animations; + +[RegisterComponent] +public sealed partial class FlippingComponent : Component +{ + public const string AnimationKey = "flip"; +} diff --git a/Content.Server/Construction/ConstructionSystem.Graph.cs b/Content.Server/Construction/ConstructionSystem.Graph.cs index 1b74fd9d4e..ec8fe049c9 100644 --- a/Content.Server/Construction/ConstructionSystem.Graph.cs +++ b/Content.Server/Construction/ConstructionSystem.Graph.cs @@ -9,6 +9,7 @@ using Robust.Shared.Containers; using Robust.Shared.Prototypes; using System.Linq; +using Content.Shared.Hands.Components; namespace Content.Server.Construction { @@ -304,8 +305,8 @@ public bool ChangeNode(EntityUid uid, EntityUid? userUid, string id, bool perfor return null; // [Optional] Exit if the new entity's prototype is a parent of the original - // E.g., if an entity with the 'AirlockCommand' prototype was to be replaced with a new entity that - // had the 'Airlock' prototype, and DoNotReplaceInheritingEntities was true, the code block would + // E.g., if an entity with the 'AirlockCommand' prototype was to be replaced with a new entity that + // had the 'Airlock' prototype, and DoNotReplaceInheritingEntities was true, the code block would // exit here because 'AirlockCommand' is derived from 'Airlock' if (GetCurrentNode(uid, construction)?.DoNotReplaceInheritingEntities == true && metaData.EntityPrototype?.ID != null) @@ -394,6 +395,17 @@ public bool ChangeNode(EntityUid uid, EntityUid? userUid, string id, bool perfor } } + // WD EDIT START + if (userUid != null && IsTransformParentOf(userUid.Value, transform) && TryComp(userUid, out HandsComponent? hands)) + { + var hand = hands.Hands.Values.FirstOrDefault(h => h.HeldEntity == uid); + if (hand != null) + _handsSystem.TryDrop(userUid.Value, hand, handsComp: hands); + + _handsSystem.PickupOrDrop(userUid, newUid, handsComp: hands); + } + // WD EDIT END + var entChangeEv = new ConstructionChangeEntityEvent(newUid, uid); RaiseLocalEvent(uid, entChangeEv); RaiseLocalEvent(newUid, entChangeEv, broadcast: true); @@ -410,6 +422,13 @@ public bool ChangeNode(EntityUid uid, EntityUid? userUid, string id, bool perfor return newUid; } + private bool IsTransformParentOf(EntityUid uid, TransformComponent target) // WD EDIT + { + var parentUid = target.ParentUid; + + return parentUid == uid || TryComp(parentUid, out TransformComponent? trans) && IsTransformParentOf(uid, trans); + } + /// /// Performs a construction graph change on a construction entity, also changing the node to a valid one on /// the new graph. diff --git a/Content.Server/_White/Animations/FlipOnHitSystem.cs b/Content.Server/_White/Animations/FlipOnHitSystem.cs new file mode 100644 index 0000000000..714cad5bc8 --- /dev/null +++ b/Content.Server/_White/Animations/FlipOnHitSystem.cs @@ -0,0 +1,17 @@ +using Content.Shared._White.Animations; +using Robust.Shared.Player; + +namespace Content.Server._White.Animations; + +public sealed class FlipOnHitSystem : SharedFlipOnHitSystem +{ + protected override void PlayAnimation(EntityUid user) + { + var filter = Filter.Pvs(user, entityManager: EntityManager); + + if (TryComp(user, out var actor)) + filter.RemovePlayer(actor.PlayerSession); + + RaiseNetworkEvent(new FlipOnHitEvent(GetNetEntity(user)), filter); + } +} diff --git a/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs new file mode 100644 index 0000000000..84ef3f8ca6 --- /dev/null +++ b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs @@ -0,0 +1,258 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Popups; +using Content.Shared.Temperature; +using Content.Shared.Toggleable; +using Content.Shared.Wieldable; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; + +namespace Content.Shared.Item.ItemToggle; +/// +/// Handles generic item toggles, like a welder turning on and off, or an e-sword. +/// +/// +/// If you need extended functionality (e.g. requiring power) then add a new component and use events. +/// +public abstract class SharedItemToggleSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedPointLightSystem _light = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(TurnOffonUnwielded); + SubscribeLocalEvent(TurnOnonWielded); + SubscribeLocalEvent(OnUseInHand); + + SubscribeLocalEvent(OnIsHotEvent); + + SubscribeLocalEvent(UpdateActiveSound); + } + + private void OnStartup(Entity ent, ref ComponentStartup args) + { + UpdateVisuals(ent); + } + + private void OnUseInHand(EntityUid uid, ItemToggleComponent itemToggle, UseInHandEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + Toggle(uid, args.User, predicted: itemToggle.Predictable, itemToggle: itemToggle); + } + + /// + /// Used when an item is attempted to be toggled. + /// + public void Toggle(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return; + + if (itemToggle.Activated) + { + TryDeactivate(uid, user, itemToggle: itemToggle, predicted: predicted); + } + else + { + TryActivate(uid, user, itemToggle: itemToggle, predicted: predicted); + } + } + + /// + /// Used when an item is attempting to be activated. It returns false if the attempt fails any reason, interrupting the activation. + /// + public bool TryActivate(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return false; + + if (itemToggle.Activated) + return true; + + if (!itemToggle.Predictable && _netManager.IsClient) + return true; + + var attempt = new ItemToggleActivateAttemptEvent(user); + RaiseLocalEvent(uid, ref attempt); + + if (attempt.Cancelled) + { + if (predicted) + _audio.PlayPredicted(itemToggle.SoundFailToActivate, uid, user); + else + _audio.PlayPvs(itemToggle.SoundFailToActivate, uid); + + if (attempt.Popup != null && user != null) + { + if (predicted) + _popup.PopupClient(attempt.Popup, uid, user.Value); + else + _popup.PopupEntity(attempt.Popup, uid, user.Value); + } + + return false; + } + + Activate(uid, itemToggle, predicted, user); + + return true; + } + + /// + /// Used when an item is attempting to be deactivated. It returns false if the attempt fails any reason, interrupting the deactivation. + /// + public bool TryDeactivate(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return false; + + if (!itemToggle.Predictable && _netManager.IsClient) + return true; + + if (!itemToggle.Activated) + return true; + + var attempt = new ItemToggleDeactivateAttemptEvent(user); + RaiseLocalEvent(uid, ref attempt); + + if (attempt.Cancelled) + { + return false; + } + + Deactivate(uid, itemToggle, predicted, user); + return true; + } + + private void Activate(EntityUid uid, ItemToggleComponent itemToggle, bool predicted, EntityUid? user = null) + { + // TODO: Fix this hardcoding + TryComp(uid, out AppearanceComponent? appearance); + _appearance.SetData(uid, ToggleableLightVisuals.Enabled, true, appearance); + _appearance.SetData(uid, ToggleVisuals.Toggled, true, appearance); + + if (_light.TryGetLight(uid, out var light)) + { + _light.SetEnabled(uid, true, light); + } + + var soundToPlay = itemToggle.SoundActivate; + if (predicted) + _audio.PlayPredicted(soundToPlay, uid, user); + else + _audio.PlayPvs(soundToPlay, uid); + + // END FIX HARDCODING + + var toggleUsed = new ItemToggledEvent(predicted, Activated: true, user); + RaiseLocalEvent(uid, ref toggleUsed); + + itemToggle.Activated = true; + UpdateVisuals((uid, itemToggle)); + Dirty(uid, itemToggle); + } + + /// + /// Used to make the actual changes to the item's components on deactivation. + /// + private void Deactivate(EntityUid uid, ItemToggleComponent itemToggle, bool predicted, EntityUid? user = null) + { + if (_netManager.IsClient) // WD EDIT + return; + + var soundToPlay = itemToggle.SoundDeactivate; + _audio.PlayPvs(soundToPlay, uid); + // END FIX HARDCODING + + var toggleUsed = new ItemToggledEvent(predicted, Activated: false, user); + RaiseLocalEvent(uid, ref toggleUsed); + + itemToggle.Activated = false; + UpdateVisuals((uid, itemToggle)); + Dirty(uid, itemToggle); + } + + private void UpdateVisuals(Entity ent) + { + if (TryComp(ent, out AppearanceComponent? appearance)) + { + _appearance.SetData(ent, ToggleVisuals.Toggled, ent.Comp.Activated, appearance); + + if (ent.Comp.ToggleLight) + _appearance.SetData(ent, ToggleableLightVisuals.Enabled, ent.Comp.Activated, appearance); + } + + if (!ent.Comp.ToggleLight) + return; + + if (_light.TryGetLight(ent, out var light)) + _light.SetEnabled(ent, ent.Comp.Activated, light); + } + + /// + /// Used for items that require to be wielded in both hands to activate. For instance the dual energy sword will turn off if not wielded. + /// + private void TurnOffonUnwielded(EntityUid uid, ItemToggleComponent itemToggle, ItemUnwieldedEvent args) + { + if (itemToggle.Activated) + TryDeactivate(uid, args.User, itemToggle: itemToggle); + } + + /// + /// Wieldable items will automatically turn on when wielded. + /// + private void TurnOnonWielded(EntityUid uid, ItemToggleComponent itemToggle, ref ItemWieldedEvent args) + { + if (!itemToggle.Activated) + TryActivate(uid, itemToggle: itemToggle); + } + + public bool IsActivated(EntityUid uid, ItemToggleComponent? comp = null) + { + if (!Resolve(uid, ref comp, false)) + return true; // assume always activated if no component + + return comp.Activated; + } + + /// + /// Used to make the item hot when activated. + /// + private void OnIsHotEvent(EntityUid uid, ItemToggleHotComponent itemToggleHot, IsHotEvent args) + { + args.IsHot |= IsActivated(uid); + } + + /// + /// Used to update the looping active sound linked to the entity. + /// + private void UpdateActiveSound(EntityUid uid, ItemToggleActiveSoundComponent activeSound, ref ItemToggledEvent args) + { + if (_netManager.IsClient) // WD EDIT + return; + + if (args.Activated) + { + if (activeSound.ActiveSound != null && activeSound.PlayingStream == null) + { + activeSound.PlayingStream = _audio.PlayPvs(activeSound.ActiveSound, uid, AudioParams.Default.WithLoop(true)).Value.Entity; + } + } + else + { + activeSound.PlayingStream = _audio.Stop(activeSound.PlayingStream); + } + } +} diff --git a/Content.Shared/_White/Animations/FlipOnHitComponent.cs b/Content.Shared/_White/Animations/FlipOnHitComponent.cs new file mode 100644 index 0000000000..b997a8e393 --- /dev/null +++ b/Content.Shared/_White/Animations/FlipOnHitComponent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._White.Animations; + +[RegisterComponent, NetworkedComponent] +public sealed partial class FlipOnHitComponent : Component; diff --git a/Content.Shared/_White/Animations/SharedFlipOnHitSystem.cs b/Content.Shared/_White/Animations/SharedFlipOnHitSystem.cs new file mode 100644 index 0000000000..e461e88877 --- /dev/null +++ b/Content.Shared/_White/Animations/SharedFlipOnHitSystem.cs @@ -0,0 +1,45 @@ +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Standing; +using Content.Shared.Weapons.Melee.Events; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; + +namespace Content.Shared._White.Animations; + +public abstract class SharedFlipOnHitSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly StandingStateSystem _standingState = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHit); + } + + private void OnHit(Entity ent, ref MeleeHitEvent args) + { + if (!_timing.IsFirstTimePredicted) + return; + + if (args.HitEntities.Count == 0) + return; + + if (TryComp(ent, out ItemToggleComponent? itemToggle) && !itemToggle.Activated) + return; + + if (_standingState.IsDown(args.User)) + return; + + PlayAnimation(args.User); + } + + protected abstract void PlayAnimation(EntityUid user); +} + +[Serializable, NetSerializable] +public sealed class FlipOnHitEvent(NetEntity user) : EntityEventArgs +{ + public NetEntity User = user; +} diff --git a/Content.Shared/_White/Wield/ToggleableWieldedComponent.cs b/Content.Shared/_White/Wield/ToggleableWieldedComponent.cs new file mode 100644 index 0000000000..2d4e80241b --- /dev/null +++ b/Content.Shared/_White/Wield/ToggleableWieldedComponent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared._White.Wield; + +[RegisterComponent] +public sealed partial class ToggleableWieldedComponent : Component; diff --git a/Content.Shared/_White/Wield/ToggleableWieldedSystem.cs b/Content.Shared/_White/Wield/ToggleableWieldedSystem.cs new file mode 100644 index 0000000000..bf25f2a7e4 --- /dev/null +++ b/Content.Shared/_White/Wield/ToggleableWieldedSystem.cs @@ -0,0 +1,20 @@ +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Wieldable.Components; + +namespace Content.Shared._White.Wield; + +public sealed class ToggleableWieldedSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(AttemptActivate); + } + + private void AttemptActivate(Entity ent, ref ItemToggleActivateAttemptEvent args) + { + if (TryComp(ent, out WieldableComponent? wieldable) && !wieldable.Wielded) + args.Cancelled = true; + } +} diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 0b0719e77f..723d950835 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -1,6 +1,8 @@ - type: entity - id: BaseMeleeWeaponEnergy # more generic naming in case someone makes like, idk, an energy axe + name: energy sword parent: BaseItem + id: EnergySwordBase + description: A very loud & dangerous sword with a beam made of pure, concentrated plasma. Cuts through unarmored targets like butter. abstract: true components: - type: EnergySword @@ -12,17 +14,12 @@ - type: ItemToggleActiveSound activeSound: path: /Audio/Weapons/ebladehum.ogg - - type: ComponentToggler - components: - - type: Sharp - - type: DisarmMalus - malus: 0.6 - - type: Execution - doAfterDuration: 4.0 + - type: ItemToggleSharp - type: ItemToggleHot + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 - type: ItemToggleSize activatedSize: Huge - - type: ItemTogglePointLight - type: ItemToggleMeleeWeapon activatedSoundOnHit: path: /Audio/Weapons/eblade1.ogg @@ -38,18 +35,16 @@ params: variation: 0.125 activatedDamage: - types: - Slash: 15 - Heat: 15 - Structural: 20 + types: + Slash: 15 + Heat: 15 + Structural: 20 - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1 damage: types: Blunt: 4.5 - - type: Item - size: Small - type: UseDelay delay: 1.0 - type: PointLight @@ -68,68 +63,19 @@ right: - state: inhand-right-blade shader: unshaded - - type: Reflect + - type: DisarmMalus + malus: 0 - type: IgnitionSource temperature: 700 - type: entity name: energy sword - parent: [BaseMeleeWeaponEnergy, BaseSyndicateContraband] + parent: EnergySwordBase id: EnergySword description: A very loud & dangerous sword with a beam made of pure, concentrated plasma. Cuts through unarmored targets like butter. components: - type: Sprite sprite: Objects/Weapons/Melee/e_sword.rsi - layers: - - state: e_sword - - state: e_sword_blade - color: "#FFFFFF" - visible: false - shader: unshaded - map: [ "blade" ] - - type: Item - sprite: Objects/Weapons/Melee/e_sword-inhands.rsi - -- type: entity - name: energy dagger - parent: [BaseMeleeWeaponEnergy, BaseSyndicateContraband] - id: EnergyDaggerLoud - description: A not as loud and dangerous dagger with a beam made of pure, concentrated plasma. This one is completely undisguised. - components: - - type: ItemToggle - soundActivate: - path: /Audio/Weapons/ebladeon.ogg - params: - volume: -3 - soundDeactivate: - path: /Audio/Weapons/ebladeoff.ogg - params: - volume: -3 - - type: ItemToggleMeleeWeapon - activatedSoundOnSwing: - path: /Audio/Weapons/eblademiss.ogg - params: - volume: -3 - variation: 0.250 - activatedDamage: - types: - Slash: 10 - Heat: 10 - deactivatedSecret: true - - type: ItemToggleActiveSound - activeSound: - path: /Audio/Weapons/ebladehum.ogg - params: - volume: -3 - - type: ComponentToggler - components: - - type: Sharp - - type: DisarmMalus - malus: 0.4 - - type: Execution - doAfterDuration: 4.0 - - type: Sprite - sprite: Objects/Weapons/Melee/e_dagger_loud.rsi layers: - state: e_sword - state: e_sword_blade @@ -137,30 +83,41 @@ visible: false shader: unshaded map: [ "blade" ] - - type: MeleeWeapon - wideAnimationRotation: 145 - attackRate: 1 - hidden: true - damage: - types: - Blunt: 1 - type: Item - size: Tiny - sprite: Objects/Weapons/Melee/e_dagger_loud.rsi - - type: PointLight - enabled: false - radius: 1.5 - energy: 1.5 - color: white - netsync: false + size: Small + sprite: DeltaV/Objects/Weapons/Melee/e_sword.rsi # Delta-V + - type: Reflect # WD EDIT + reflectProb: .5 + spread: 75 + reflects: + - Energy #DeltaV: + - type: Construction # WD EDIT + deconstructionTarget: null + graph: EnergyDoubleSwordGraph + node: esword + - type: Tag # WD EDIT + tags: + - EnergySword - type: entity name: pen - parent: BaseMeleeWeaponEnergy + parent: EnergySwordBase id: EnergyDagger suffix: E-Dagger description: 'A dark ink pen.' components: + - type: Sprite + sprite: Objects/Weapons/Melee/e_dagger.rsi + layers: + - state: e_sword + - state: e_sword_blade + color: "#FFFFFF" + visible: false + shader: unshaded + map: [ "blade" ] + - type: Item + size: Tiny + sprite: Objects/Weapons/Melee/e_dagger.rsi - type: ItemToggle soundActivate: path: /Audio/Weapons/ebladeon.ogg @@ -170,72 +127,59 @@ path: /Audio/Weapons/ebladeoff.ogg params: volume: -6 - - type: ItemToggleActiveSound - activeSound: - path: /Audio/Weapons/ebladehum.ogg - params: - volume: -6 - type: ItemToggleMeleeWeapon activatedSoundOnSwing: path: /Audio/Weapons/eblademiss.ogg params: - volume: -3 + volume: -6 variation: 0.250 activatedDamage: + types: + Slash: 4 + Heat: 8 + deactivatedSecret: true + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + params: + volume: -6 + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.4 + - type: MeleeWeapon + wideAnimationRotation: -135 + attackRate: 1 + hidden: true + damage: types: - Slash: 10 - Heat: 10 - - type: ComponentToggler - components: - - type: Sharp - - type: DisarmMalus - malus: 0.4 - - type: Execution - doAfterDuration: 4.0 - - type: Contraband - severity: Syndicate - allowedDepartments: null - - type: Sprite - sprite: Objects/Weapons/Melee/e_dagger.rsi - layers: - - state: e_sword - - state: e_sword_blade - color: "#FFFFFF" - visible: false - shader: unshaded - map: [ "blade" ] - - type: Item - size: Tiny - sprite: Objects/Weapons/Melee/e_dagger.rsi + Blunt: 1 + - type: Reflect # WD EDIT + reflectProb: .25 + spread: 75 + reflects: + - Energy - type: PointLight enabled: false radius: 1.5 energy: 1.5 color: white netsync: false - - type: MeleeWeapon - wideAnimationRotation: 145 - attackRate: 1 - hidden: true - damage: - types: - Blunt: 1 + - type: Appearance - type: Tag tags: - Write - type: entity - parent: [BaseItem, BaseSyndicateContraband] + parent: BaseItem id: EnergyDaggerBox name: e-dagger box suffix: E-Dagger description: A small box containing an e-dagger. Packaging disintegrates when opened, leaving no evidence behind. components: - - type: Item - size: Tiny - type: Sprite sprite: Objects/Storage/penbox.rsi state: e_dagger + - type: Item + size: Tiny - type: SpawnItemsOnUse items: - id: EnergyDagger @@ -244,18 +188,12 @@ - type: entity name: energy cutlass - parent: [BaseMeleeWeaponEnergy, BaseMajorContraband] + parent: EnergySwordBase id: EnergyCutlass - description: An exotic energy weapon. + description: An exotic energy weapon, brutal blade crackling with crudely harnessed plasma. #DeltaV - nicer description. components: - - type: ItemToggleMeleeWeapon - activatedDamage: - types: - Slash: 10 - Heat: 12 - deactivatedSecret: true - type: Sprite - sprite: Objects/Weapons/Melee/e_cutlass.rsi + sprite: DeltaV/Objects/Weapons/Melee/e_cutlass.rsi # DeltaV layers: - state: e_cutlass - state: e_cutlass_blade @@ -264,56 +202,28 @@ shader: unshaded map: [ "blade" ] - type: Item - sprite: Objects/Weapons/Melee/e_cutlass.rsi - -- type: entity - name: double-bladed energy sword - parent: [BaseMeleeWeaponEnergy, BaseSyndicateContraband] - id: EnergySwordDouble - description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets. - components: - - type: ItemToggle - onUse: false # wielding events control it instead - soundActivate: - path: /Audio/Weapons/ebladeon.ogg - params: - volume: 3 - soundDeactivate: - path: /Audio/Weapons/ebladeoff.ogg - params: - volume: 3 + size: Small + sprite: DeltaV/Objects/Weapons/Melee/e_cutlass.rsi #DeltaV - type: ItemToggleMeleeWeapon - activatedSoundOnSwing: - path: /Audio/Weapons/eblademiss.ogg - params: - volume: 3 - variation: 0.250 activatedDamage: types: - Slash: 12 + Slash: 10 Heat: 12 - Structural: 15 - - type: ItemToggleActiveSound - activeSound: - path: /Audio/Weapons/ebladehum.ogg - params: - volume: 3 - - type: ComponentToggler - components: - - type: Sharp - - type: DisarmMalus - malus: 0.7 - - type: Execution - doAfterDuration: 4.0 - - type: Wieldable - wieldSound: null # esword light sound instead - - type: MeleeWeapon - wideAnimationRotation: -135 - attackRate: 1.5 - angle: 100 + deactivatedSecret: true + - type: MeleeWeapon # DeltaV - reduced attack rate of e-cutlass; slower, more brutal swings + attackRate: 0.75 + soundHit: + path: /Audio/Weapons/eblade1.ogg damage: types: - Blunt: 4.5 + Blunt: 6 + +- type: entity + name: double-bladed energy sword + parent: EnergySwordBase + id: EnergySwordDouble + description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets. + components: - type: Sprite sprite: Objects/Weapons/Melee/e_sword_double.rsi layers: @@ -326,15 +236,20 @@ - type: Item size: Small sprite: Objects/Weapons/Melee/e_sword_double-inhands.rsi - - type: Reflect - reflectProb: .75 - spread: 75 - -- type: entity - suffix: One-Handed, For Borgs - parent: EnergySwordDouble - id: CyborgEnergySwordDouble # why is this invalid if ID is BorgEnergySwordDouble - description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. Specially designed for syndicate cyborgs. - components: # could add energy-draining like the L6C - type: Wieldable - freeHandsRequired: 0 # because borg has no off-hand to wield with. Without this, it will be unable to activate the esword + - type: IncreaseDamageOnWield + damage: + types: + Slash: 15 + Heat: 15 + - type: Reflect # WD EDIT + reflectProb: 1 + spread: 75 + reflects: + - Energy + - type: ToggleableWielded # WD EDIT + - type: FlipOnHit # WD EDIT + - type: Construction # WD EDIT + deconstructionTarget: null + graph: EnergyDoubleSwordGraph + node: desword diff --git a/Resources/Prototypes/_White/Recipes/hidden_crafts.yml b/Resources/Prototypes/_White/Recipes/hidden_crafts.yml new file mode 100644 index 0000000000..c55b8e544d --- /dev/null +++ b/Resources/Prototypes/_White/Recipes/hidden_crafts.yml @@ -0,0 +1,11 @@ +- type: constructionGraph + id: EnergyDoubleSwordGraph + start: esword + graph: + - node: esword + edges: + - to: desword + steps: + - tag: EnergySword + - node: desword + entity: EnergySwordDouble \ No newline at end of file diff --git a/Resources/Prototypes/_White/tags.yml b/Resources/Prototypes/_White/tags.yml new file mode 100644 index 0000000000..62e70f42a9 --- /dev/null +++ b/Resources/Prototypes/_White/tags.yml @@ -0,0 +1,2 @@ +- type: Tag + id: EnergySword \ No newline at end of file