if (action.ClientExclusive)
{
- if (instantAction.Event != null)
- {
- instantAction.Event.Performer = user;
- instantAction.Event.Action = actionId;
- }
-
PerformAction(user, actions, actionId, instantAction, instantAction.Event, GameTiming.CurTime);
}
else
if (action.Event != null)
{
action.Event.Target = coords;
- action.Event.Performer = user;
- action.Event.Action = actionId;
}
_actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
if (action.Event != null)
{
action.Event.Target = entity;
- action.Event.Performer = user;
- action.Event.Action = actionId;
}
_actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
{
action.Event.Entity = entity;
action.Event.Coords = coords;
- action.Event.Performer = user;
- action.Event.Action = actionId;
}
_actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
return;
var (actId, act) = _random.Pick(options);
- if (act.Event != null)
- {
- act.Event.Performer = args.User;
- act.Event.Action = actId;
- }
-
_actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false);
args.Handled = true;
}
var (entActId, entAct) = _random.Pick(entOptions);
if (entAct.Event != null)
{
- entAct.Event.Performer = args.User;
- entAct.Event.Action = entActId;
entAct.Event.Target = args.Target.Value;
}
var (entActId, entAct) = _random.Pick(entWorldOptions);
if (entAct.Event != null)
{
- entAct.Event.Performer = args.User;
- entAct.Event.Action = entActId;
entAct.Event.Entity = args.Target;
entAct.Event.Coords = args.ClickLocation;
}
var (actId, act) = _random.Pick(options);
if (act.Event != null)
{
- act.Event.Performer = args.User;
- act.Event.Action = actId;
act.Event.Target = args.ClickLocation;
}
if (action.Event != null)
{
- action.Event.Performer = user;
- action.Event.Action = user.Comp.ActionEnt.Value;
action.Event.Coords = Transform(target).Coordinates;
}
/// <summary>
/// The action the event belongs to.
/// </summary>
- public EntityUid Action;
+ public Entity<BaseActionComponent> Action;
+
+ /// <summary>
+ /// Should we toggle the action entity?
+ /// </summary>
+ public bool Toggle;
}
--- /dev/null
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// Grants actions on MapInit and removes them on shutdown
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(ActionGrantSystem))]
+public sealed partial class ActionGrantComponent : Component
+{
+ [DataField(required: true), AutoNetworkedField, AlwaysPushInheritance]
+ public List<EntProtoId> Actions = new();
+
+ [DataField, AutoNetworkedField]
+ public List<EntityUid> ActionEntities = new();
+}
--- /dev/null
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// <see cref="ActionGrantComponent"/>
+/// </summary>
+public sealed class ActionGrantSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<ActionGrantComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<ActionGrantComponent, ComponentShutdown>(OnShutdown);
+ SubscribeLocalEvent<ItemActionGrantComponent, GetItemActionsEvent>(OnItemGet);
+ }
+
+ private void OnItemGet(Entity<ItemActionGrantComponent> ent, ref GetItemActionsEvent args)
+ {
+ if (!TryComp(ent.Owner, out ActionGrantComponent? grant))
+ return;
+
+ foreach (var action in grant.ActionEntities)
+ {
+ args.AddAction(action);
+ }
+ }
+
+ private void OnMapInit(Entity<ActionGrantComponent> ent, ref MapInitEvent args)
+ {
+ foreach (var action in ent.Comp.Actions)
+ {
+ EntityUid? actionEnt = null;
+ _actions.AddAction(ent.Owner, ref actionEnt, action);
+
+ if (actionEnt != null)
+ ent.Comp.ActionEntities.Add(actionEnt.Value);
+ }
+ }
+
+ private void OnShutdown(Entity<ActionGrantComponent> ent, ref ComponentShutdown args)
+ {
+ foreach (var actionEnt in ent.Comp.ActionEntities)
+ {
+ _actions.RemoveAction(ent.Owner, actionEnt);
+ }
+ }
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions.Events;
+
+/// <summary>
+/// Adds / removes the component upon action.
+/// </summary>
+[Virtual]
+public partial class ActionComponentChangeEvent : InstantActionEvent
+{
+ [DataField(required: true)]
+ public ComponentRegistry Components = new();
+}
+
+/// <summary>
+/// Similar to <see cref="ActionComponentChangeEvent"/> except raises an event to attempt to relay it.
+/// </summary>
+public sealed partial class RelayedActionComponentChangeEvent : ActionComponentChangeEvent
+{
+
+}
+
+[ByRefEvent]
+public record struct AttemptRelayActionComponentChangeEvent
+{
+ public EntityUid? Target;
+}
--- /dev/null
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// Works in tandem with <see cref="ActionGrantComponent"/> by granting those actions to the equipper entity.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(ActionGrantSystem))]
+public sealed partial class ItemActionGrantComponent : Component
+{
+ [DataField(required: true), AutoNetworkedField, AlwaysPushInheritance]
+ public List<EntProtoId> Actions = new();
+}
using Content.Shared.Rejuvenate;
using Content.Shared.Whitelist;
using Robust.Shared.Audio.Systems;
-using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Timing;
SubscribeLocalEvent<WorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
SubscribeLocalEvent<EntityWorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
+ SubscribeLocalEvent<ActionsComponent, ActionComponentChangeEvent>(OnActionCompChange);
+ SubscribeLocalEvent<ActionsComponent, RelayedActionComponentChangeEvent>(OnRelayActionCompChange);
SubscribeLocalEvent<ActionsComponent, DidEquipEvent>(OnDidEquip);
SubscribeLocalEvent<ActionsComponent, DidEquipHandEvent>(OnHandEquipped);
SubscribeLocalEvent<ActionsComponent, DidUnequipEvent>(OnDidUnequip);
break;
}
- if (performEvent != null)
- {
- performEvent.Performer = user;
- performEvent.Action = actionEnt;
- }
-
// All checks passed. Perform the action!
PerformAction(user, component, actionEnt, action, performEvent, curTime);
}
// This here is required because of client-side prediction (RaisePredictiveEvent results in event re-use).
actionEvent.Handled = false;
var target = performer;
+ actionEvent.Performer = performer;
+ actionEvent.Action = (actionId, action);
if (!action.RaiseOnUser && action.Container != null && !HasComp<MindComponent>(action.Container))
target = action.Container.Value;
return; // no interaction occurred.
// play sound, reduce charges, start cooldown, and mark as dirty (if required).
+ if (actionEvent?.Toggle == true)
+ {
+ action.Toggled = !action.Toggled;
+ }
- _audio.PlayPredicted(action.Sound, performer,predicted ? performer : null);
+ _audio.PlayPredicted(action.Sound, performer, predicted ? performer : null);
- var dirty = toggledBefore == action.Toggled;
+ var dirty = toggledBefore != action.Toggled;
if (action.Charges != null)
{
action.Cooldown = (curTime, curTime + action.UseDelay.Value);
}
- Dirty(actionId, action);
-
- if (dirty && component != null)
- Dirty(performer, component);
+ if (dirty)
+ {
+ Dirty(actionId, action);
+ UpdateAction(actionId, action);
+ }
var ev = new ActionPerformedEvent(performer);
RaiseLocalEvent(actionId, ref ev);
#endregion
+ private void OnRelayActionCompChange(Entity<ActionsComponent> ent, ref RelayedActionComponentChangeEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ var ev = new AttemptRelayActionComponentChangeEvent();
+ RaiseLocalEvent(ent.Owner, ref ev);
+ var target = ev.Target ?? ent.Owner;
+
+ args.Handled = true;
+ args.Toggle = true;
+
+ if (!args.Action.Comp.Toggled)
+ {
+ EntityManager.AddComponents(target, args.Components);
+ }
+ else
+ {
+ EntityManager.RemoveComponents(target, args.Components);
+ }
+ }
+
+ private void OnActionCompChange(Entity<ActionsComponent> ent, ref ActionComponentChangeEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ args.Handled = true;
+ args.Toggle = true;
+ var target = ent.Owner;
+
+ if (!args.Action.Comp.Toggled)
+ {
+ EntityManager.AddComponents(target, args.Components);
+ }
+ else
+ {
+ EntityManager.RemoveComponents(target, args.Components);
+ }
+ }
+
#region EquipHandlers
private void OnDidEquip(EntityUid uid, ActionsComponent component, DidEquipEvent args)
{