Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wizard Item Recall Spell #34411

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Content.Client/Actions/ActionsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ private void BaseHandleState<T>(EntityUid uid, BaseActionComponent component, Ba
component.Priority = state.Priority;
component.AttachedEntity = EnsureEntity<T>(state.AttachedEntity, uid);
component.RaiseOnUser = state.RaiseOnUser;
component.RaiseOnAction = state.RaiseOnAction;
component.AutoPopulate = state.AutoPopulate;
component.Temporary = state.Temporary;
component.ItemIconStyle = state.ItemIconStyle;
Expand Down
11 changes: 11 additions & 0 deletions Content.Client/ItemRecall/ItemRecallSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Content.Shared.ItemRecall;

namespace Content.Client.ItemRecall;

/// <summary>
/// System for handling the ItemRecall ability for wizards.
/// </summary>
public sealed partial class ItemRecallSystem : SharedItemRecallSystem
{

}
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved
30 changes: 30 additions & 0 deletions Content.Server/ItemRecall/ItemRecallSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.ItemRecall;
using Robust.Server.GameStates;

namespace Content.Server.ItemRecall;

/// <summary>
/// System for handling the ItemRecall ability for wizards.
/// </summary>
public sealed partial class ItemRecallSystem : SharedItemRecallSystem
{
[Dependency] private readonly PvsOverrideSystem _pvs = default!;

protected override void AddToPVSOverride(EntityUid uid, EntityUid user)
{
if (!_mind.TryGetMind(user, out var _, out var mind))
return;

if (mind.Session != null)
_pvs.AddSessionOverride(uid, mind.Session);
}

protected override void RemoveFromPVSOverride(EntityUid uid, EntityUid user)
{
if (!_mind.TryGetMind(user, out var _, out var mind))
return;

if (mind.Session != null)
_pvs.RemoveSessionOverride(uid, mind.Session);
}
}
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 9 additions & 0 deletions Content.Shared/Actions/BaseActionComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ public EntityUid? EntityIcon
[DataField]
public bool RaiseOnUser;

/// <summary>
/// If true, this will cause the the action event to always be raised directed at the action itself instead of the action's container/provider.
/// Takes priority over RaiseOnUser.
/// </summary>
[DataField]
public bool RaiseOnAction;
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Whether or not to automatically add this action to the action bar when it becomes available.
/// </summary>
Expand Down Expand Up @@ -212,6 +219,7 @@ public abstract class BaseActionComponentState : ComponentState
public int Priority;
public NetEntity? AttachedEntity;
public bool RaiseOnUser;
public bool RaiseOnAction;
public bool AutoPopulate;
public bool Temporary;
public ItemActionIconStyle ItemIconStyle;
Expand All @@ -223,6 +231,7 @@ protected BaseActionComponentState(BaseActionComponent component, IEntityManager
EntityIcon = entManager.GetNetEntity(component.EntIcon);
AttachedEntity = entManager.GetNetEntity(component.AttachedEntity);
RaiseOnUser = component.RaiseOnUser;
RaiseOnAction = component.RaiseOnAction;
Icon = component.Icon;
IconOn = component.IconOn;
IconColor = component.IconColor;
Expand Down
3 changes: 3 additions & 0 deletions Content.Shared/Actions/SharedActionsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,9 @@ public void PerformAction(EntityUid performer, ActionsComponent? component, Enti
if (!action.RaiseOnUser && action.Container != null && !HasComp<MindComponent>(action.Container))
target = action.Container.Value;

if (action.RaiseOnAction)
target = actionId;

RaiseLocalEvent(target, (object) actionEvent, broadcast: true);
handled = actionEvent.Handled;
}
Expand Down
25 changes: 25 additions & 0 deletions Content.Shared/ItemRecall/ItemRecallComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Robust.Shared.GameStates;

namespace Content.Shared.ItemRecall;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedItemRecallSystem))]
public sealed partial class ItemRecallComponent : Component
{
[DataField]
public LocId? WhileMarkedName = "item-recall-marked-name";

[DataField]
public LocId? WhileMarkedDescription = "item-recall-marked-description";

[DataField]
public string? InitialName;

[DataField]
public string? InitialDescription;

/// <summary>
/// The entity currently marked to be recalled by this action.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? MarkedEntity;
}
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved
15 changes: 15 additions & 0 deletions Content.Shared/ItemRecall/ItemRecallEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Content.Shared.Actions;

namespace Content.Shared.ItemRecall;

/// <summary>
/// Raised when using the ItemRecall action.
/// </summary>
[ByRefEvent]
public sealed partial class OnItemRecallActionEvent : InstantActionEvent;

/// <summary>
/// Raised on the item to recall it back to its user.
/// </summary>
[ByRefEvent]
public record struct RecallItemEvent;
18 changes: 18 additions & 0 deletions Content.Shared/ItemRecall/RecallMarkerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Robust.Shared.GameStates;
using Robust.Shared.Utility;

namespace Content.Shared.ItemRecall;


/// <summary>
/// Component used as a marker for an item marked by the ItemRecall ability.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedItemRecallSystem))]
public sealed partial class RecallMarkerComponent : Component
{
/// <summary>
/// The action that marked this item.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? MarkedByAction;
}
186 changes: 186 additions & 0 deletions Content.Shared/ItemRecall/SharedItemRecallSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
using Content.Shared.Actions;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Mind;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Robust.Shared.Network;
using Robust.Shared.Player;

namespace Content.Shared.ItemRecall;

