Files
ss14-wl/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
LEVELcat 1d4ba544cc Merge branch 'fixUPWL3' of https://github.com/Litogin/Ho
# Resolved Conflicts:
#	Content.Client/Sprite/ContentSpriteSystem.cs
#	Content.Server/Corvax/StationGoal/StationGoalCommand.cs
#	Content.Server/Corvax/StationGoal/StationGoalPaperSystem.cs
#	Content.Server/GameTicking/GameTicker.Spawning.cs
#	Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs
#	Content.Server/Silicons/Borgs/BorgSystem.cs
#	Content.Shared.Database/LogType.cs
#	Content.Shared/Preferences/HumanoidCharacterProfile.cs
#	Resources/Audio/Magic/attributions.yml
#	Resources/Changelog/ChangelogSyndie.yml
#	Resources/Credits/GitHub.txt
#	Resources/Locale/ru-RU/guidebook/guides.ftl
#	Resources/Prototypes/Actions/types.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/games.yml
#	Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml
#	Resources/Prototypes/Entities/Structures/Machines/lathe.yml
#	Resources/Prototypes/Entities/Structures/Power/apc.yml
#	Resources/Prototypes/Entities/Structures/Power/substation.yml
#	Resources/Prototypes/Research/experimental.yml
#	Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodbartender.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodbartender.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodbartender.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcaptain.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcaptain.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcaptain.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcargo.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcargo.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcargo.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodce.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodce.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodce.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcentcom.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcentcom.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcentcom.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodchemist.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodchemist.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodchemist.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcmo.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcmo.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodcmo.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hooddefault.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hooddefault.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hooddefault.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodengi.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodengi.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodengi.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhop.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhop.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhop.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhos.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhos.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhos.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhydro.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhydro.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodhydro.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodjani.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodjani.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodjani.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodmed.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodmed.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodmed.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodminer.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodminer.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodminer.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodpara.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodpara.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodpara.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodqm.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodqm.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodqm.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrd.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrd.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrd.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrobo.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrobo.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodrobo.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsci.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsci.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsci.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsec.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsec.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsec.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsyndicate.rsi/equipped-HELMET.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsyndicate.rsi/icon.png
#	Resources/Textures/Clothing/Head/Hoods/Coat/hoodsyndicate.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/ATMOS-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/BAR-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/BAR-icon.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CAP-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CARGO-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CE-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CENTCOM-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CHEM-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/CMO-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/ENGI-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/GENE-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/HOP-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/HYDRO-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/JANI-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/MED-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/MINER-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/PARA-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/QM-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/RD-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/ROBO-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/SCI-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/SYNDIE-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/VIRO-equipped-OUTERCLOTHING.png
#	Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/equipped-OUTERCLOTHING.png
2025-04-05 16:17:55 +03:00

234 lines
9.0 KiB
C#

