SubscribeLocalEvent<ActionsContainerComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ActionsContainerComponent, EntRemovedFromContainerMessage>(OnEntityRemoved);
SubscribeLocalEvent<ActionsContainerComponent, EntInsertedIntoContainerMessage>(OnEntityInserted);
+ SubscribeLocalEvent<ActionsContainerComponent, ActionAddedEvent>(OnActionAdded);
SubscribeLocalEvent<ActionsContainerComponent, MindAddedMessage>(OnMindAdded);
SubscribeLocalEvent<ActionsContainerComponent, MindRemovedMessage>(OnMindRemoved);
}
{
if(!_mind.TryGetMind(uid, out var mindId, out _))
return;
-
if (!TryComp<ActionsContainerComponent>(mindId, out var mindActionContainerComp))
return;
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>
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>
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;
_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;
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;
+ }
+
+ upgradeActionId = UpgradeAction(actionId, actionUpgradeComp, newActionProto, newLevel);
+ 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)
+ private bool CanLevelUp(int newLevel, Dictionary<int, EntProtoId> levelDict)
{
- newLevelProto = null;
-
if (levelDict.Count < 1)
return false;
var canLevel = false;
var finalLevel = levelDict.Keys.ToList()[levelDict.Keys.Count - 1];
+ foreach (var (level, proto) in levelDict)
+ {
+ if (newLevel > finalLevel)
+ continue;
+
+ if ((newLevel <= finalLevel && newLevel != level) || newLevel == level)
+ {
+ canLevel = true;
+ 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;
- canLevel = true;
+ canUpgrade = true;
newLevelProto = proto;
DebugTools.AssertNotNull(newLevelProto);
break;
}
- return canLevel;
+ 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);
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)
}
}
+ /// <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))
}
}
+ /// <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)