Action, Action Container, and Action Upgrade changes (#24005)
* Added TransferActionWithNewAttached and TransferAllActionsWithNewAttached and OnActionAdded event method to ActionContainerSystem. These are needed where the action needs to have a different attached entity for usage. Fixed a bug with not being able to upgrade actions between levels. Added a way to grant and remove a singular action. * adds an action container component to mind on action added to fix tests * Swaps trycomp for hascomp * Maybe this will fix the thests * Grants action container to performer as well * Wait that makes no sense, removing that * fixes mind action grant logic * Changes ent check back to netent check * Reverts unintended container changes
This commit is contained in:
@@ -51,7 +51,7 @@ internal sealed class UpgradeActionCommand : IConsoleCommand
|
||||
|
||||
if (args.Length == 1)
|
||||
{
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, actionUpgradeComponent))
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, out _, actionUpgradeComponent))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-cannot-level-up"));
|
||||
return;
|
||||
@@ -74,7 +74,7 @@ internal sealed class UpgradeActionCommand : IConsoleCommand
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, actionUpgradeComponent, level))
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, out _, actionUpgradeComponent, level))
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-cannot-level-up"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public sealed class ActionContainerSystem : EntitySystem
|
||||
SubscribeLocalEvent<ActionsContainerComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<ActionsContainerComponent, EntRemovedFromContainerMessage>(OnEntityRemoved);
|
||||
SubscribeLocalEvent<ActionsContainerComponent, EntInsertedIntoContainerMessage>(OnEntityInserted);
|
||||
SubscribeLocalEvent<ActionsContainerComponent, ActionAddedEvent>(OnActionAdded);
|
||||
SubscribeLocalEvent<ActionsContainerComponent, MindAddedMessage>(OnMindAdded);
|
||||
SubscribeLocalEvent<ActionsContainerComponent, MindRemovedMessage>(OnMindRemoved);
|
||||
}
|
||||
@@ -38,7 +39,6 @@ public sealed class ActionContainerSystem : EntitySystem
|
||||
{
|
||||
if(!_mind.TryGetMind(uid, out var mindId, out _))
|
||||
return;
|
||||
|
||||
if (!TryComp<ActionsContainerComponent>(mindId, out var mindActionContainerComp))
|
||||
return;
|
||||
|
||||
@@ -174,6 +174,61 @@ public sealed class ActionContainerSystem : EntitySystem
|
||||
DebugTools.AssertEqual(oldContainer.Container.Count, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers an actions from one container to another, while changing the attached entity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will actually remove and then re-grant the action.
|
||||
/// Useful where you need to transfer from one container to another but also change the attached entity (ie spellbook > mind > user)
|
||||
/// </remarks>
|
||||
public void TransferActionWithNewAttached(
|
||||
EntityUid actionId,
|
||||
EntityUid newContainer,
|
||||
EntityUid newAttached,
|
||||
BaseActionComponent? action = null,
|
||||
ActionsContainerComponent? container = null)
|
||||
{
|
||||
if (!_actions.ResolveActionData(actionId, ref action))
|
||||
return;
|
||||
|
||||
if (action.Container == newContainer)
|
||||
return;
|
||||
|
||||
var attached = newAttached;
|
||||
if (!AddAction(newContainer, actionId, action, container))
|
||||
return;
|
||||
|
||||
DebugTools.AssertEqual(action.Container, newContainer);
|
||||
_actions.AddActionDirect(newAttached, actionId, action: action);
|
||||
|
||||
DebugTools.AssertEqual(action.AttachedEntity, attached);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers all actions from one container to another, while changing the attached entity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will actually remove and then re-grant the action.
|
||||
/// Useful where you need to transfer from one container to another but also change the attached entity (ie spellbook > mind > user)
|
||||
/// </remarks>
|
||||
public void TransferAllActionsWithNewAttached(
|
||||
EntityUid from,
|
||||
EntityUid to,
|
||||
EntityUid newAttached,
|
||||
ActionsContainerComponent? oldContainer = null,
|
||||
ActionsContainerComponent? newContainer = null)
|
||||
{
|
||||
if (!Resolve(from, ref oldContainer) || !Resolve(to, ref newContainer))
|
||||
return;
|
||||
|
||||
foreach (var action in oldContainer.Container.ContainedEntities.ToArray())
|
||||
{
|
||||
TransferActionWithNewAttached(action, to, newAttached, container: newContainer);
|
||||
}
|
||||
|
||||
DebugTools.AssertEqual(oldContainer.Container.Count, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a pre-existing action to an action container. If the action is already in some container it will first remove it.
|
||||
/// </summary>
|
||||
@@ -281,6 +336,12 @@ public sealed class ActionContainerSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
data.Container = null;
|
||||
}
|
||||
|
||||
private void OnActionAdded(EntityUid uid, ActionsContainerComponent component, ActionAddedEvent args)
|
||||
{
|
||||
if (TryComp<MindComponent>(uid, out var mindComp) && mindComp.OwnedEntity != null && HasComp<ActionsContainerComponent>(mindComp.OwnedEntity.Value))
|
||||
_actions.GrantContainedAction(mindComp.OwnedEntity.Value, uid, args.Action);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,6 +11,7 @@ public sealed partial class ActionUpgradeComponent : Component
|
||||
/// <summary>
|
||||
/// Current Level of the action.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public int Level = 1;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,7 +21,7 @@ public sealed class ActionUpgradeSystem : EntitySystem
|
||||
|
||||
private void OnActionUpgradeEvent(EntityUid uid, ActionUpgradeComponent component, ActionUpgradeEvent args)
|
||||
{
|
||||
if (!CanLevelUp(args.NewLevel, component.EffectedLevels, out var newActionProto)
|
||||
if (!CanUpgrade(args.NewLevel, component.EffectedLevels, out var newActionProto)
|
||||
|| !_actions.TryGetActionData(uid, out var actionComp))
|
||||
return;
|
||||
|
||||
@@ -56,8 +56,9 @@ public sealed class ActionUpgradeSystem : EntitySystem
|
||||
_entityManager.DeleteEntity(uid);
|
||||
}
|
||||
|
||||
public bool TryUpgradeAction(EntityUid? actionId, ActionUpgradeComponent? actionUpgradeComponent = null, int newLevel = 0)
|
||||
public bool TryUpgradeAction(EntityUid? actionId, out EntityUid? upgradeActionId, ActionUpgradeComponent? actionUpgradeComponent = null, int newLevel = 0)
|
||||
{
|
||||
upgradeActionId = null;
|
||||
if (!TryGetActionUpgrade(actionId, out var actionUpgradeComp))
|
||||
return false;
|
||||
|
||||
@@ -68,21 +69,26 @@ public sealed class ActionUpgradeSystem : EntitySystem
|
||||
if (newLevel < 1)
|
||||
newLevel = actionUpgradeComponent.Level + 1;
|
||||
|
||||
if (!CanLevelUp(newLevel, actionUpgradeComponent.EffectedLevels, out _))
|
||||
if (!CanLevelUp(newLevel, actionUpgradeComponent.EffectedLevels))
|
||||
return false;
|
||||
|
||||
UpgradeAction(actionId, actionUpgradeComp);
|
||||
actionUpgradeComponent.Level = newLevel;
|
||||
|
||||
// If it can level up but can't upgrade, still return true and return current actionId as the upgradeId.
|
||||
if (!CanUpgrade(newLevel, actionUpgradeComponent.EffectedLevels, out var newActionProto))
|
||||
{
|
||||
upgradeActionId = actionId;
|
||||
DebugTools.AssertNotNull(upgradeActionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Add checks for branching upgrades
|
||||
private bool CanLevelUp(
|
||||
int newLevel,
|
||||
Dictionary<int, EntProtoId> levelDict,
|
||||
[NotNullWhen(true)]out EntProtoId? newLevelProto)
|
||||
{
|
||||
newLevelProto = null;
|
||||
upgradeActionId = UpgradeAction(actionId, actionUpgradeComp, newActionProto, newLevel);
|
||||
DebugTools.AssertNotNull(upgradeActionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CanLevelUp(int newLevel, Dictionary<int, EntProtoId> levelDict)
|
||||
{
|
||||
if (levelDict.Count < 1)
|
||||
return false;
|
||||
|
||||
@@ -91,25 +97,47 @@ public sealed class ActionUpgradeSystem : EntitySystem
|
||||
|
||||
foreach (var (level, proto) in levelDict)
|
||||
{
|
||||
if (newLevel != level || newLevel > finalLevel)
|
||||
if (newLevel > finalLevel)
|
||||
continue;
|
||||
|
||||
if ((newLevel <= finalLevel && newLevel != level) || newLevel == level)
|
||||
{
|
||||
canLevel = true;
|
||||
newLevelProto = proto;
|
||||
DebugTools.AssertNotNull(newLevelProto);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return canLevel;
|
||||
}
|
||||
|
||||
private bool CanUpgrade(int newLevel, Dictionary<int, EntProtoId> levelDict, [NotNullWhen(true)]out EntProtoId? newLevelProto)
|
||||
{
|
||||
var canUpgrade = false;
|
||||
newLevelProto = null;
|
||||
|
||||
var finalLevel = levelDict.Keys.ToList()[levelDict.Keys.Count - 1];
|
||||
|
||||
foreach (var (level, proto) in levelDict)
|
||||
{
|
||||
if (newLevel != level || newLevel > finalLevel)
|
||||
continue;
|
||||
|
||||
canUpgrade = true;
|
||||
newLevelProto = proto;
|
||||
DebugTools.AssertNotNull(newLevelProto);
|
||||
break;
|
||||
}
|
||||
|
||||
return canUpgrade;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a level by one
|
||||
/// </summary>
|
||||
public void UpgradeAction(EntityUid? actionId, ActionUpgradeComponent? actionUpgradeComponent = null, int newLevel = 0)
|
||||
public EntityUid? UpgradeAction(EntityUid? actionId, ActionUpgradeComponent? actionUpgradeComponent = null, EntProtoId? newActionProto = null, int newLevel = 0)
|
||||
{
|
||||
if (!TryGetActionUpgrade(actionId, out var actionUpgradeComp))
|
||||
return;
|
||||
return null;
|
||||
|
||||
actionUpgradeComponent ??= actionUpgradeComp;
|
||||
DebugTools.AssertNotNull(actionUpgradeComponent);
|
||||
@@ -118,7 +146,47 @@ public sealed class ActionUpgradeSystem : EntitySystem
|
||||
if (newLevel < 1)
|
||||
newLevel = actionUpgradeComponent.Level + 1;
|
||||
|
||||
RaiseActionUpgradeEvent(newLevel, actionId.Value);
|
||||
actionUpgradeComponent.Level = newLevel;
|
||||
// RaiseActionUpgradeEvent(newLevel, actionId.Value);
|
||||
|
||||
if (!CanUpgrade(newLevel, actionUpgradeComponent.EffectedLevels, out var newActionPrototype)
|
||||
|| !_actions.TryGetActionData(actionId, out var actionComp))
|
||||
return null;
|
||||
|
||||
newActionProto ??= newActionPrototype;
|
||||
DebugTools.AssertNotNull(newActionProto);
|
||||
|
||||
var originalContainer = actionComp.Container;
|
||||
var originalAttachedEntity = actionComp.AttachedEntity;
|
||||
|
||||
_actionContainer.RemoveAction(actionId.Value, actionComp);
|
||||
|
||||
EntityUid? upgradedActionId = null;
|
||||
if (originalContainer != null
|
||||
&& TryComp<ActionsContainerComponent>(originalContainer.Value, out var actionContainerComp))
|
||||
{
|
||||
upgradedActionId = _actionContainer.AddAction(originalContainer.Value, newActionProto, actionContainerComp);
|
||||
|
||||
if (originalAttachedEntity != null)
|
||||
_actions.GrantContainedActions(originalAttachedEntity.Value, originalContainer.Value);
|
||||
else
|
||||
_actions.GrantContainedActions(originalContainer.Value, originalContainer.Value);
|
||||
}
|
||||
else if (originalAttachedEntity != null)
|
||||
{
|
||||
upgradedActionId = _actionContainer.AddAction(originalAttachedEntity.Value, newActionProto);
|
||||
}
|
||||
|
||||
if (!TryComp<ActionUpgradeComponent>(upgradedActionId, out var upgradeComp))
|
||||
return null;
|
||||
|
||||
upgradeComp.Level = newLevel;
|
||||
|
||||
// TODO: Preserve ordering of actions
|
||||
|
||||
_entityManager.DeleteEntity(actionId);
|
||||
|
||||
return upgradedActionId.Value;
|
||||
}
|
||||
|
||||
private void RaiseActionUpgradeEvent(int level, EntityUid actionId)
|
||||
|
||||
@@ -691,6 +691,24 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grants the provided action from the container to the target entity. If the target entity has no action
|
||||
/// component, this will give them one.
|
||||
/// </summary>
|
||||
/// <param name="performer"></param>
|
||||
/// <param name="container"></param>
|
||||
/// <param name="actionId"></param>
|
||||
public void GrantContainedAction(Entity<ActionsComponent?> performer, Entity<ActionsContainerComponent?> container, EntityUid actionId)
|
||||
{
|
||||
if (!Resolve(container, ref container.Comp))
|
||||
return;
|
||||
|
||||
performer.Comp ??= EnsureComp<ActionsComponent>(performer);
|
||||
|
||||
if (TryGetActionData(actionId, out var action))
|
||||
AddActionDirect(performer, actionId, performer.Comp, action);
|
||||
}
|
||||
|
||||
public IEnumerable<(EntityUid Id, BaseActionComponent Comp)> GetActions(EntityUid holderId, ActionsComponent? actions = null)
|
||||
{
|
||||
if (!Resolve(holderId, ref actions, false))
|
||||
@@ -723,6 +741,18 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a single provided action provided by another entity.
|
||||
/// </summary>
|
||||
public void RemoveProvidedAction(EntityUid performer, EntityUid container, EntityUid actionId, ActionsComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(performer, ref comp, false) || !TryGetActionData(actionId, out var action))
|
||||
return;
|
||||
|
||||
if (action.Container == container)
|
||||
RemoveAction(performer, actionId, comp);
|
||||
}
|
||||
|
||||
public void RemoveAction(EntityUid? actionId)
|
||||
{
|
||||
if (actionId == null)
|
||||
|
||||
Reference in New Issue
Block a user