Spell pre-examine (#1661)

* examine spells

* fux

* fix
This commit is contained in:
Red
2025-08-11 23:46:28 +03:00
committed by GitHub
parent aa5fe8d4d7
commit e6f5ed2450
9 changed files with 129 additions and 86 deletions

View File

@@ -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, FormattedMessage? charges = null)
public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? requires = null)
{
_gameTiming = IoCManager.Resolve<IGameTiming>();
@@ -52,17 +52,6 @@ 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,

View File

@@ -3,12 +3,13 @@ using Content.Client.Actions;
using Content.Client.Actions.UI;
using Content.Client.Cooldown;
using Content.Client.Stylesheets;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;
using Content.Shared.Examine;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
@@ -23,6 +24,7 @@ namespace Content.Client.UserInterface.Systems.Actions.Controls;
public sealed class ActionButton : Control, IEntityControl
{
private IEntityManager _entities;
private IPlayerManager _player;
private SpriteSystem? _spriteSys;
private ActionUIController? _controller;
private SharedChargesSystem _sharedChargesSys;
@@ -67,6 +69,7 @@ public sealed class ActionButton : Control, IEntityControl
// TODO why is this constructor so slooooow. The rest of the code is fine
_entities = entities;
_player = IoCManager.Resolve<IPlayerManager>();
_spriteSys = spriteSys;
_sharedChargesSys = _entities.System<SharedChargesSystem>();
_controller = controller;
@@ -197,23 +200,21 @@ public sealed class ActionButton : Control, IEntityControl
return null;
var name = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityName));
var decr = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
FormattedMessage? chargesText = null;
var desc = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
// TODO: Don't touch this use an event make callers able to add their own shit for actions or I kill you.
if (_entities.TryGetComponent(Action, out LimitedChargesComponent? actionCharges))
{
var charges = _sharedChargesSys.GetCurrentCharges((Action.Value, actionCharges, null));
chargesText = FormattedMessage.FromMarkupPermissive(Loc.GetString($"Charges: {charges.ToString()}/{actionCharges.MaxCharges}"));
if (_player.LocalEntity is null)
return null;
if (_entities.TryGetComponent(Action, out AutoRechargeComponent? autoRecharge))
{
var chargeTimeRemaining = _sharedChargesSys.GetNextRechargeTime((Action.Value, actionCharges, autoRecharge));
chargesText.AddText(Loc.GetString($"{Environment.NewLine}Time Til Recharge: {chargeTimeRemaining}"));
}
}
//CP14
desc.AddText("\n");
//CP14 end
return new ActionAlertTooltip(name, decr, charges: chargesText);
var ev = new ExaminedEvent(desc, Action.Value, _player.LocalEntity.Value, true, !desc.IsEmpty);
_entities.EventBus.RaiseLocalEvent(Action.Value.Owner, ev);
var newDesc = ev.GetTotalMessage();
return new ActionAlertTooltip(name, newDesc);
}
protected override void ControlFocusExited()

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared._CP14.Religion.Components;
@@ -6,6 +7,7 @@ using Content.Shared.CombatMode.Pacification;
using Content.Shared.Damage.Components;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
using Content.Shared.Speech.Muting;
@@ -152,7 +154,15 @@ public abstract partial class CP14SharedMagicSystem
if (!ent.Comp.AllowedStates.Contains(mobStateComp.CurrentState))
{
args.PushReason(Loc.GetString(ent.Comp.Popup));
var states = string.Join(", ",
ent.Comp.AllowedStates.Select(state => state switch
{
MobState.Alive => Loc.GetString("cp14-magic-spell-target-mob-state-live"),
MobState.Dead => Loc.GetString("cp14-magic-spell-target-mob-state-dead"),
MobState.Critical => Loc.GetString("cp14-magic-spell-target-mob-state-critical")
}));
args.PushReason(Loc.GetString("cp14-magic-spell-target-mob-state", ("state", states)));
args.Cancel();
}
}

View File

