Small tweak and cleanup of spells and actions (#15943)
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Content.Client.Popups;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.ActionTypes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
@@ -28,9 +25,6 @@ namespace Content.Client.Actions
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceManager _resources = default!;
|
||||
[Dependency] private readonly ISerializationManager _serialization = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
|
||||
public event Action<ActionType>? ActionAdded;
|
||||
public event Action<ActionType>? ActionRemoved;
|
||||
|
||||
@@ -20,7 +20,6 @@ using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -39,7 +38,6 @@ namespace Content.Client.UserInterface.Systems.Actions;
|
||||
|
||||
public sealed class ActionUIController : UIController, IOnStateChanged<GameplayState>, IOnSystemChanged<ActionsSystem>
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlays = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -47,6 +45,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
[UISystemDependency] private readonly ActionsSystem? _actionsSystem = default;
|
||||
[UISystemDependency] private readonly InteractionOutlineSystem? _interactionOutline = default;
|
||||
[UISystemDependency] private readonly TargetOutlineSystem? _targetOutline = default;
|
||||
[UISystemDependency] private readonly SpriteSystem _spriteSystem = default!;
|
||||
|
||||
private const int DefaultPageIndex = 0;
|
||||
private ActionButtonContainer? _container;
|
||||
@@ -65,7 +64,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
/// <summary>
|
||||
/// Action slot we are currently selecting a target for.
|
||||
/// </summary>
|
||||
public TargetedAction? SelectingTargetFor { get; private set; } = null;
|
||||
public TargetedAction? SelectingTargetFor { get; private set; }
|
||||
|
||||
public ActionUIController()
|
||||
{
|
||||
@@ -190,15 +189,15 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (!_timing.IsFirstTimePredicted || _actionsSystem == null || SelectingTargetFor is not { } action)
|
||||
return false;
|
||||
|
||||
if (_playerManager.LocalPlayer?.ControlledEntity is not EntityUid user)
|
||||
if (_playerManager.LocalPlayer?.ControlledEntity is not { } user)
|
||||
return false;
|
||||
|
||||
if (!_entities.TryGetComponent(user, out ActionsComponent? comp))
|
||||
if (!EntityManager.TryGetComponent(user, out ActionsComponent? comp))
|
||||
return false;
|
||||
|
||||
// Is the action currently valid?
|
||||
if (!action.Enabled
|
||||
|| action.Charges != null && action.Charges == 0
|
||||
|| action.Charges is 0
|
||||
|| action.Cooldown.HasValue && action.Cooldown.Value.End > _timing.CurTime)
|
||||
{
|
||||
// The user is targeting with this action, but it is not valid. Maybe mark this click as
|
||||
@@ -247,7 +246,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
_actionsSystem.PerformAction(user, actionComp, action, action.Event, _timing.CurTime);
|
||||
}
|
||||
else
|
||||
_entities.RaisePredictiveEvent(new RequestPerformActionEvent(action, coords));
|
||||
EntityManager.RaisePredictiveEvent(new RequestPerformActionEvent(action, coords));
|
||||
|
||||
if (!action.Repeat)
|
||||
StopTargeting();
|
||||
@@ -279,7 +278,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
_actionsSystem.PerformAction(user, actionComp, action, action.Event, _timing.CurTime);
|
||||
}
|
||||
else
|
||||
_entities.RaisePredictiveEvent(new RequestPerformActionEvent(action, args.EntityUid));
|
||||
EntityManager.RaisePredictiveEvent(new RequestPerformActionEvent(action, args.EntityUid));
|
||||
|
||||
if (!action.Repeat)
|
||||
StopTargeting();
|
||||
@@ -414,6 +413,10 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
|
||||
private void OnActionAdded(ActionType action)
|
||||
{
|
||||
// if the action is toggled when we add it, start targetting
|
||||
if (action is TargetedAction targetAction && action.Toggled)
|
||||
StartTargeting(targetAction);
|
||||
|
||||
foreach (var page in _pages)
|
||||
{
|
||||
for (var i = 0; i < page.Size; i++)
|
||||
@@ -434,6 +437,10 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (_container == null)
|
||||
return;
|
||||
|
||||
// stop targeting if the action is removed
|
||||
if (action == SelectingTargetFor)
|
||||
StopTargeting();
|
||||
|
||||
foreach (var button in _container.GetButtons())
|
||||
{
|
||||
if (button.Action == action)
|
||||
@@ -520,8 +527,8 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
return filter switch
|
||||
{
|
||||
Filters.Enabled => action.Enabled,
|
||||
Filters.Item => action.Provider != null && action.Provider != _actionsSystem?.PlayerActions?.Owner,
|
||||
Filters.Innate => action.Provider == null || action.Provider == _actionsSystem?.PlayerActions?.Owner,
|
||||
Filters.Item => action.Provider != null && action.Provider != _playerManager.LocalPlayer?.ControlledEntity,
|
||||
Filters.Innate => action.Provider == null || action.Provider == _playerManager.LocalPlayer?.ControlledEntity,
|
||||
Filters.Instant => action is InstantAction,
|
||||
Filters.Targeted => action is TargetedAction,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(filter), filter, null)
|
||||
@@ -582,10 +589,10 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (action.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (action.Provider == null || action.Provider == _actionsSystem?.PlayerActions?.Owner)
|
||||
if (action.Provider == null || action.Provider == _playerManager.LocalPlayer?.ControlledEntity)
|
||||
return false;
|
||||
|
||||
var name = _entities.GetComponent<MetaDataComponent>(action.Provider.Value).EntityName;
|
||||
var name = EntityManager.GetComponent<MetaDataComponent>(action.Provider.Value).EntityName;
|
||||
return name.Contains(search, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
@@ -731,12 +738,12 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
{
|
||||
if (action.EntityIcon != null)
|
||||
{
|
||||
_dragShadow.Texture = _entities.GetComponent<SpriteComponent>(action.EntityIcon.Value).Icon?
|
||||
_dragShadow.Texture = EntityManager.GetComponent<SpriteComponent>(action.EntityIcon.Value).Icon?
|
||||
.GetFrame(RSI.State.Direction.South, 0);
|
||||
}
|
||||
else if (action.Icon != null)
|
||||
{
|
||||
_dragShadow.Texture = action.Icon!.Frame0();
|
||||
_dragShadow.Texture = _spriteSystem.Frame0(action.Icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -761,13 +768,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
_dragShadow.Visible = false;
|
||||
}
|
||||
|
||||
public void ReloadActionContainer()
|
||||
{
|
||||
UnloadGui();
|
||||
LoadGui();
|
||||
}
|
||||
|
||||
public void UnloadGui()
|
||||
private void UnloadGui()
|
||||
{
|
||||
_actionsSystem?.UnlinkAllActions();
|
||||
|
||||
@@ -780,7 +781,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
ActionsBar.PageButtons.RightArrow.OnPressed -= OnRightArrowPressed;
|
||||
}
|
||||
|
||||
public void LoadGui()
|
||||
private void LoadGui()
|
||||
{
|
||||
if (ActionsBar == null)
|
||||
{
|
||||
@@ -809,7 +810,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
_container.ActionUnpressed += OnActionUnpressed;
|
||||
}
|
||||
|
||||
public void ClearActions()
|
||||
private void ClearActions()
|
||||
{
|
||||
_container?.ClearActionData();
|
||||
}
|
||||
@@ -906,7 +907,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
/// If currently targeting with no slot or a different slot, switches to
|
||||
/// targeting with the specified slot.
|
||||
/// </summary>
|
||||
public void ToggleTargeting(TargetedAction action)
|
||||
private void ToggleTargeting(TargetedAction action)
|
||||
{
|
||||
if (SelectingTargetFor == action)
|
||||
{
|
||||
@@ -935,9 +936,9 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
handOverlay.EntityOverride = action.Provider;
|
||||
}
|
||||
else if (action.Toggled && action.IconOn != null)
|
||||
handOverlay.IconOverride = action.IconOn.Frame0();
|
||||
handOverlay.IconOverride = _spriteSystem.Frame0(action.IconOn);
|
||||
else if (action.Icon != null)
|
||||
handOverlay.IconOverride = action.Icon.Frame0();
|
||||
handOverlay.IconOverride = _spriteSystem.Frame0(action.Icon);
|
||||
}
|
||||
|
||||
// TODO: allow world-targets to check valid positions. E.g., maybe:
|
||||
@@ -962,7 +963,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
/// <summary>
|
||||
/// Switch out of targeting mode if currently selecting target for an action
|
||||
/// </summary>
|
||||
public void StopTargeting()
|
||||
private void StopTargeting()
|
||||
{
|
||||
if (SelectingTargetFor == null)
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Actions.ActionTypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
|
||||
namespace Content.Server.Magic;
|
||||
namespace Content.Server.Magic.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Spellbooks for having an entity learn spells as long as they've read the book and it's in their hand.
|
||||
@@ -19,14 +19,25 @@ public sealed class SpellbookComponent : Component
|
||||
/// The three fields below is just used for initialization.
|
||||
/// </summary>
|
||||
[DataField("worldSpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, WorldTargetActionPrototype>))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public readonly Dictionary<string, int> WorldSpells = new();
|
||||
|
||||
[DataField("entitySpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, EntityTargetActionPrototype>))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public readonly Dictionary<string, int> EntitySpells = new();
|
||||
|
||||
[DataField("instantSpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, InstantActionPrototype>))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public readonly Dictionary<string, int> InstantSpells = new();
|
||||
|
||||
[DataField("learnTime")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float LearnTime = .75f;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the spell action stays even after the book is removed
|
||||
/// </summary>
|
||||
[DataField("learnPermanently")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool LearnPermanently;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Body.Systems;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Magic.Components;
|
||||
using Content.Server.Magic.Events;
|
||||
using Content.Server.Weapons.Ranged.Systems;
|
||||
using Content.Shared.Actions;
|
||||
@@ -72,7 +73,7 @@ public sealed class MagicSystem : EntitySystem
|
||||
if (args.Handled || args.Cancelled)
|
||||
return;
|
||||
|
||||
_actionsSystem.AddActions(args.Args.User, component.Spells, uid);
|
||||
_actionsSystem.AddActions(args.Args.User, component.Spells, component.LearnPermanently ? null : uid);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -166,12 +167,14 @@ public sealed class MagicSystem : EntitySystem
|
||||
{
|
||||
// If applicable, this ensures the projectile is parented to grid on spawn, instead of the map.
|
||||
var mapPos = pos.ToMap(EntityManager);
|
||||
EntityCoordinates spawnCoords = _mapManager.TryFindGridAt(mapPos, out var grid)
|
||||
var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var grid)
|
||||
? pos.WithEntityId(grid.Owner, EntityManager)
|
||||
: new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position);
|
||||
|
||||
var ent = Spawn(ev.Prototype, spawnCoords);
|
||||
_gunSystem.ShootProjectile(ent, ev.Target.Position - mapPos.Position, userVelocity, ev.Performer);
|
||||
var direction = ev.Target.ToMapPos(EntityManager, _transformSystem) -
|
||||
spawnCoords.ToMapPos(EntityManager, _transformSystem);
|
||||
_gunSystem.ShootProjectile(ent, direction, userVelocity, ev.Performer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace Content.Shared.Actions;
|
||||
public sealed class ActionsComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
[Access(typeof(SharedActionsSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
[Access(typeof(SharedActionsSystem), Other = AccessPermissions.ReadExecute)]
|
||||
// FIXME Friends
|
||||
public SortedSet<ActionType> Actions = new();
|
||||
|
||||
public override bool SendOnlyToOwner => true;
|
||||
|
||||
@@ -5,12 +5,9 @@ using Content.Shared.Database;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
@@ -25,8 +22,8 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -98,7 +95,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
/// </summary>
|
||||
private void OnActionRequest(RequestPerformActionEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity is not EntityUid user)
|
||||
if (args.SenderSession.AttachedEntity is not { } user)
|
||||
return;
|
||||
|
||||
if (!TryComp(user, out ActionsComponent? component))
|
||||
@@ -134,7 +131,8 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
_rotateToFaceSystem.TryFaceCoordinates(user, Transform(entityTarget).WorldPosition);
|
||||
var targetWorldPos = _transformSystem.GetWorldPosition(entityTarget);
|
||||
_rotateToFaceSystem.TryFaceCoordinates(user, targetWorldPos);
|
||||
|
||||
if (!ValidateEntityTarget(user, entityTarget, entityAction))
|
||||
return;
|
||||
@@ -156,7 +154,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
|
||||
case WorldTargetAction worldAction:
|
||||
|
||||
if (ev.EntityCoordinatesTarget is not EntityCoordinates entityCoordinatesTarget)
|
||||
if (ev.EntityCoordinatesTarget is not { } entityCoordinatesTarget)
|
||||
{
|
||||
Logger.Error($"Attempted to perform a world-targeted action without a target! Action: {worldAction.DisplayName}");
|
||||
return;
|
||||
@@ -231,7 +229,8 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
if (action.Range <= 0)
|
||||
return true;
|
||||
|
||||
return (xform.WorldPosition - targetXform.WorldPosition).Length <= action.Range;
|
||||
var distance = (_transformSystem.GetWorldPosition(xform) - _transformSystem.GetWorldPosition(targetXform)).Length;
|
||||
return distance <= action.Range;
|
||||
}
|
||||
|
||||
if (_interactionSystem.InRangeUnobstructed(user, target, range: action.Range)
|
||||
@@ -259,7 +258,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
if (action.Range <= 0)
|
||||
return true;
|
||||
|
||||
return coords.InRange(EntityManager, Transform(user).Coordinates, action.Range);
|
||||
return coords.InRange(EntityManager, _transformSystem, Transform(user).Coordinates, action.Range);
|
||||
}
|
||||
|
||||
return _interactionSystem.InRangeUnobstructed(user, coords, range: action.Range);
|
||||
@@ -354,7 +353,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
{
|
||||
comp ??= EnsureComp<ActionsComponent>(uid);
|
||||
|
||||
bool allClientExclusive = true;
|
||||
var allClientExclusive = true;
|
||||
|
||||
foreach (var action in actions)
|
||||
{
|
||||
@@ -400,7 +399,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
private void OnDidEquip(EntityUid uid, ActionsComponent component, DidEquipEvent args)
|
||||
{
|
||||
var ev = new GetItemActionsEvent(args.SlotFlags);
|
||||
RaiseLocalEvent(args.Equipment, ev, false);
|
||||
RaiseLocalEvent(args.Equipment, ev);
|
||||
|
||||
if (ev.Actions.Count == 0)
|
||||
return;
|
||||
@@ -411,7 +410,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
private void OnHandEquipped(EntityUid uid, ActionsComponent component, DidEquipHandEvent args)
|
||||
{
|
||||
var ev = new GetItemActionsEvent();
|
||||
RaiseLocalEvent(args.Equipped, ev, false);
|
||||
RaiseLocalEvent(args.Equipped, ev);
|
||||
|
||||
if (ev.Actions.Count == 0)
|
||||
return;
|
||||
|
||||
@@ -107,4 +107,4 @@
|
||||
FlashRune: -1
|
||||
ExplosionRune: -1
|
||||
IgniteRune: -1
|
||||
StunRune: -1
|
||||
StunRune: -1
|
||||
|
||||
Reference in New Issue
Block a user