using System.Numerics;
using Content.Client.Animations;
using Content.Client.Weapons.Melee.Components;
using Content.Shared.Weapons.Melee;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.Map;
namespace Content.Client.Weapons.Melee;
public sealed partial class MeleeWeaponSystem
{
private const string FadeAnimationKey = "melee-fade";
private const string SlashAnimationKey = "melee-slash";
private const string ThrustAnimationKey = "melee-thrust";
/// <summary>
/// Does all of the melee effects for a player that are predicted, i.e. character lunge and weapon animation.
/// </summary>
public override void DoLunge(EntityUid user, EntityUid weapon, Angle angle, Vector2 localPos, string? animation, bool predicted = true)
{
if (!Timing.IsFirstTimePredicted)
return;
var lunge = GetLungeAnimation(localPos);
// Stop any existing lunges on the user.
_animation.Stop(user, MeleeLungeKey);
_animation.Play(user, lunge, MeleeLungeKey);
if (localPos == Vector2.Zero || animation == null)
return;
if (!_xformQuery.TryGetComponent(user, out var userXform) || userXform.MapID == MapId.Nullspace)
return;
var animationUid = Spawn(animation, userXform.Coordinates);
if (!TryComp<SpriteComponent>(animationUid, out var sprite)
|| !TryComp<WeaponArcVisualsComponent>(animationUid, out var arcComponent))
{
return;
}
var spriteRotation = Angle.Zero;
if (arcComponent.Animation != WeaponArcAnimation.None
&& TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent))
{
if (user != weapon
&& TryComp(weapon, out SpriteComponent? weaponSpriteComponent))
sprite.CopyFrom(weaponSpriteComponent);
spriteRotation = meleeWeaponComponent.WideAnimationRotation;
if (meleeWeaponComponent.SwingLeft)
angle *= -1;
}
sprite.Rotation = localPos.ToWorldAngle();
var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
var xform = _xformQuery.GetComponent(animationUid);
TrackUserComponent track;
switch (arcComponent.Animation)
{
case WeaponArcAnimation.Slash:
track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user;
_animation.Play(animationUid, GetSlashAnimation(sprite, angle, spriteRotation), SlashAnimationKey);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey);
break;
case WeaponArcAnimation.Thrust:
track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user;
_animation.Play(animationUid, GetThrustAnimation(sprite, distance, spriteRotation), ThrustAnimationKey);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
break;
case WeaponArcAnimation.None:
var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform);
var worldPos = mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos);
var newLocalPos = Vector2.Transform(worldPos, TransformSystem.GetInvWorldMatrix(xform.ParentUid));
TransformSystem.SetLocalPositionNoLerp(animationUid, newLocalPos, xform);
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;
}
}
private Animation GetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation)
{
const float slashStart = 0.03f;
const float slashEnd = 0.065f;
const float length = slashEnd + 0.05f;
var startRotation = sprite.Rotation + arc / 2;
var endRotation = sprite.Rotation - arc / 2;
var startRotationOffset = startRotation.RotateVec(new Vector2(0f, -1f));
var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -1f));
startRotation += spriteRotation;
endRotation += spriteRotation;
return new Animation()
{
Length = TimeSpan.FromSeconds(length),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Rotation),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(startRotation, 0f),
new AnimationTrackProperty.KeyFrame(startRotation, slashStart),
new AnimationTrackProperty.KeyFrame(endRotation, slashEnd)
}
},
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(startRotationOffset, 0f),
new AnimationTrackProperty.KeyFrame(startRotationOffset, slashStart),
new AnimationTrackProperty.KeyFrame(endRotationOffset, slashEnd)
}
},
}
};
}
private Animation GetThrustAnimation(SpriteComponent sprite, float distance, Angle spriteRotation)
{
const float thrustEnd = 0.05f;
const float length = 0.15f;
var startOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance / 5f));
var endOffset = sprite.Rotation.RotateVec(new Vector2(0f, -distance));
sprite.Rotation += spriteRotation;
return new Animation()
{
Length = TimeSpan.FromSeconds(length),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(startOffset, 0f),
new AnimationTrackProperty.KeyFrame(endOffset, thrustEnd),
new AnimationTrackProperty.KeyFrame(endOffset, length),
}
},
}
};
}
private Animation GetFadeAnimation(SpriteComponent sprite, float start, float end)
{
return new Animation
{
Length = TimeSpan.FromSeconds(end),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Color),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(sprite.Color, start),
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), end)
}
}
}
};
}
/// <summary>
/// Get the sprite offset animation to use for mob lunges.
/// </summary>
private Animation GetLungeAnimation(Vector2 direction)
{
const float length = 0.1f;
return new Animation
{
Length = TimeSpan.FromSeconds(length),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, 0f),
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length)
}
}
}
};
}
/// <summary>
/// Updates the effect positions to follow the user
/// </summary>
private void UpdateEffects()
{
var query = EntityQueryEnumerator<TrackUserComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var arcComponent, out var xform))
{
if (arcComponent.User == null)
continue;
Vector2 targetPos = TransformSystem.GetWorldPosition(/*WL-Changes-start*/arcComponent.User.Value/*WL-Changes-end*/);
if (arcComponent.Offset != Vector2.Zero)
{
var entRotation = TransformSystem.GetWorldRotation(xform);
targetPos += entRotation.RotateVec(arcComponent.Offset);
}
TransformSystem.SetWorldPosition(uid, targetPos);
}
}
}