@@ -0,0 +1,74 @@
using System.Linq;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared.Examine;
using Content.Shared.Mobs;
namespace Content.Shared._CP14.MagicSpell;
public abstract partial class CP14SharedMagicSystem
{
private void InitializeExamine()
{
SubscribeLocalEvent<CP14MagicEffectComponent, ExaminedEvent>(OnManaEffectExamined);
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, ExaminedEvent>(OnManacostExamined);
SubscribeLocalEvent<CP14MagicEffectStaminaCostComponent, ExaminedEvent>(OnStaminaCostExamined);
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, ExaminedEvent>(OnVerbalExamined);
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, ExaminedEvent>(OnSomaticExamined);
SubscribeLocalEvent<CP14MagicEffectMaterialAspectComponent, ExaminedEvent>(OnMaterialExamined);
SubscribeLocalEvent<CP14MagicEffectRequiredMusicToolComponent, ExaminedEvent>(OnMusicExamined);
SubscribeLocalEvent<CP14MagicEffectTargetMobStatusRequiredComponent, ExaminedEvent>(OnMobStateExamined);
}
private void OnManaEffectExamined(Entity<CP14MagicEffectComponent> ent, ref ExaminedEvent args)
{
if (_proto.TryIndex(ent.Comp.MagicType, out var indexedMagic))
{
args.PushMarkup($"{Loc.GetString("cp14-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]", 10);
}
}
private void OnManacostExamined(Entity<CP14MagicEffectManaCostComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup($"{Loc.GetString("cp14-magic-manacost")}: [color=#5da9e8]{ent.Comp.ManaCost}[/color]", priority: 9);
}
private void OnStaminaCostExamined(Entity<CP14MagicEffectStaminaCostComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup($"{Loc.GetString("cp14-magic-staminacost")}: [color=#3fba54]{ent.Comp.Stamina}[/color]", priority: 9);
}
private void OnVerbalExamined(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("cp14-magic-verbal-aspect"), 8);
}
private void OnSomaticExamined(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("cp14-magic-somatic-aspect") + " " + ent.Comp.FreeHandRequired, 8);
}
private void OnMaterialExamined(Entity<CP14MagicEffectMaterialAspectComponent> ent, ref ExaminedEvent args)
{
if (ent.Comp.Requirement is not null)
args.PushMarkup(Loc.GetString("cp14-magic-material-aspect") + " " + ent.Comp.Requirement.GetRequirementTitle(_proto));
}
private void OnMusicExamined(Entity<CP14MagicEffectRequiredMusicToolComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("cp14-magic-music-aspect"));
}
private void OnMobStateExamined(Entity<CP14MagicEffectTargetMobStatusRequiredComponent> ent, ref ExaminedEvent args)
{
var states = string.Join(", ",
ent.Comp.AllowedStates.Select(state => state switch
{
MobState.Alive => Loc.GetString("cp14-magic-spell-target-mob-state-live"),
MobState.Dead => Loc.GetString("cp14-magic-spell-target-mob-state-dead"),
MobState.Critical => Loc.GetString("cp14-magic-spell-target-mob-state-critical")
}));
args.PushMarkup(Loc.GetString("cp14-magic-spell-target-mob-state", ("state", states)));
}
}

View File

