diff --git a/Content.Client/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs b/Content.Client/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs new file mode 100644 index 00000000000..ff7487df76f --- /dev/null +++ b/Content.Client/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs @@ -0,0 +1,124 @@ +using Robust.Client.Animations; +using Robust.Shared.Animations; +using Robust.Shared.GameStates; +using Robust.Client.GameObjects; +using Content.Shared.Emoting; +using Content.Shared._CorvaxNext.Emoting; +using System.Numerics; +using Robust.Shared.Prototypes; +using Content.Shared.Chat.Prototypes; + +namespace Content.Client._CorvaxNext.Emoting; + +public sealed partial class AnimatedEmotesSystem : SharedAnimatedEmotesSystem +{ + [Dependency] private readonly AnimationPlayerSystem _anim = default!; + [Dependency] private readonly IPrototypeManager _prot = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHandleState); + + SubscribeLocalEvent(OnFlip); + SubscribeLocalEvent(OnSpin); + SubscribeLocalEvent(OnJump); + } + + public void PlayEmote(EntityUid uid, Animation anim, string animationKey = "emoteAnimKeyId") + { + if (_anim.HasRunningAnimation(uid, animationKey)) + return; + + _anim.Play(uid, anim, animationKey); + } + + private void OnHandleState(EntityUid uid, AnimatedEmotesComponent component, ref ComponentHandleState args) + { + if (args.Current is not AnimatedEmotesComponentState state + || !_prot.TryIndex(state.Emote, out var emote)) + return; + + if (emote.Event != null) + RaiseLocalEvent(uid, emote.Event); + } + + private void OnFlip(Entity ent, ref AnimationFlipEmoteEvent args) + { + var a = new Animation + { + Length = TimeSpan.FromMilliseconds(500), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Rotation), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Angle.Zero, 0f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(180), 0.25f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(360), 0.25f), + } + } + } + }; + PlayEmote(ent, a); + } + + private void OnSpin(Entity ent, ref AnimationSpinEmoteEvent args) + { + var a = new Animation + { + Length = TimeSpan.FromMilliseconds(600), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(TransformComponent), + Property = nameof(TransformComponent.LocalRotation), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(90), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(180), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(270), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.Zero, 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(90), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(180), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(270), 0.075f), + new AnimationTrackProperty.KeyFrame(Angle.Zero, 0.075f), + } + } + } + }; + PlayEmote(ent, a, "emoteAnimSpin"); + } + + private void OnJump(Entity ent, ref AnimationJumpEmoteEvent args) + { + var a = new Animation + { + Length = TimeSpan.FromMilliseconds(250), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Offset), + InterpolationMode = AnimationInterpolationMode.Cubic, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), + new AnimationTrackProperty.KeyFrame(new Vector2(0, .35f), 0.125f), + new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0.125f), + } + } + } + }; + PlayEmote(ent, a); + } +} diff --git a/Content.Server/Chat/Systems/ChatSystem.Emote.cs b/Content.Server/Chat/Systems/ChatSystem.Emote.cs index fddf453ff06..c100e5ea630 100644 --- a/Content.Server/Chat/Systems/ChatSystem.Emote.cs +++ b/Content.Server/Chat/Systems/ChatSystem.Emote.cs @@ -210,7 +210,7 @@ private bool AllowedToUseEmote(EntityUid source, EmotePrototype emote) private void InvokeEmoteEvent(EntityUid uid, EmotePrototype proto) { var ev = new EmoteEvent(proto); - RaiseLocalEvent(uid, ref ev); + RaiseLocalEvent(uid, ref ev, true); // Corvax-Next-AnimateEmote } } diff --git a/Content.Server/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs b/Content.Server/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs new file mode 100644 index 00000000000..a16a5e6e413 --- /dev/null +++ b/Content.Server/_CorvaxNext/Emoting/AnimatedEmotesSystem.cs @@ -0,0 +1,29 @@ +using Robust.Shared.GameStates; +using Content.Server.Chat.Systems; +using Content.Shared.Chat.Prototypes; +using Content.Shared.Emoting; +using Content.Shared._CorvaxNext.Emoting; +using Robust.Shared.Prototypes; + +namespace Content.Server._CorvaxNext.Emoting; + +public sealed partial class AnimatedEmotesSystem : SharedAnimatedEmotesSystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEmote); + } + + private void OnEmote(EntityUid uid, AnimatedEmotesComponent component, ref EmoteEvent args) + { + PlayEmoteAnimation(uid, component, args.Emote.ID); + } + + public void PlayEmoteAnimation(EntityUid uid, AnimatedEmotesComponent component, ProtoId prot) + { + component.Emote = prot; + Dirty(uid, component); + } +} diff --git a/Content.Shared/Chat/Prototypes/EmotePrototype.cs b/Content.Shared/Chat/Prototypes/EmotePrototype.cs index 7ee958ee6a7..114e6afe75d 100644 --- a/Content.Shared/Chat/Prototypes/EmotePrototype.cs +++ b/Content.Shared/Chat/Prototypes/EmotePrototype.cs @@ -68,6 +68,11 @@ public sealed partial class EmotePrototype : IPrototype /// [DataField] public HashSet ChatTriggers = new(); + + // Corvax-Next-AnimateEmote-Start + [DataField] + public object? Event = null; + // Corvax-Next-AnimateEmote-End } /// diff --git a/Content.Shared/_CorvaxNext/Emoting/AnimatedEmotesComponent.cs b/Content.Shared/_CorvaxNext/Emoting/AnimatedEmotesComponent.cs new file mode 100644 index 00000000000..753cee31fea --- /dev/null +++ b/Content.Shared/_CorvaxNext/Emoting/AnimatedEmotesComponent.cs @@ -0,0 +1,28 @@ +using Content.Shared.Chat.Prototypes; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._CorvaxNext.Emoting; + +// use as a template +//[Serializable, NetSerializable, DataDefinition] public sealed partial class AnimationNameEmoteEvent : EntityEventArgs { } + +[Serializable, NetSerializable, DataDefinition] public sealed partial class AnimationFlipEmoteEvent : EntityEventArgs { } +[Serializable, NetSerializable, DataDefinition] public sealed partial class AnimationSpinEmoteEvent : EntityEventArgs { } +[Serializable, NetSerializable, DataDefinition] public sealed partial class AnimationJumpEmoteEvent : EntityEventArgs { } + +[RegisterComponent, NetworkedComponent] public sealed partial class AnimatedEmotesComponent : Component +{ + [DataField] public ProtoId? Emote; +} + +[Serializable, NetSerializable] public sealed partial class AnimatedEmotesComponentState : ComponentState +{ + public ProtoId? Emote; + + public AnimatedEmotesComponentState(ProtoId? emote) + { + Emote = emote; + } +} diff --git a/Content.Shared/_CorvaxNext/Emoting/SharedAnimatedEmotesSystem.cs b/Content.Shared/_CorvaxNext/Emoting/SharedAnimatedEmotesSystem.cs new file mode 100644 index 00000000000..f83892ed3fe --- /dev/null +++ b/Content.Shared/_CorvaxNext/Emoting/SharedAnimatedEmotesSystem.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._CorvaxNext.Emoting; + +public abstract class SharedAnimatedEmotesSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetState); + } + + private void OnGetState(Entity ent, ref ComponentGetState args) + { + args.State = new AnimatedEmotesComponentState(ent.Comp.Emote); + } +} diff --git a/Resources/Locale/ru-RU/_corvaxnext/emotes.ftl b/Resources/Locale/ru-RU/_corvaxnext/emotes.ftl new file mode 100644 index 00000000000..4494c552c2b --- /dev/null +++ b/Resources/Locale/ru-RU/_corvaxnext/emotes.ftl @@ -0,0 +1,7 @@ +chat-emote-name-flip = Сделать сальто +chat-emote-name-spin = Покрутиться +chat-emote-name-jump = Прыгнуть + +chat-emote-msg-flip = делает сальто! +chat-emote-msg-spin = вращается! +chat-emote-msg-jump = прыгает! diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index d1c6f878bdc..48c54318ac6 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -44,6 +44,7 @@ - type: TTS # Corvax-TTS - type: RequireProjectileTarget active: False + - type: AnimatedEmotes # Corvax-Next-AutoAnimate - type: entity save: false diff --git a/Resources/Prototypes/_CorvaxNext/Actions/emotes.yml b/Resources/Prototypes/_CorvaxNext/Actions/emotes.yml new file mode 100644 index 00000000000..5f69c48e7bc --- /dev/null +++ b/Resources/Prototypes/_CorvaxNext/Actions/emotes.yml @@ -0,0 +1,68 @@ +- type: emote + id: Flip + name: chat-emote-name-flip + chatMessages: ["chat-emote-msg-flip"] + chatTriggers: + - flip + - flips + - flipping + - does a flip + - do a flip + - backflip + - frontflip + - somersault + - cartwheel + - прыжок с переворотом + - кувырок + - сальто + - делает сальто + - сделал сальто + - делает сальтуху + - прыгает с переворотом + event: !type:AnimationFlipEmoteEvent + +- type: emote + id: Spin + name: chat-emote-name-spin + chatMessages: ["chat-emote-msg-spin"] + chatTriggers: + - spin + - spins + - spinning + - twirl + - twirls + - twirling + - rotates + - rotating + - вращается + - вращается на месте + - кружится + - кружится на месте + - вертится + - закручивается + - разворот + event: !type:AnimationSpinEmoteEvent + +- type: emote + id: Jump + name: chat-emote-name-jump + chatMessages: ["chat-emote-msg-jump"] + chatTriggers: + - jump + - jumps + - jumping + - hops + - hopping + - leaps + - leaping + - bounce + - bounces + - bouncing + - прыгает + - прыгнул + - подпрыгнул + - прыгает вверх + - подскакивает + - скачет + - прыжок + event: !type:AnimationJumpEmoteEvent