Added a component that lets ranged weapons make melee attacks. (#29484)
This commit is contained in:
@@ -6,6 +6,7 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
|
using Content.Shared.Weapons.Melee.Components;
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
using Content.Shared.Weapons.Melee.Events;
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
@@ -89,16 +90,6 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
|
|
||||||
// TODO using targeted actions while combat mode is enabled should NOT trigger attacks.
|
// TODO using targeted actions while combat mode is enabled should NOT trigger attacks.
|
||||||
|
|
||||||
// TODO: Need to make alt-fire melee its own component I guess?
|
|
||||||
// Melee and guns share a lot in the middle but share virtually nothing at the start and end so
|
|
||||||
// it's kinda tricky.
|
|
||||||
// I think as long as we make secondaries their own component it's probably fine
|
|
||||||
// as long as guncomp has an alt-use key then it shouldn't be too much of a PITA to deal with.
|
|
||||||
if (TryComp<GunComponent>(weaponUid, out var gun) && gun.UseKey)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
||||||
|
|
||||||
if (mousePos.MapId == MapId.Nullspace)
|
if (mousePos.MapId == MapId.Nullspace)
|
||||||
@@ -117,20 +108,37 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
coordinates = TransformSystem.ToCoordinates(_map.GetMap(mousePos.MapId), mousePos);
|
coordinates = TransformSystem.ToCoordinates(_map.GetMap(mousePos.MapId), mousePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the gun has AltFireComponent, it can be used to attack.
|
||||||
|
if (TryComp<GunComponent>(weaponUid, out var gun) && gun.UseKey)
|
||||||
|
{
|
||||||
|
if (!TryComp<AltFireMeleeComponent>(weaponUid, out var altFireComponent) || altDown != BoundKeyState.Down)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch(altFireComponent.AttackType)
|
||||||
|
{
|
||||||
|
case AltFireAttackType.Light:
|
||||||
|
ClientLightAttack(entity, mousePos, coordinates, weaponUid, weapon);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AltFireAttackType.Heavy:
|
||||||
|
ClientHeavyAttack(entity, coordinates, weaponUid, weapon);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AltFireAttackType.Disarm:
|
||||||
|
ClientDisarm(entity, mousePos, coordinates);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Heavy attack.
|
// Heavy attack.
|
||||||
if (altDown == BoundKeyState.Down)
|
if (altDown == BoundKeyState.Down)
|
||||||
{
|
{
|
||||||
// If it's an unarmed attack then do a disarm
|
// If it's an unarmed attack then do a disarm
|
||||||
if (weapon.AltDisarm && weaponUid == entity)
|
if (weapon.AltDisarm && weaponUid == entity)
|
||||||
{
|
{
|
||||||
EntityUid? target = null;
|
ClientDisarm(entity, mousePos, coordinates);
|
||||||
|
|
||||||
if (_stateManager.CurrentState is GameplayStateBase screen)
|
|
||||||
{
|
|
||||||
target = screen.GetClickedEntity(mousePos);
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(GetNetEntity(target), GetNetCoordinates(coordinates)));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,28 +148,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
|
|
||||||
// Light attack
|
// Light attack
|
||||||
if (useDown == BoundKeyState.Down)
|
if (useDown == BoundKeyState.Down)
|
||||||
{
|
ClientLightAttack(entity, mousePos, coordinates, weaponUid, weapon);
|
||||||
var attackerPos = TransformSystem.GetMapCoordinates(entity);
|
|
||||||
|
|
||||||
if (mousePos.MapId != attackerPos.MapId ||
|
|
||||||
(attackerPos.Position - mousePos.Position).Length() > weapon.Range)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityUid? target = null;
|
|
||||||
|
|
||||||
if (_stateManager.CurrentState is GameplayStateBase screen)
|
|
||||||
{
|
|
||||||
target = screen.GetClickedEntity(mousePos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't light-attack if interaction will be handling this instead
|
|
||||||
if (Interaction.CombatModeCanHandInteract(entity, target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session)
|
protected override bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session)
|
||||||
@@ -236,6 +223,35 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(MaxTargets, entities.Count)), GetNetCoordinates(coordinates)));
|
RaisePredictiveEvent(new HeavyAttackEvent(GetNetEntity(meleeUid), entities.GetRange(0, Math.Min(MaxTargets, entities.Count)), GetNetCoordinates(coordinates)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ClientDisarm(EntityUid attacker, MapCoordinates mousePos, EntityCoordinates coordinates)
|
||||||
|
{
|
||||||
|
EntityUid? target = null;
|
||||||
|
|
||||||
|
if (_stateManager.CurrentState is GameplayStateBase screen)
|
||||||
|
target = screen.GetClickedEntity(mousePos);
|
||||||
|
|
||||||
|
RaisePredictiveEvent(new DisarmAttackEvent(GetNetEntity(target), GetNetCoordinates(coordinates)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientLightAttack(EntityUid attacker, MapCoordinates mousePos, EntityCoordinates coordinates, EntityUid weaponUid, MeleeWeaponComponent meleeComponent)
|
||||||
|
{
|
||||||
|
var attackerPos = TransformSystem.GetMapCoordinates(attacker);
|
||||||
|
|
||||||
|
if (mousePos.MapId != attackerPos.MapId || (attackerPos.Position - mousePos.Position).Length() > meleeComponent.Range)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EntityUid? target = null;
|
||||||
|
|
||||||
|
if (_stateManager.CurrentState is GameplayStateBase screen)
|
||||||
|
target = screen.GetClickedEntity(mousePos);
|
||||||
|
|
||||||
|
// Don't light-attack if interaction will be handling this instead
|
||||||
|
if (Interaction.CombatModeCanHandInteract(attacker, target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates)));
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMeleeLunge(MeleeLungeEvent ev)
|
private void OnMeleeLunge(MeleeLungeEvent ev)
|
||||||
{
|
{
|
||||||
var ent = GetEntity(ev.Entity);
|
var ent = GetEntity(ev.Entity);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Weapons.Melee.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used to allow ranged weapons to make melee attacks by right-clicking.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedMeleeWeaponSystem))]
|
||||||
|
public sealed partial class AltFireMeleeComponent : Component
|
||||||
|
{
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public AltFireAttackType AttackType = AltFireAttackType.Light;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum AltFireAttackType : byte
|
||||||
|
{
|
||||||
|
Light = 0, // Standard single-target attack.
|
||||||
|
Heavy = 1 << 0, // Wide swing.
|
||||||
|
Disarm = 1 << 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user