Follow mouse rotation in combat mode (#20433)

This commit is contained in:
Kara
2023-09-24 14:22:44 -07:00
committed by GitHub
parent 19a977e805
commit 2e481be694
6 changed files with 94 additions and 8 deletions

View File

@@ -41,6 +41,22 @@ public sealed class MouseRotatorSystem : SharedMouseRotatorSystem
var curRot = _transform.GetWorldRotation(xform); var curRot = _transform.GetWorldRotation(xform);
// 4-dir handling is separate --
// only raise event if the cardinal direction has changed
if (rotator.Simple4DirMode)
{
var angleDir = angle.GetCardinalDir();
if (angleDir == curRot.GetCardinalDir())
return;
RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent()
{
Direction = angleDir,
});
return;
}
// Don't raise event if mouse ~hasn't moved (or if too close to goal rotation already) // Don't raise event if mouse ~hasn't moved (or if too close to goal rotation already)
var diff = Angle.ShortestDistance(angle, curRot); var diff = Angle.ShortestDistance(angle, curRot);
if (Math.Abs(diff.Theta) < rotator.AngleTolerance.Theta) if (Math.Abs(diff.Theta) < rotator.AngleTolerance.Theta)

View File

@@ -1,3 +1,5 @@
using Content.Shared.MouseRotator;
using Content.Shared.Movement.Components;
using Content.Shared.Targeting; using Content.Shared.Targeting;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
@@ -41,6 +43,13 @@ namespace Content.Shared.CombatMode
[ViewVariables(VVAccess.ReadWrite), DataField("isInCombatMode"), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite), DataField("isInCombatMode"), AutoNetworkedField]
public bool IsInCombatMode; public bool IsInCombatMode;
/// <summary>
/// Will add <see cref="MouseRotatorComponent"/> and <see cref="NoRotateOnMoveComponent"/>
/// to entities with this flag enabled that enter combat mode, and vice versa for removal.
/// </summary>
[DataField, AutoNetworkedField]
public bool ToggleMouseRotator = true;
[ViewVariables(VVAccess.ReadWrite), DataField("activeZone"), AutoNetworkedField] [ViewVariables(VVAccess.ReadWrite), DataField("activeZone"), AutoNetworkedField]
public TargetingZone ActiveZone; public TargetingZone ActiveZone;
} }

View File

@@ -1,4 +1,6 @@
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.MouseRotator;
using Content.Shared.Movement.Components;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Targeting; using Content.Shared.Targeting;
using Robust.Shared.Network; using Robust.Shared.Network;
@@ -30,6 +32,8 @@ public abstract class SharedCombatModeSystem : EntitySystem
private void OnShutdown(EntityUid uid, CombatModeComponent component, ComponentShutdown args) private void OnShutdown(EntityUid uid, CombatModeComponent component, ComponentShutdown args)
{ {
_actionsSystem.RemoveAction(uid, component.CombatToggleActionEntity); _actionsSystem.RemoveAction(uid, component.CombatToggleActionEntity);
SetMouseRotatorComponents(uid, false);
} }
private void OnActionPerform(EntityUid uid, CombatModeComponent component, ToggleCombatActionEvent args) private void OnActionPerform(EntityUid uid, CombatModeComponent component, ToggleCombatActionEvent args)
@@ -76,6 +80,12 @@ public abstract class SharedCombatModeSystem : EntitySystem
if (component.CombatToggleActionEntity != null) if (component.CombatToggleActionEntity != null)
_actionsSystem.SetToggled(component.CombatToggleActionEntity, component.IsInCombatMode); _actionsSystem.SetToggled(component.CombatToggleActionEntity, component.IsInCombatMode);
// Change mouse rotator comps if flag is set
if (!component.ToggleMouseRotator)
return;
SetMouseRotatorComponents(entity, value);
} }
public virtual void SetActiveZone(EntityUid entity, TargetingZone zone, public virtual void SetActiveZone(EntityUid entity, TargetingZone zone,
@@ -86,6 +96,20 @@ public abstract class SharedCombatModeSystem : EntitySystem
component.ActiveZone = zone; component.ActiveZone = zone;
} }
private void SetMouseRotatorComponents(EntityUid uid, bool value)
{
if (value)
{
EnsureComp<MouseRotatorComponent>(uid);
EnsureComp<NoRotateOnMoveComponent>(uid);
}
else
{
RemComp<MouseRotatorComponent>(uid);
RemComp<NoRotateOnMoveComponent>(uid);
}
}
} }
public sealed partial class ToggleCombatActionEvent : InstantActionEvent { } public sealed partial class ToggleCombatActionEvent : InstantActionEvent { }

View File

