Action Upgrade System (#22277)
* Adds uses before delay so actions can be used multiple times before cooldown * adds methods to get remaining charges, to set uses before delay, and to set use delay * adds method to change action name * moves set usedelay * action upgrade ECS * adds method to reset remaining uses * adds upgrade events * refactors action upgrade event and adds logic to parse it * fix serialization issue * adds level up draft method * adds action commands and a command to upgrade an action * more warning lines to help * Gets action to upgrade properly * Removes unneeded fields from the action upgrade component and now properly raises the level of the new action * Cleans up dead code and comments * Fixes punctuation in actions-commands and adds a TryUpgradeAction method. * removes TODO comment * robust fix * removes RT * readds RT * update RT to 190 * removes change name method * removes remaining uses & related fields and adds that functionality to charges * Adds Charges to action tooltips that require it
This commit is contained in:
@@ -87,6 +87,8 @@ namespace Content.Client.Actions
|
||||
component.Cooldown = state.Cooldown;
|
||||
component.UseDelay = state.UseDelay;
|
||||
component.Charges = state.Charges;
|
||||
component.MaxCharges = state.MaxCharges;
|
||||
component.RenewCharges = state.RenewCharges;
|
||||
component.Container = EnsureEntity<T>(state.Container, uid);
|
||||
component.EntityIcon = EnsureEntity<T>(state.EntityIcon, uid);
|
||||
component.CheckCanInteract = state.CheckCanInteract;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Content.Client.Actions.UI
|
||||
/// </summary>
|
||||
public (TimeSpan Start, TimeSpan End)? Cooldown { get; set; }
|
||||
|
||||
public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? requires = null)
|
||||
public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? requires = null, FormattedMessage? charges = null)
|
||||
{
|
||||
_gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
|
||||
@@ -52,6 +52,17 @@ namespace Content.Client.Actions.UI
|
||||
vbox.AddChild(description);
|
||||
}
|
||||
|
||||
if (charges != null && !string.IsNullOrWhiteSpace(charges.ToString()))
|
||||
{
|
||||
var chargesLabel = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipActionCharges }
|
||||
};
|
||||
chargesLabel.SetMessage(charges);
|
||||
vbox.AddChild(chargesLabel);
|
||||
}
|
||||
|
||||
vbox.AddChild(_cooldownLabel = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace Content.Client.Stylesheets
|
||||
public const string StyleClassTooltipActionDescription = "tooltipActionDesc";
|
||||
public const string StyleClassTooltipActionCooldown = "tooltipActionCooldown";
|
||||
public const string StyleClassTooltipActionRequirements = "tooltipActionCooldown";
|
||||
public const string StyleClassTooltipActionCharges = "tooltipActionCharges";
|
||||
public const string StyleClassHotbarSlotNumber = "hotbarSlotNumber";
|
||||
public const string StyleClassActionSearchBox = "actionSearchBox";
|
||||
public const string StyleClassActionMenuItemRevoked = "actionMenuItemRevoked";
|
||||
@@ -940,6 +941,10 @@ namespace Content.Client.Stylesheets
|
||||
{
|
||||
new StyleProperty("font", notoSans15)
|
||||
}),
|
||||
new StyleRule(new SelectorElement(typeof(RichTextLabel), new[] {StyleClassTooltipActionCharges}, null, null), new[]
|
||||
{
|
||||
new StyleProperty("font", notoSans15)
|
||||
}),
|
||||
|
||||
// small number for the entity counter in the entity menu
|
||||
new StyleRule(new SelectorElement(typeof(Label), new[] {ContextMenuElement.StyleClassEntityMenuIconLabel}, null, null), new[]
|
||||
|
||||
@@ -171,7 +171,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
|
||||
// Is the action currently valid?
|
||||
if (!action.Enabled
|
||||
|| action.Charges is 0
|
||||
|| action is { Charges: 0, RenewCharges: false }
|
||||
|| 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
|
||||
|
||||
@@ -191,6 +191,12 @@ public sealed class ActionButton : Control, IEntityControl
|
||||
var name = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityName));
|
||||
var decr = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
|
||||
|
||||
if (_action is { Charges: not null })
|
||||
{
|
||||
var charges = FormattedMessage.FromMarkupPermissive(Loc.GetString($"Charges: {_action.Charges.Value.ToString()}/{_action.MaxCharges.ToString()}"));
|
||||
return new ActionAlertTooltip(name, decr, charges: charges);
|
||||
}
|
||||
|
||||
return new ActionAlertTooltip(name, decr);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
<BoxContainer Orientation="Vertical" RectClipContent="True">
|
||||
<RichTextLabel MaxWidth="350" StyleClasses="StyleClassTooltipActionTitle"/>
|
||||
<RichTextLabel MaxWidth="350" StyleClasses="StyleClassTooltipActionDescription"/>
|
||||
<RichTextLabel MaxWidth="350" StyleClasses="StyleClassTooltipActionCharges"/>
|
||||
</BoxContainer>
|
||||
</controls:ActionTooltip>
|
||||
|
||||
81
Content.Server/Commands/ActionCommands.cs
Normal file
81
Content.Server/Commands/ActionCommands.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
internal sealed class UpgradeActionCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
|
||||
public string Command => "upgradeaction";
|
||||
public string Description => Loc.GetString("upgradeaction-command-description");
|
||||
public string Help => Loc.GetString("upgradeaction-command-help");
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-need-one-argument"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length > 2)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-max-two-arguments"));
|
||||
return;
|
||||
}
|
||||
|
||||
var actionUpgrade = _entMan.EntitySysManager.GetEntitySystem<ActionUpgradeSystem>();
|
||||
var id = args[0];
|
||||
|
||||
if (!EntityUid.TryParse(id, out var uid))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-incorrect-entityuid-format"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_entMan.EntityExists(uid))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-entity-does-not-exist"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_entMan.TryGetComponent<ActionUpgradeComponent>(uid, out var actionUpgradeComponent))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-entity-is-not-action"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length == 1)
|
||||
{
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, actionUpgradeComponent))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-cannot-level-up"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.Length == 2)
|
||||
{
|
||||
var levelArg = args[1];
|
||||
|
||||
if (!int.TryParse(levelArg, out var level))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-second-argument-not-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (level <= 0)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-less-than-required-level"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actionUpgrade.TryUpgradeAction(uid, actionUpgradeComponent, level))
|
||||
shell.WriteLine(Loc.GetString("upgradeaction-command-cannot-level-up"));
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Content.Shared/Actions/ActionUpgradeComponent.cs
Normal file
24
Content.Shared/Actions/ActionUpgradeComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Actions;
|
||||
|
||||
// For actions that can use basic upgrades
|
||||
// Not all actions should be upgradable
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(ActionUpgradeSystem))]
|
||||
public sealed partial class ActionUpgradeComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Current Level of the action.
|
||||
/// </summary>
|
||||
public int Level = 1;
|
||||
|
||||
/// <summary>
|
||||
/// What level(s) effect this action?
|
||||
/// You can skip levels, so you can have this entity change at level 2 but then won't change again until level 5.
|
||||
/// </summary>
|
||||
[DataField("effectedLevels"), ViewVariables]
|
||||
public Dictionary<int, EntProtoId> EffectedLevels = new();
|
||||
|
||||
// TODO: Branching level upgrades
|
||||
}
|
||||
149
Content.Shared/Actions/ActionUpgradeSystem.cs
Normal file
149
Content.Shared/Actions/ActionUpgradeSystem.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Actions;
|
||||
|
||||
public sealed class ActionUpgradeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ActionUpgradeComponent, ActionUpgradeEvent>(OnActionUpgradeEvent);
|
||||
}
|
||||
|
||||
private void OnActionUpgradeEvent(EntityUid uid, ActionUpgradeComponent component, ActionUpgradeEvent args)
|
||||
{
|
||||
if (!CanLevelUp(args.NewLevel, component.EffectedLevels, out var newActionProto)
|
||||
|| !_actions.TryGetActionData(uid, out var actionComp))
|
||||
return;
|
||||
|
||||
var originalContainer = actionComp.Container;
|
||||
var originalAttachedEntity = actionComp.AttachedEntity;
|
||||
|
||||
_actionContainer.RemoveAction(uid, 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;
|
||||
|
||||
upgradeComp.Level = args.NewLevel;
|
||||
|
||||
// TODO: Preserve ordering of actions
|
||||
|
||||
_entityManager.DeleteEntity(uid);
|
||||
}
|
||||
|
||||
public bool TryUpgradeAction(EntityUid? actionId, ActionUpgradeComponent? actionUpgradeComponent = null, int newLevel = 0)
|
||||
{
|
||||
if (!TryGetActionUpgrade(actionId, out var actionUpgradeComp))
|
||||
return false;
|
||||
|
||||
actionUpgradeComponent ??= actionUpgradeComp;
|
||||
DebugTools.AssertNotNull(actionUpgradeComponent);
|
||||
DebugTools.AssertNotNull(actionId);
|
||||
|
||||
if (newLevel < 1)
|
||||
newLevel = actionUpgradeComponent.Level + 1;
|
||||
|
||||
if (!CanLevelUp(newLevel, actionUpgradeComponent.EffectedLevels, out _))
|
||||
return false;
|
||||
|
||||
UpgradeAction(actionId, actionUpgradeComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Add checks for branching upgrades
|
||||
private bool CanLevelUp(
|
||||
int newLevel,
|
||||
Dictionary<int, EntProtoId> levelDict,
|
||||
[NotNullWhen(true)]out EntProtoId? newLevelProto)
|
||||
{
|
||||
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 != level || newLevel > finalLevel)
|
||||
continue;
|
||||
|
||||
canLevel = true;
|
||||
newLevelProto = proto;
|
||||
DebugTools.AssertNotNull(newLevelProto);
|
||||
break;
|
||||
}
|
||||
|
||||
return canLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a level by one
|
||||
/// </summary>
|
||||
public void UpgradeAction(EntityUid? actionId, ActionUpgradeComponent? actionUpgradeComponent = null, int newLevel = 0)
|
||||
{
|
||||
if (!TryGetActionUpgrade(actionId, out var actionUpgradeComp))
|
||||
return;
|
||||
|
||||
actionUpgradeComponent ??= actionUpgradeComp;
|
||||
DebugTools.AssertNotNull(actionUpgradeComponent);
|
||||
DebugTools.AssertNotNull(actionId);
|
||||
|
||||
if (newLevel < 1)
|
||||
newLevel = actionUpgradeComponent.Level + 1;
|
||||
|
||||
RaiseActionUpgradeEvent(newLevel, actionId.Value);
|
||||
}
|
||||
|
||||
private void RaiseActionUpgradeEvent(int level, EntityUid actionId)
|
||||
{
|
||||
var ev = new ActionUpgradeEvent(level, actionId);
|
||||
RaiseLocalEvent(actionId, ev);
|
||||
}
|
||||
|
||||
public bool TryGetActionUpgrade(
|
||||
[NotNullWhen(true)] EntityUid? uid,
|
||||
[NotNullWhen(true)] out ActionUpgradeComponent? result,
|
||||
bool logError = true)
|
||||
{
|
||||
result = null;
|
||||
if (!Exists(uid))
|
||||
return false;
|
||||
|
||||
if (!TryComp<ActionUpgradeComponent>(uid, out var actionUpgradeComponent))
|
||||
{
|
||||
Log.Error($"Failed to get action upgrade from action entity: {ToPrettyString(uid.Value)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
result = actionUpgradeComponent;
|
||||
DebugTools.AssertOwner(uid, result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -66,9 +66,21 @@ public abstract partial class BaseActionComponent : Component
|
||||
/// <summary>
|
||||
/// Convenience tool for actions with limited number of charges. Automatically decremented on use, and the
|
||||
/// action is disabled when it reaches zero. Does NOT automatically remove the action from the action bar.
|
||||
/// However, charges will regenerate if <see cref="RenewCharges"/> is enabled and the action will not disable
|
||||
/// when charges reach zero.
|
||||
/// </summary>
|
||||
[DataField("charges")] public int? Charges;
|
||||
|
||||
/// <summary>
|
||||
/// The max charges this action has, set automatically from <see cref="Charges"/>
|
||||
/// </summary>
|
||||
public int MaxCharges;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, charges will regenerate after a <see cref="Cooldown"/> is complete
|
||||
/// </summary>
|
||||
[DataField("renewCharges")]public bool RenewCharges;
|
||||
|
||||
/// <summary>
|
||||
/// The entity that contains this action. If the action is innate, this may be the user themselves.
|
||||
/// This should almost always be non-null.
|
||||
@@ -159,6 +171,8 @@ public abstract class BaseActionComponentState : ComponentState
|
||||
public (TimeSpan Start, TimeSpan End)? Cooldown;
|
||||
public TimeSpan? UseDelay;
|
||||
public int? Charges;
|
||||
public int MaxCharges;
|
||||
public bool RenewCharges;
|
||||
public NetEntity? Container;
|
||||
public NetEntity? EntityIcon;
|
||||
public bool CheckCanInteract;
|
||||
@@ -186,6 +200,8 @@ public abstract class BaseActionComponentState : ComponentState
|
||||
Cooldown = component.Cooldown;
|
||||
UseDelay = component.UseDelay;
|
||||
Charges = component.Charges;
|
||||
MaxCharges = component.MaxCharges;
|
||||
RenewCharges = component.RenewCharges;
|
||||
CheckCanInteract = component.CheckCanInteract;
|
||||
ClientExclusive = component.ClientExclusive;
|
||||
Priority = component.Priority;
|
||||
|
||||
13
Content.Shared/Actions/Events/ActionUpgradeEvent.cs
Normal file
13
Content.Shared/Actions/Events/ActionUpgradeEvent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Content.Shared.Actions.Events;
|
||||
|
||||
public sealed class ActionUpgradeEvent : EntityEventArgs
|
||||
{
|
||||
public int NewLevel;
|
||||
public EntityUid? ActionId;
|
||||
|
||||
public ActionUpgradeEvent(int newLevel, EntityUid? actionId)
|
||||
{
|
||||
NewLevel = newLevel;
|
||||
ActionId = actionId;
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,16 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<InstantActionComponent, MapInitEvent>(OnInit);
|
||||
SubscribeLocalEvent<EntityTargetActionComponent, MapInitEvent>(OnInit);
|
||||
SubscribeLocalEvent<WorldTargetActionComponent, MapInitEvent>(OnInit);
|
||||
|
||||
SubscribeLocalEvent<ActionsComponent, DidEquipEvent>(OnDidEquip);
|
||||
SubscribeLocalEvent<ActionsComponent, DidEquipHandEvent>(OnHandEquipped);
|
||||
SubscribeLocalEvent<ActionsComponent, DidUnequipEvent>(OnDidUnequip);
|
||||
@@ -56,6 +61,12 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
SubscribeAllEvent<RequestPerformActionEvent>(OnActionRequest);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, BaseActionComponent component, MapInitEvent args)
|
||||
{
|
||||
if (component.Charges != null)
|
||||
component.MaxCharges = component.Charges.Value;
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, ActionsComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var act in component.Actions)
|
||||
@@ -165,6 +176,31 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
public void SetUseDelay(EntityUid? actionId, TimeSpan? delay)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action) || action.UseDelay == delay)
|
||||
return;
|
||||
|
||||
action.UseDelay = delay;
|
||||
UpdateAction(actionId, action);
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
public void ReduceUseDelay(EntityUid? actionId, TimeSpan? lowerDelay)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action))
|
||||
return;
|
||||
|
||||
if (action.UseDelay != null && lowerDelay != null)
|
||||
action.UseDelay = action.UseDelay - lowerDelay;
|
||||
|
||||
if (action.UseDelay < TimeSpan.Zero)
|
||||
action.UseDelay = null;
|
||||
|
||||
UpdateAction(actionId, action);
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
private void OnRejuventate(EntityUid uid, ActionsComponent component, RejuvenateEvent args)
|
||||
{
|
||||
foreach (var act in component.Actions)
|
||||
@@ -218,6 +254,51 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
public int? GetCharges(EntityUid? actionId)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action))
|
||||
return null;
|
||||
|
||||
return action.Charges;
|
||||
}
|
||||
|
||||
public void AddCharges(EntityUid? actionId, int addCharges)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action) || action.Charges == null || addCharges < 1)
|
||||
return;
|
||||
|
||||
action.Charges += addCharges;
|
||||
UpdateAction(actionId, action);
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
public void RemoveCharges(EntityUid? actionId, int? removeCharges)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action) || action.Charges == null)
|
||||
return;
|
||||
|
||||
if (removeCharges == null)
|
||||
action.Charges = removeCharges;
|
||||
else
|
||||
action.Charges -= removeCharges;
|
||||
|
||||
if (action.Charges is < 0)
|
||||
action.Charges = null;
|
||||
|
||||
UpdateAction(actionId, action);
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
public void ResetCharges(EntityUid? actionId)
|
||||
{
|
||||
if (!TryGetActionData(actionId, out var action))
|
||||
return;
|
||||
|
||||
action.Charges = action.MaxCharges;
|
||||
UpdateAction(actionId, action);
|
||||
Dirty(actionId.Value, action);
|
||||
}
|
||||
|
||||
private void OnActionsGetState(EntityUid uid, ActionsComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new ActionsComponentState(GetNetEntitySet(component.Actions));
|
||||
@@ -261,9 +342,14 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var curTime = GameTiming.CurTime;
|
||||
// TODO: Check for charge recovery timer
|
||||
if (action.Cooldown.HasValue && action.Cooldown.Value.End > curTime)
|
||||
return;
|
||||
|
||||
// TODO: Replace with individual charge recovery when we have the visuals to aid it
|
||||
if (action is { Charges: < 1, RenewCharges: true })
|
||||
ResetCharges(actionEnt);
|
||||
|
||||
BaseActionEvent? performEvent = null;
|
||||
|
||||
// Validate request by checking action blockers and the like:
|
||||
@@ -438,12 +524,12 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
{
|
||||
dirty = true;
|
||||
action.Charges--;
|
||||
if (action.Charges == 0)
|
||||
if (action is { Charges: 0, RenewCharges: false })
|
||||
action.Enabled = false;
|
||||
}
|
||||
|
||||
action.Cooldown = null;
|
||||
if (action.UseDelay != null)
|
||||
if (action is { UseDelay: not null, Charges: null or < 1 })
|
||||
{
|
||||
dirty = true;
|
||||
action.Cooldown = (curTime, curTime + action.UseDelay.Value);
|
||||
|
||||
12
Resources/Locale/en-US/actions/actions/actions-commands.ftl
Normal file
12
Resources/Locale/en-US/actions/actions/actions-commands.ftl
Normal file
@@ -0,0 +1,12 @@
|
||||
## Actions Commands loc
|
||||
|
||||
## Upgradeaction command loc
|
||||
upgradeaction-command-need-one-argument = upgradeaction needs at least one argument, the action entity uid. The second optional argument is a specified level.
|
||||
upgradeaction-command-max-two-arguments = upgradeaction has a maximum of two arguments, the action entity uid and the (optional) level to set.
|
||||
upgradeaction-command-second-argument-not-number = upgradeaction's second argument can only be a number.
|
||||
upgradeaction-command-less-than-required-level = upgradeaction cannot accept a level of 0 or lower.
|
||||
upgradeaction-command-incorrect-entityuid-format = You must use a valid entityuid format for upgradeaction.
|
||||
upgradeaction-command-entity-does-not-exist = This entity does not exist, a valid entity is required for upgradeaction.
|
||||
upgradeaction-command-entity-is-not-action = This entity doesn't have the action upgrade component, so this action cannot be leveled.
|
||||
upgradeaction-command-cannot-level-up = The action cannot be leveled up.
|
||||
upgradeaction-command-description = Upgrades an action by one level, or to the specified level, if applicable.
|
||||
@@ -5,7 +5,34 @@
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: WorldTargetAction
|
||||
useDelay: 30
|
||||
useDelay: 15
|
||||
itemIconStyle: BigAction
|
||||
checkCanAccess: false
|
||||
range: 60
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/fireball.ogg
|
||||
icon:
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: fireball
|
||||
event: !type:ProjectileSpellEvent
|
||||
prototype: ProjectileFireball
|
||||
posData: !type:TargetCasterPos
|
||||
speech: action-speech-spell-fireball
|
||||
- type: ActionUpgrade
|
||||
effectedLevels:
|
||||
2: ActionFireballII
|
||||
|
||||
- type: entity
|
||||
id: ActionFireballII
|
||||
parent: ActionFireball
|
||||
name: Fireball II
|
||||
description: Fire three explosive fireball towards the clicked location.
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: WorldTargetAction
|
||||
useDelay: 5
|
||||
charges: 3
|
||||
renewCharges: true
|
||||
itemIconStyle: BigAction
|
||||
checkCanAccess: false
|
||||
range: 60
|
||||
|
||||
Reference in New Issue
Block a user