@@ -49,11 +49,11 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
InitializeInstantActions();
InitializeChecks();
InitializeSlowdown();
InitializeExamine();
_magicContainerQuery = GetEntityQuery<CP14MagicEnergyContainerComponent>();
_magicEffectQuery = GetEntityQuery<CP14MagicEffectComponent>();
SubscribeLocalEvent<CP14MagicEffectComponent, MapInitEvent>(OnMagicEffectInit);
SubscribeLocalEvent<CP14MagicEffectComponent, ComponentShutdown>(OnMagicEffectShutdown);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14StartCastMagicEffectEvent>(OnStartCast);
@@ -102,54 +102,6 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
UpdateToggleableActions();
}
/// <summary>
/// Auto generation description for spell action
/// </summary>
private void OnMagicEffectInit(Entity<CP14MagicEffectComponent> ent, ref MapInitEvent args)
{
var meta = MetaData(ent);
var sb = new StringBuilder();
sb.Append(meta.EntityDescription);
if (TryComp<CP14MagicEffectManaCostComponent>(ent, out var manaCost) && manaCost.ManaCost > 0)
{
sb.Append($"\n\n{Loc.GetString("cp14-magic-manacost")}: [color=#5da9e8]{manaCost.ManaCost}[/color]");
}
if (TryComp<CP14MagicEffectStaminaCostComponent>(ent, out var staminaCost) && staminaCost.Stamina > 0)
{
sb.Append($"\n\n{Loc.GetString("cp14-magic-staminacost")}: [color=#3fba54]{staminaCost.Stamina}[/color]");
}
if (_proto.TryIndex(ent.Comp.MagicType, out var indexedMagic))
{
sb.Append($"\n{Loc.GetString("cp14-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]");
}
if (TryComp<CP14MagicEffectVerbalAspectComponent>(ent, out var verbal))
{
sb.Append("\n" + Loc.GetString("cp14-magic-verbal-aspect"));
}
if (TryComp<CP14MagicEffectSomaticAspectComponent>(ent, out var somatic))
{
sb.Append("\n" + Loc.GetString("cp14-magic-somatic-aspect") + " " + somatic.FreeHandRequired);
}
if (TryComp<CP14MagicEffectMaterialAspectComponent>(ent, out var material) && material.Requirement is not null)
{
sb.Append("\n" + Loc.GetString("cp14-magic-material-aspect") + " " + material.Requirement.GetRequirementTitle(_proto));
}
if (TryComp<CP14MagicEffectRequiredMusicToolComponent>(ent, out var music))
{
sb.Append("\n" + Loc.GetString("cp14-magic-music-aspect"));
}
_meta.SetEntityDescription(ent, sb.ToString());
}
private void OnMagicEffectShutdown(Entity<CP14MagicEffectComponent> ent, ref ComponentShutdown args)
{
if (_doAfter.IsRunning(ent.Comp.ActiveDoAfter))

View File

@@ -10,8 +10,5 @@ namespace Content.Shared._CP14.MagicSpell.Components;
public sealed partial class CP14MagicEffectTargetMobStatusRequiredComponent : Component
{
[DataField]
public LocId Popup = "cp14-magic-spell-target-alive";
[DataField]
public List<MobState> AllowedStates = new() { MobState.Alive };
public HashSet<MobState> AllowedStates = new() { MobState.Alive };
}

View File

@@ -1,7 +1,9 @@
using Content.Shared._CP14.Skill.Prototypes;
using Content.Shared.Actions;
using Content.Shared.Examine;
using Content.Shared.Mind;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Skill.Effects;
@@ -53,6 +55,16 @@ public sealed partial class AddAction : CP14SkillEffect
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
{
return !protoManager.TryIndex(Action, out var indexedAction) ? string.Empty : indexedAction.Description;
var dummyAction = entMagager.Spawn(Action);
var message = new FormattedMessage();
if (!entMagager.TryGetComponent<MetaDataComponent>(dummyAction, out var meta))
return null;
message.AddText(meta.EntityDescription + "\n");
var ev = new ExaminedEvent(message, dummyAction, dummyAction, true, true);
entMagager.EventBus.RaiseLocalEvent(dummyAction, ev);
entMagager.DeleteEntity(dummyAction);
return ev.GetTotalMessage().ToMarkup();
}
}

View File

@@ -23,6 +23,10 @@ cp14-magic-staminacost = Stamina cost
cp14-magic-spell-pacified = It could hurt someone!
cp14-magic-spell-target-not-mob = The target must be a living thing!
cp14-magic-spell-target-dead = Can't be used on the dead!
cp14-magic-spell-target-alive = Can't be used on the living!
cp14-magic-spell-target-mob-state = Can only be used on {$state} targets!
cp14-magic-spell-target-mob-state-dead = dead
cp14-magic-spell-target-mob-state-live = living
cp14-magic-spell-target-mob-state-critical = dying
cp14-magic-spell-target-god-follower = Your target should be your follower!

View File

@@ -23,6 +23,10 @@ cp14-magic-staminacost = Затраты энергии
cp14-magic-spell-pacified = Это может навредить кому либо!
cp14-magic-spell-target-not-mob = Цель должна быть живым существом!
cp14-magic-spell-target-dead = Нельзя использовать на мертвых!
cp14-magic-spell-target-alive = Нельзя использовать на живых!
cp14-magic-spell-target-mob-state = Можно использовать только на {$state} цели!
cp14-magic-spell-target-mob-state-dead = мертвые
cp14-magic-spell-target-mob-state-live = живые
cp14-magic-spell-target-mob-state-critical = умирающие
cp14-magic-spell-target-god-follower = Цель должна быть вашим последователем!