@@ -14,22 +14,31 @@ public sealed partial class MouseRotatorComponent : Component
/// <summary> /// <summary>
/// How much the desired angle needs to change before a predictive event is sent /// How much the desired angle needs to change before a predictive event is sent
/// </summary> /// </summary>
[DataField] [DataField, AutoNetworkedField]
[ViewVariables(VVAccess.ReadWrite)] public Angle AngleTolerance = Angle.FromDegrees(20.0);
public Angle AngleTolerance = Angle.FromDegrees(5.0);
/// <summary> /// <summary>
/// The angle that will be lerped to /// The angle that will be lerped to
/// </summary> /// </summary>
[AutoNetworkedField, DataField] [DataField, AutoNetworkedField]
public Angle? GoalRotation; public Angle? GoalRotation;
/// <summary> /// <summary>
/// Max degrees the entity can rotate per second /// Max degrees the entity can rotate per second
/// </summary> /// </summary>
[DataField] [DataField, AutoNetworkedField]
[ViewVariables(VVAccess.ReadWrite)]
public double RotationSpeed = float.MaxValue; public double RotationSpeed = float.MaxValue;
/// <summary>
/// This one is important. If this is true, <see cref="AngleTolerance"/> does not apply, and the system will
/// use <see cref="RequestMouseRotatorRotationSimpleEvent"/> instead. In this mode, the client will only send
/// events when an entity should snap to a different cardinal direction, rather than for every angle change.
///
/// This is useful for cases like humans, where what really matters is the visual sprite direction, as opposed to something
/// like turrets or ship guns, which have finer range of movement.
/// </summary>
[DataField, AutoNetworkedField]
public bool Simple4DirMode = true;
} }
/// <summary> /// <summary>
@@ -41,3 +50,13 @@ public sealed class RequestMouseRotatorRotationEvent : EntityEventArgs
{ {
public Angle Rotation; public Angle Rotation;
} }
/// <summary>
/// Simpler version of <see cref="RequestMouseRotatorRotationEvent"/> for implementations
/// that only require snapping to 4-dir and not full angle rotation.
/// </summary>
[Serializable, NetSerializable]
public sealed class RequestMouseRotatorRotationSimpleEvent : EntityEventArgs
{
public Direction Direction;
}

View File

@@ -16,6 +16,7 @@ public abstract class SharedMouseRotatorSystem : EntitySystem
base.Initialize(); base.Initialize();
SubscribeAllEvent<RequestMouseRotatorRotationEvent>(OnRequestRotation); SubscribeAllEvent<RequestMouseRotatorRotationEvent>(OnRequestRotation);
SubscribeAllEvent<RequestMouseRotatorRotationSimpleEvent>(OnRequestSimpleRotation);
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@@ -48,13 +49,27 @@ public abstract class SharedMouseRotatorSystem : EntitySystem
private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessionEventArgs args) private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessionEventArgs args)
{ {
if (args.SenderSession.AttachedEntity is not { } ent || !TryComp<MouseRotatorComponent>(ent, out var rotator)) if (args.SenderSession.AttachedEntity is not { } ent
|| !TryComp<MouseRotatorComponent>(ent, out var rotator) || rotator.Simple4DirMode)
{ {
Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation without a mouse rotator component attached!"); Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation directly without a valid mouse rotator component attached!");
return; return;
} }
rotator.GoalRotation = msg.Rotation; rotator.GoalRotation = msg.Rotation;
Dirty(ent, rotator); Dirty(ent, rotator);
} }
private void OnRequestSimpleRotation(RequestMouseRotatorRotationSimpleEvent ev, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { } ent
|| !TryComp<MouseRotatorComponent>(ent, out var rotator) || !rotator.Simple4DirMode)
{
Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting 4-dir rotation directly without a valid mouse rotator component attached!");
return;
}
rotator.GoalRotation = ev.Direction.ToAngle();
Dirty(ent, rotator);
}
} }

View File

@@ -66,6 +66,7 @@
interactSuccessSound: interactSuccessSound:
path: /Audio/Effects/double_beep.ogg path: /Audio/Effects/double_beep.ogg
- type: CombatMode - type: CombatMode
toggleMouseRotator: false
- type: Damageable - type: Damageable
damageContainer: Inorganic damageContainer: Inorganic
- type: Destructible - type: Destructible
@@ -110,7 +111,9 @@
SoundTargetInLOS: !type:SoundPathSpecifier SoundTargetInLOS: !type:SoundPathSpecifier
path: /Audio/Effects/double_beep.ogg path: /Audio/Effects/double_beep.ogg
- type: MouseRotator - type: MouseRotator
angleTolerance: 5
rotationSpeed: 180 rotationSpeed: 180
simple4DirMode: false
- type: NoRotateOnInteract - type: NoRotateOnInteract
- type: NoRotateOnMove - type: NoRotateOnMove
- type: Input - type: Input