Polish melee effects (#11653)
* Polish melee effects * adjustments * Animation changes * Fix fist
This commit is contained in:
@@ -8,6 +8,9 @@ public sealed class WeaponArcVisualsComponent : Component
|
|||||||
{
|
{
|
||||||
[ViewVariables, DataField("animation")]
|
[ViewVariables, DataField("animation")]
|
||||||
public WeaponArcAnimation Animation = WeaponArcAnimation.None;
|
public WeaponArcAnimation Animation = WeaponArcAnimation.None;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("fadeOut")]
|
||||||
|
public bool Fadeout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WeaponArcAnimation : byte
|
public enum WeaponArcAnimation : byte
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
using Content.Client.Weapons.Melee.Components;
|
||||||
using Content.Shared.Weapons;
|
using Content.Shared.Weapons;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Animations;
|
using Robust.Shared.Animations;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Client.Weapons.Melee;
|
namespace Content.Client.Weapons.Melee;
|
||||||
|
|
||||||
@@ -13,7 +14,12 @@ public sealed partial class MeleeWeaponSystem
|
|||||||
/// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register.
|
/// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const float DamageAnimationLength = 0.30f;
|
private const float DamageAnimationLength = 0.30f;
|
||||||
|
|
||||||
|
private const string AnimationKey = "melee-animation";
|
||||||
private const string DamageAnimationKey = "damage-effect";
|
private const string DamageAnimationKey = "damage-effect";
|
||||||
|
private const string FadeAnimationKey = "melee-fade";
|
||||||
|
private const string SlashAnimationKey = "melee-slash";
|
||||||
|
private const string ThrustAnimationKey = "melee-thrust";
|
||||||
|
|
||||||
private void InitializeEffect()
|
private void InitializeEffect()
|
||||||
{
|
{
|
||||||
@@ -54,7 +60,7 @@ public sealed partial class MeleeWeaponSystem
|
|||||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||||
KeyFrames =
|
KeyFrames =
|
||||||
{
|
{
|
||||||
new AnimationTrackProperty.KeyFrame(color * sprite.Color, 0f),
|
new AnimationTrackProperty.KeyFrame(color, 0f),
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color, DamageAnimationLength)
|
new AnimationTrackProperty.KeyFrame(sprite.Color, DamageAnimationLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,4 +110,175 @@ public sealed partial class MeleeWeaponSystem
|
|||||||
_animation.Play(player, animation, DamageAnimationKey);
|
_animation.Play(player, animation, DamageAnimationKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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, Angle angle, Vector2 localPos, string? animation)
|
||||||
|
{
|
||||||
|
if (!Timing.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var lunge = GetLungeAnimation(localPos);
|
||||||
|
|
||||||
|
// Stop any existing lunges on the user.
|
||||||
|
_animation.Stop(user, MeleeLungeKey);
|
||||||
|
_animation.Play(user, lunge, MeleeLungeKey);
|
||||||
|
|
||||||
|
// Clientside entity to spawn
|
||||||
|
if (animation != null)
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(user, out var userXform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var coords = userXform.Coordinates;
|
||||||
|
var animationUid = Spawn(animation, coords);
|
||||||
|
|
||||||
|
if (localPos != Vector2.Zero && TryComp<SpriteComponent>(animationUid, out var sprite))
|
||||||
|
{
|
||||||
|
if (TryComp<WeaponArcVisualsComponent>(animationUid, out var arcComponent))
|
||||||
|
{
|
||||||
|
sprite.NoRotation = true;
|
||||||
|
sprite.Rotation = localPos.ToWorldAngle();
|
||||||
|
|
||||||
|
var distance = Math.Clamp(localPos.Length / 2f, 0.2f, 1f);
|
||||||
|
|
||||||
|
switch (arcComponent.Animation)
|
||||||
|
{
|
||||||
|
case WeaponArcAnimation.Slash:
|
||||||
|
_animation.Play(animationUid, GetSlashAnimation(sprite, angle), SlashAnimationKey);
|
||||||
|
if (arcComponent.Fadeout)
|
||||||
|
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey);
|
||||||
|
break;
|
||||||
|
case WeaponArcAnimation.Thrust:
|
||||||
|
_animation.Play(animationUid, GetThrustAnimation(sprite, distance), ThrustAnimationKey);
|
||||||
|
if (arcComponent.Fadeout)
|
||||||
|
_animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
|
||||||
|
break;
|
||||||
|
case WeaponArcAnimation.None:
|
||||||
|
var mapPos = userXform.WorldPosition;
|
||||||
|
var xform = Transform(animationUid);
|
||||||
|
xform.AttachToGridOrMap();
|
||||||
|
xform.WorldPosition = mapPos + (userXform.WorldRotation - userXform.LocalRotation).RotateVec(localPos);
|
||||||
|
if (arcComponent.Fadeout)
|
||||||
|
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Animation GetSlashAnimation(SpriteComponent sprite, Angle arc)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
sprite.NoRotation = true;
|
||||||
|
|
||||||
|
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(startRotation.RotateVec(new Vector2(0f, -1f)), 0f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(startRotation.RotateVec(new Vector2(0f, -1f)), slashStart),
|
||||||
|
new AnimationTrackProperty.KeyFrame(endRotation.RotateVec(new Vector2(0f, -1f)), slashEnd)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Animation GetThrustAnimation(SpriteComponent sprite, float distance)
|
||||||
|
{
|
||||||
|
const float thrustEnd = 0.05f;
|
||||||
|
const float length = 0.15f;
|
||||||
|
|
||||||
|
return new Animation()
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(length),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty()
|
||||||
|
{
|
||||||
|
ComponentType = typeof(SpriteComponent),
|
||||||
|
Property = nameof(SpriteComponent.Offset),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance / 5f)), 0f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance)), thrustEnd),
|
||||||
|
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance)), 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,14 +197,13 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
target = screen.GetEntityUnderPosition(mousePos);
|
target = screen.GetEntityUnderPosition(mousePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.RaisePredictiveEvent(new LightAttackEvent(target, weapon.Owner, coordinates));
|
RaisePredictiveEvent(new LightAttackEvent(target, weapon.Owner, coordinates));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapon.Attacking)
|
if (weapon.Attacking)
|
||||||
{
|
{
|
||||||
EntityManager.RaisePredictiveEvent(new StopAttackEvent(weapon.Owner));
|
RaisePredictiveEvent(new StopAttackEvent(weapon.Owner));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,189 +244,4 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
if (Exists(ev.Entity))
|
if (Exists(ev.Entity))
|
||||||
DoLunge(ev.Entity, ev.Angle, ev.LocalPos, ev.Animation);
|
DoLunge(ev.Entity, ev.Angle, ev.LocalPos, ev.Animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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, Angle angle, Vector2 localPos, string? animation)
|
|
||||||
{
|
|
||||||
if (!Timing.IsFirstTimePredicted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var lunge = GetLungeAnimation(localPos);
|
|
||||||
|
|
||||||
// Stop any existing lunges on the user.
|
|
||||||
_animation.Stop(user, MeleeLungeKey);
|
|
||||||
_animation.Play(user, lunge, MeleeLungeKey);
|
|
||||||
|
|
||||||
// Clientside entity to spawn
|
|
||||||
if (animation != null)
|
|
||||||
{
|
|
||||||
var animationUid = Spawn(animation, new EntityCoordinates(user, Vector2.Zero));
|
|
||||||
|
|
||||||
if (localPos != Vector2.Zero && TryComp<SpriteComponent>(animationUid, out var sprite))
|
|
||||||
{
|
|
||||||
sprite[0].AutoAnimated = false;
|
|
||||||
|
|
||||||
if (TryComp<WeaponArcVisualsComponent>(animationUid, out var arcComponent))
|
|
||||||
{
|
|
||||||
sprite.NoRotation = true;
|
|
||||||
sprite.Rotation = localPos.ToWorldAngle();
|
|
||||||
var distance = Math.Clamp(localPos.Length / 2f, 0.2f, 1f);
|
|
||||||
|
|
||||||
switch (arcComponent.Animation)
|
|
||||||
{
|
|
||||||
case WeaponArcAnimation.Slash:
|
|
||||||
_animation.Play(animationUid, GetSlashAnimation(sprite, angle), "melee-slash");
|
|
||||||
break;
|
|
||||||
case WeaponArcAnimation.Thrust:
|
|
||||||
_animation.Play(animationUid, GetThrustAnimation(sprite, distance), "melee-thrust");
|
|
||||||
break;
|
|
||||||
case WeaponArcAnimation.None:
|
|
||||||
sprite.Offset = localPos.Normalized * distance;
|
|
||||||
_animation.Play(animationUid, GetStaticAnimation(sprite), "melee-fade");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Animation GetSlashAnimation(SpriteComponent sprite, Angle arc)
|
|
||||||
{
|
|
||||||
var slashStart = 0.03f;
|
|
||||||
var slashEnd = 0.065f;
|
|
||||||
var length = slashEnd + 0.05f;
|
|
||||||
var startRotation = sprite.Rotation - arc / 2;
|
|
||||||
var endRotation = sprite.Rotation + arc / 2;
|
|
||||||
sprite.NoRotation = true;
|
|
||||||
|
|
||||||
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(startRotation.RotateVec(new Vector2(0f, -1f)), 0f),
|
|
||||||
new AnimationTrackProperty.KeyFrame(startRotation.RotateVec(new Vector2(0f, -1f)), slashStart),
|
|
||||||
new AnimationTrackProperty.KeyFrame(endRotation.RotateVec(new Vector2(0f, -1f)), slashEnd)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new AnimationTrackComponentProperty()
|
|
||||||
{
|
|
||||||
ComponentType = typeof(SpriteComponent),
|
|
||||||
Property = nameof(SpriteComponent.Color),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color, slashEnd),
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), length),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Animation GetThrustAnimation(SpriteComponent sprite, float distance)
|
|
||||||
{
|
|
||||||
var length = 0.15f;
|
|
||||||
var thrustEnd = 0.05f;
|
|
||||||
|
|
||||||
return new Animation()
|
|
||||||
{
|
|
||||||
Length = TimeSpan.FromSeconds(length),
|
|
||||||
AnimationTracks =
|
|
||||||
{
|
|
||||||
new AnimationTrackComponentProperty()
|
|
||||||
{
|
|
||||||
ComponentType = typeof(SpriteComponent),
|
|
||||||
Property = nameof(SpriteComponent.Offset),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance / 5f)), 0f),
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance)), thrustEnd),
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Rotation.RotateVec(new Vector2(0f, -distance)), length),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new AnimationTrackComponentProperty()
|
|
||||||
{
|
|
||||||
ComponentType = typeof(SpriteComponent),
|
|
||||||
Property = nameof(SpriteComponent.Color),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color, thrustEnd),
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), length),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the fadeout for static weapon arcs.
|
|
||||||
/// </summary>
|
|
||||||
private Animation GetStaticAnimation(SpriteComponent sprite)
|
|
||||||
{
|
|
||||||
var length = 0.15f;
|
|
||||||
|
|
||||||
return new()
|
|
||||||
{
|
|
||||||
Length = TimeSpan.FromSeconds(length),
|
|
||||||
AnimationTracks =
|
|
||||||
{
|
|
||||||
new AnimationTrackComponentProperty()
|
|
||||||
{
|
|
||||||
ComponentType = typeof(SpriteComponent),
|
|
||||||
Property = nameof(SpriteComponent.Color),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color, 0f),
|
|
||||||
new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the sprite offset animation to use for mob lunges.
|
|
||||||
/// </summary>
|
|
||||||
private Animation GetLungeAnimation(Vector2 direction)
|
|
||||||
{
|
|
||||||
var 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ namespace Content.Server.Zombies
|
|||||||
//This is the actual damage of the zombie. We assign the visual appearance
|
//This is the actual damage of the zombie. We assign the visual appearance
|
||||||
//and range here because of stuff we'll find out later
|
//and range here because of stuff we'll find out later
|
||||||
var melee = EnsureComp<MeleeWeaponComponent>(target);
|
var melee = EnsureComp<MeleeWeaponComponent>(target);
|
||||||
melee.Animation = zombiecomp.AttackAnimation;
|
melee.ClickAnimation = zombiecomp.AttackAnimation;
|
||||||
|
melee.WideAnimation = zombiecomp.AttackAnimation;
|
||||||
melee.Range = 0.75f;
|
melee.Range = 0.75f;
|
||||||
|
|
||||||
//We have specific stuff for humanoid zombies because they matter more
|
//We have specific stuff for humanoid zombies because they matter more
|
||||||
|
|||||||
@@ -97,7 +97,10 @@ public sealed class MeleeWeaponComponent : Component
|
|||||||
public Angle Angle = Angle.FromDegrees(60);
|
public Angle Angle = Angle.FromDegrees(60);
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("animation", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[ViewVariables(VVAccess.ReadWrite), DataField("animation", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
public string Animation = "WeaponArcSlash";
|
public string ClickAnimation = "WeaponArcPunch";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("wideAnimation", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string WideAnimation = "WeaponArcSlash";
|
||||||
|
|
||||||
// Sounds
|
// Sounds
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
using Content.Shared.Weapons.Melee.Events;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
@@ -272,19 +271,23 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
weapon.NextAttack += TimeSpan.FromSeconds(1f / weapon.AttackRate);
|
weapon.NextAttack += TimeSpan.FromSeconds(1f / weapon.AttackRate);
|
||||||
|
|
||||||
// Attack confirmed
|
// Attack confirmed
|
||||||
|
string animation;
|
||||||
|
|
||||||
switch (attack)
|
switch (attack)
|
||||||
{
|
{
|
||||||
case LightAttackEvent light:
|
case LightAttackEvent light:
|
||||||
DoLightAttack(user, light, weapon, session);
|
DoLightAttack(user, light, weapon, session);
|
||||||
|
animation = weapon.ClickAnimation;
|
||||||
break;
|
break;
|
||||||
case DisarmAttackEvent disarm:
|
case DisarmAttackEvent disarm:
|
||||||
if (!DoDisarm(user, disarm, weapon, session))
|
if (!DoDisarm(user, disarm, weapon, session))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
animation = weapon.ClickAnimation;
|
||||||
break;
|
break;
|
||||||
case HeavyAttackEvent heavy:
|
case HeavyAttackEvent heavy:
|
||||||
DoHeavyAttack(user, heavy, weapon, session);
|
DoHeavyAttack(user, heavy, weapon, session);
|
||||||
|
animation = weapon.WideAnimation;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -293,7 +296,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
// Play a sound to give instant feedback; same with playing the animations
|
// Play a sound to give instant feedback; same with playing the animations
|
||||||
Audio.PlayPredicted(weapon.SwingSound, weapon.Owner, user);
|
Audio.PlayPredicted(weapon.SwingSound, weapon.Owner, user);
|
||||||
|
|
||||||
DoLungeAnimation(user, weapon.Angle, attack.Coordinates.ToMap(EntityManager), weapon.Animation);
|
DoLungeAnimation(user, weapon.Angle, attack.Coordinates.ToMap(EntityManager), weapon.Range, animation);
|
||||||
weapon.Attacking = true;
|
weapon.Attacking = true;
|
||||||
Dirty(weapon);
|
Dirty(weapon);
|
||||||
}
|
}
|
||||||
@@ -351,7 +354,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoLungeAnimation(EntityUid user, Angle angle, MapCoordinates coordinates, string? animation)
|
private void DoLungeAnimation(EntityUid user, Angle angle, MapCoordinates coordinates, float length, string? animation)
|
||||||
{
|
{
|
||||||
// TODO: Assert that offset eyes are still okay.
|
// TODO: Assert that offset eyes are still okay.
|
||||||
if (!TryComp<TransformComponent>(user, out var userXform))
|
if (!TryComp<TransformComponent>(user, out var userXform))
|
||||||
@@ -364,6 +367,14 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
localPos = userXform.LocalRotation.RotateVec(localPos);
|
localPos = userXform.LocalRotation.RotateVec(localPos);
|
||||||
|
|
||||||
|
// We'll play the effect just short visually so it doesn't look like we should be hitting but actually aren't.
|
||||||
|
const float BufferLength = 0.2f;
|
||||||
|
var visualLength = length - BufferLength;
|
||||||
|
|
||||||
|
if (localPos.Length > visualLength)
|
||||||
|
localPos = localPos.Normalized * visualLength;
|
||||||
|
|
||||||
DoLunge(user, angle, localPos, animation);
|
DoLunge(user, angle, localPos, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,22 @@
|
|||||||
- type: EffectVisuals
|
- type: EffectVisuals
|
||||||
- type: WeaponArcVisuals
|
- type: WeaponArcVisuals
|
||||||
|
|
||||||
# TODO: Camera recoil (try it as a shake, i.e. zoom out and then rotate slightly maybe)
|
- type: entity
|
||||||
# See https://github.com/gasgiant/Camera-Shake
|
# Plays the state animation then disappears with no fade or swing
|
||||||
|
id: WeaponArcAnimated
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Effects/arcs.rsi
|
||||||
|
state: disarm
|
||||||
|
netsync: false
|
||||||
|
drawdepth: Effects
|
||||||
|
- type: EffectVisuals
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
|
|
||||||
|
|
||||||
|
# Uses TimedDespawn instead of EffectVisuals because auto animation is easier but doesn't raise an animation complete event.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponArcThrust
|
id: WeaponArcThrust
|
||||||
@@ -22,8 +36,6 @@
|
|||||||
- type: WeaponArcVisuals
|
- type: WeaponArcVisuals
|
||||||
animation: Thrust
|
animation: Thrust
|
||||||
|
|
||||||
# TODO: Hold for 0.1, thrust out n distance, then fade out
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponArcSlash
|
id: WeaponArcSlash
|
||||||
parent: WeaponArcStatic
|
parent: WeaponArcStatic
|
||||||
@@ -38,24 +50,36 @@
|
|||||||
parent: WeaponArcStatic
|
parent: WeaponArcStatic
|
||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: bite
|
state: bite
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.399
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponArcClaw
|
id: WeaponArcClaw
|
||||||
parent: WeaponArcStatic
|
parent: WeaponArcStatic
|
||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: claw
|
state: claw
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.399
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponArcDisarm
|
id: WeaponArcDisarm
|
||||||
parent: WeaponArcStatic
|
parent: WeaponArcAnimated
|
||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: disarm
|
state: disarm
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.299
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponArcFist
|
id: WeaponArcFist
|
||||||
@@ -64,3 +88,39 @@
|
|||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: fist
|
state: fist
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: WeaponArcPunch
|
||||||
|
parent: WeaponArcStatic
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
|
- type: Sprite
|
||||||
|
state: punch
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.499
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: WeaponArcKick
|
||||||
|
parent: WeaponArcStatic
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
|
- type: Sprite
|
||||||
|
state: kick
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.299
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: WeaponArcSmash
|
||||||
|
parent: WeaponArcStatic
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: WeaponArcVisuals
|
||||||
|
fadeOut: false
|
||||||
|
- type: Sprite
|
||||||
|
state: smash
|
||||||
|
- type: TimedDespawn
|
||||||
|
lifetime: 0.299
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
angle: 0
|
angle: 0
|
||||||
soundHit:
|
soundHit:
|
||||||
collection: AlienClaw
|
collection: AlienClaw
|
||||||
animation: WeaponArcClaw
|
animation: WeaponArcBite
|
||||||
damage:
|
damage:
|
||||||
groups:
|
groups:
|
||||||
Brute: 12
|
Brute: 12
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
soundHit:
|
soundHit:
|
||||||
path: /Audio/Weapons/pierce.ogg
|
path: /Audio/Weapons/pierce.ogg
|
||||||
angle: 30
|
angle: 30
|
||||||
animation: WeaponArcFist
|
animation: WeaponArcPunch
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Piercing: 5
|
Piercing: 5
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 188 B After Width: | Height: | Size: 5.0 KiB |
@@ -5,7 +5,7 @@
|
|||||||
"y": 32
|
"y": 32
|
||||||
},
|
},
|
||||||
"license": "CC-BY-SA-3.0",
|
"license": "CC-BY-SA-3.0",
|
||||||
"copyright": "https://github.com/tgstation/tgstation/raw/c545428822f1ee0d402b812221518632dbe198cb/icons/effects/effects.dmi",
|
"copyright": "Taken from https://github.com/tgstation/tgstation/raw/c545428822f1ee0d402b812221518632dbe198cb/icons/effects/effects.dmi with offsets modified",
|
||||||
"states": [
|
"states": [
|
||||||
{
|
{
|
||||||
"name": "bite",
|
"name": "bite",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 4.8 KiB |
Reference in New Issue
Block a user