* delete all modular content * clean up * Update guard.yml * spear first pass * Add imperial two-handed sword and update spear Introduces the imperial two-handed sword with new sprites, prototype, and animations. Refines spear configuration: adjusts damage, animation, and offsets, and updates its sprites and prototype to use a new resource path. Improves melee weapon animation logic for both thrust and slash attacks. * neck displacement * Update neck.png * Update migration.yml * dagger * Add sword prototype and refactor melee weapon swing logic Introduces a new sword entity and associated textures. Refactors melee weapon swing logic by renaming SwingLeft to CPSwingLeft and updating related code. Adjusts animation offsets and rotation values for daggers, spears, and two-handed swords. Moves and updates dagger texture assets to a new directory structure. * hatchet * sickle * Add skimitar sword entity and sprites Introduced a new 'skimitar' sword entity with description and associated sprite assets, including icon, in-hand, and equipped states. Also updated the imperial sword's name and description for clarity. * Add rapier weapon and adjust melee weapon balance Introduced the imperial rapier weapon with associated prototype and textures. Increased the default single-target melee damage modifier to 1.3 and removed per-weapon clickDamageModifier overrides from dagger, spear, sword, and two-handed sword. Also increased sword base damage to 10 for better balance. * Add iron tool/weapon variants and update wall thresholds Introduces iron variants for pickaxe, shovel, dagger, rapier, spear, sword, and two-handed sword, including new sprites and YAML prototypes. Adjusts wall and ore vein damage thresholds for destruction and sound triggers. Updates migration.yml to map modular iron weapons to new iron variants and spawns stone blocks on stonebrick wall breakage. Also refactors dagger textures to use an 'iron' directory. * Refactor ice dagger and adjust blacksmith skills Replaced CP14IceDagger with CP14WeaponDaggerIce, updating its parent, stats, and components for consistency. Adjusted base dagger damage types. Blacksmith job and related melting skills are now commented out or disabled, reflecting a change in skill progression and job setup. * Update ice_dagger.yml * Deprecate sword mastery skills and update melee swing logic Commented out SwordMastery, RapierMastery, and SkimitarMastery skills and removed their assignment from guard and artisan job prototypes. Renamed CPSwingLeft to SwingLeft in melee weapon code for clarity and updated related logic. * Remove requiredSkills from anvil and furnace recipes Eliminated the 'requiredSkills' field from all recipes in Anvil/misc.yml and furnace.yml. This simplifies recipe definitions and removes skill prerequisites for crafting these items. * Update guard_commander.yml * Comment out freeLearnedSkills for T1 and T2 skeletons Disabled the freeLearnedSkills entries, including SwordMastery and SkimitarMastery, in both T1 and T2 DemiplaneAntag skeleton YAML prototypes. This change may be for balancing or testing purposes. * Update migration.yml * Update migration.yml * guidebook * r * spear passive + hammer passive * tool hammer + skimitar refactor * balance tweak * kick nerf * TOWER DEFENCE UPDATE * default shield refactor * buckler (only sprites) * Update migration.yml * buckler parry * some fixes * Update T2.yml * Update T2.yml * Update instruments.yml * Update migration.yml * M O P * war axe * Update migration.yml * Keen Eye skill * arrows + bow + loadouts * Update tools.yml * trading * fix * Update misc.yml * Update migration.yml
334 lines
14 KiB
C#
334 lines
14 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 length = 1f; //CrystallEdgeMelee upgrade
|
|
var offset = -1f; //CrystallEdge Melee upgrade
|
|
|
|
var spriteRotation = Angle.Zero;
|
|
if (arcComponent.Animation != WeaponArcAnimation.None
|
|
&& TryComp(weapon, out MeleeWeaponComponent? meleeWeaponComponent))
|
|
{
|
|
if (user != weapon
|
|
&& TryComp(weapon, out SpriteComponent? weaponSpriteComponent))
|
|
_sprite.CopySprite((weapon, weaponSpriteComponent), (animationUid, sprite));
|
|
|
|
spriteRotation = meleeWeaponComponent.WideAnimationRotation;
|
|
|
|
if (meleeWeaponComponent.SwingLeft)
|
|
angle *= -1;
|
|
|
|
length = meleeWeaponComponent.CPAnimationLength; //CrystallEdge Melee upgrade
|
|
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallEdge Melee upgrade
|
|
}
|
|
_sprite.SetRotation((animationUid, sprite), 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((animationUid, 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;
|
|
//CrystallEdge MeleeUpgrade
|
|
case WeaponArcAnimation.CPSlash:
|
|
track = EnsureComp<TrackUserComponent>(animationUid);
|
|
track.User = user;
|
|
_animation.Play(animationUid, CPGetSlashAnimation(sprite, angle, spriteRotation, length, offset), SlashAnimationKey);
|
|
if (arcComponent.Fadeout)
|
|
_animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
|
|
break;
|
|
case WeaponArcAnimation.CPThrust:
|
|
track = EnsureComp<TrackUserComponent>(animationUid);
|
|
track.User = user;
|
|
_animation.Play(animationUid, CPGetThrustAnimation(sprite, -offset * 2, spriteRotation, length), ThrustAnimationKey);
|
|
if (arcComponent.Fadeout)
|
|
_animation.Play(animationUid, GetFadeAnimation(sprite, length * 0.5f, length + 0.15f), FadeAnimationKey);
|
|
break;
|
|
//CrystallEdge MeleeUpgrade end
|
|
}
|
|
}
|
|
|
|
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(Entity<SpriteComponent> sprite, float distance, Angle spriteRotation)
|
|
{
|
|
const float thrustEnd = 0.05f;
|
|
const float length = 0.15f;
|
|
var startOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -distance / 5f));
|
|
var endOffset = sprite.Comp.Rotation.RotateVec(new Vector2(0f, -distance));
|
|
_sprite.SetRotation(sprite.AsNullable(), sprite.Comp.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.2f; // 0.1 original, CrystallEdge update
|
|
|
|
return new Animation
|
|
{
|
|
Length = TimeSpan.FromSeconds(length),
|
|
AnimationTracks =
|
|
{
|
|
new AnimationTrackComponentProperty()
|
|
{
|
|
ComponentType = typeof(SpriteComponent),
|
|
Property = nameof(SpriteComponent.Offset),
|
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
|
KeyFrames =
|
|
{
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallEdge MeleeUpgrade
|
|
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallEdge MeleeUpgrade
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallEdge MeleeUpgrade
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/// <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(arcComponent.User.Value);
|
|
|
|
if (arcComponent.Offset != Vector2.Zero)
|
|
{
|
|
var entRotation = TransformSystem.GetWorldRotation(xform);
|
|
targetPos += entRotation.RotateVec(arcComponent.Offset);
|
|
}
|
|
|
|
TransformSystem.SetWorldPosition(uid, targetPos);
|
|
}
|
|
}
|
|
|
|
//CrystallEdge MeleeUpgrade start
|
|
private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f)
|
|
{
|
|
var startRotation = sprite.Rotation + (arc * 0.5f);
|
|
var endRotation = sprite.Rotation - (arc * 0.5f);
|
|
|
|
var startRotationOffset = startRotation.RotateVec(new Vector2(0f, -offset * 0.9f));
|
|
var minRotationOffset = sprite.Rotation.RotateVec(new Vector2(0f, -offset * 1.1f));
|
|
var endRotationOffset = endRotation.RotateVec(new Vector2(0f, -offset * 0.9f));
|
|
|
|
startRotation += spriteRotation;
|
|
endRotation += spriteRotation;
|
|
sprite.NoRotation = true;
|
|
|
|
return new Animation()
|
|
{
|
|
Length = TimeSpan.FromSeconds(length + 0.05f),
|
|
AnimationTracks =
|
|
{
|
|
new AnimationTrackComponentProperty()
|
|
{
|
|
ComponentType = typeof(SpriteComponent),
|
|
Property = nameof(SpriteComponent.Rotation),
|
|
KeyFrames =
|
|
{
|
|
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.0f), length * 0.0f),
|
|
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.5f), length * 0.3f),
|
|
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,1.0f), length * 0.6f),
|
|
new AnimationTrackProperty.KeyFrame(Angle.Lerp(startRotation,endRotation,0.8f), length * 1.0f),
|
|
}
|
|
},
|
|
new AnimationTrackComponentProperty()
|
|
{
|
|
ComponentType = typeof(SpriteComponent),
|
|
Property = nameof(SpriteComponent.Offset),
|
|
KeyFrames =
|
|
{
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.0f), length * 0.0f),
|
|
new AnimationTrackProperty.KeyFrame(minRotationOffset, length * 0.3f),
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,1.0f), length * 0.6f),
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startRotationOffset,endRotationOffset,0.8f), length * 1.0f),
|
|
}
|
|
},
|
|
}
|
|
};
|
|
}
|
|
|
|
private Animation CPGetThrustAnimation(SpriteComponent sprite, float offset, Angle spriteRotation, float length)
|
|
{
|
|
var startOffset = sprite.Rotation.RotateVec(new Vector2(0f, 0f));
|
|
var endOffset = sprite.Rotation.RotateVec(new Vector2(0f, offset / 2));
|
|
|
|
sprite.Rotation += spriteRotation;
|
|
|
|
return new Animation()
|
|
{
|
|
Length = TimeSpan.FromSeconds(length),
|
|
AnimationTracks =
|
|
{
|
|
new AnimationTrackComponentProperty()
|
|
{
|
|
ComponentType = typeof(SpriteComponent),
|
|
Property = nameof(SpriteComponent.Offset),
|
|
KeyFrames =
|
|
{
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0f), length * 0f),
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 1f), length * 0.5f),
|
|
new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startOffset, endOffset, 0.9f), length * 0.8f),
|
|
}
|
|
},
|
|
}
|
|
};
|
|
}
|
|
|
|
//CrystallEdge MeleeUpgrade end
|
|
|
|
}
|