/// <summary>
/// System for handling the ItemRecall ability for wizards.
/// </summary>
public abstract partial class SharedItemRecallSystem : EntitySystem
{
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedPopupSystem _popups = default!;
[Dependency] private readonly SharedProjectileSystem _proj = default!;
[Dependency] protected readonly SharedMindSystem _mind = default!;
[Dependency] private readonly INetManager _net = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ItemRecallComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<ItemRecallComponent, OnItemRecallActionEvent>(OnItemRecallActionUse);
SubscribeLocalEvent<RecallMarkerComponent, RecallItemEvent>(OnItemRecall);

SubscribeLocalEvent<RecallMarkerComponent, ComponentShutdown>(OnRecallMarkerShutdown);
}

private void OnMapInit(Entity<ItemRecallComponent> ent, ref MapInitEvent args)
{
ent.Comp.InitialName = Name(ent);
ent.Comp.InitialDescription = Description(ent);
}

private void OnItemRecallActionUse(Entity<ItemRecallComponent> ent, ref OnItemRecallActionEvent args)
{
if (ent.Comp.MarkedEntity == null)
{
if (!TryComp<HandsComponent>(args.Performer, out var hands))
return;

var markItem = _hands.GetActiveItem((args.Performer, hands));

if (markItem == null)
{
_popups.PopupClient(Loc.GetString("item-recall-item-mark-empty"), args.Performer, args.Performer);
return;
}

if (HasComp<RecallMarkerComponent>(markItem))
{
_popups.PopupClient(Loc.GetString("item-recall-item-already-marked", ("item", markItem)), args.Performer, args.Performer);
return;
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved
}

_popups.PopupClient(Loc.GetString("item-recall-item-marked", ("item", markItem.Value)), args.Performer, args.Performer);
TryMarkItem(ent, markItem.Value);
return;
}

var ev = new RecallItemEvent();
RaiseLocalEvent(ent.Comp.MarkedEntity.Value, ref ev);
args.Handled = true;
}

private void OnItemRecall(Entity<RecallMarkerComponent> ent, ref RecallItemEvent args)
{
RecallItem(ent);
}

private void RecallItem(Entity<RecallMarkerComponent> ent)
{
if (!TryComp<InstantActionComponent>(ent.Comp.MarkedByAction, out var instantAction))
return;

var actionOwner = instantAction.AttachedEntity;

if (actionOwner == null)
return;

if (TryComp<EmbeddableProjectileComponent>(ent, out var projectile))
_proj.UnEmbed(ent, projectile, actionOwner.Value);

_popups.PopupPredicted(Loc.GetString("item-recall-item-summon", ("item", ent)), actionOwner.Value, actionOwner.Value);

_hands.TryForcePickupAnyHand(actionOwner.Value, ent);
}

private void OnRecallMarkerShutdown(Entity<RecallMarkerComponent> ent, ref ComponentShutdown args)
{
TryUnmarkItem(ent);
}

private void TryMarkItem(Entity<ItemRecallComponent> ent, EntityUid item)
{
if (!TryComp<InstantActionComponent>(ent, out var instantAction))
return;

var actionOwner = instantAction.AttachedEntity;

if (actionOwner == null)
return;

AddToPVSOverride(item, actionOwner.Value);

var marker = AddComp<RecallMarkerComponent>(item);
ent.Comp.MarkedEntity = item;
Dirty(ent);

marker.MarkedByAction = ent.Owner;

UpdateActionAppearance(ent);
Dirty(item, marker);
}

private void TryUnmarkItem(EntityUid item)
{
if (!TryComp<RecallMarkerComponent>(item, out var marker))
return;

if (!TryComp<InstantActionComponent>(marker.MarkedByAction, out var instantAction))
return;

if (TryComp<ItemRecallComponent>(marker.MarkedByAction, out var action))
{
// For some reason client thinks the station grid owns the action on client and this doesn't work. It doesn't work in PopupEntity(mispredicts) and PopupPredicted either(doesnt show).
// I don't have the heart to move this code to server because of this small thing.
// This line will only do something once that is fixed.
ScarKy0 marked this conversation as resolved.
Show resolved Hide resolved
if (instantAction.AttachedEntity != null)
{
_popups.PopupClient(Loc.GetString("item-recall-item-unmark", ("item", item)), instantAction.AttachedEntity.Value, instantAction.AttachedEntity.Value, PopupType.MediumCaution);
RemoveFromPVSOverride(item, instantAction.AttachedEntity.Value);
}

action.MarkedEntity = null;
UpdateActionAppearance((marker.MarkedByAction.Value, action));
Dirty(marker.MarkedByAction.Value, action);
}

RemCompDeferred<RecallMarkerComponent>(item);
}

private void UpdateActionAppearance(Entity<ItemRecallComponent> action)
{
if (!TryComp<InstantActionComponent>(action, out var instantAction))
return;

if (action.Comp.MarkedEntity == null)
{
if (action.Comp.InitialName != null)
_metaData.SetEntityName(action, action.Comp.InitialName);
if (action.Comp.InitialDescription != null)
_metaData.SetEntityDescription(action, action.Comp.InitialDescription);
_actions.SetEntityIcon(action, null, instantAction);
}
else
{
if (action.Comp.WhileMarkedName != null)
_metaData.SetEntityName(action, Loc.GetString(action.Comp.WhileMarkedName,
("item", action.Comp.MarkedEntity.Value)));

if (action.Comp.WhileMarkedDescription != null)
_metaData.SetEntityDescription(action, Loc.GetString(action.Comp.WhileMarkedDescription,
("item", action.Comp.MarkedEntity.Value)));

_actions.SetEntityIcon(action, action.Comp.MarkedEntity, instantAction);
}
}

protected virtual void AddToPVSOverride(EntityUid uid, EntityUid user)
{

}

protected virtual void RemoveFromPVSOverride(EntityUid uid, EntityUid user)
{

}
}
Loading
Loading