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

Update 10/27/2024 #92

Merged
merged 16 commits into from
Oct 28, 2024
Merged
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
66 changes: 50 additions & 16 deletions Content.Client/RadialSelector/RadialSelectorMenuBUI.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System.Numerics;
using System.Linq;
using System.Numerics;
using Content.Client.UserInterface.Controls;
using Content.Shared.Construction.Prototypes;
using Content.Shared.RadialSelector;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
Expand All @@ -19,8 +21,9 @@ public sealed class RadialSelectorMenuBUI : BoundUserInterface
{
[Dependency] private readonly IClyde _displayManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IResourceCache _resources = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IEntityManager _entManager = default!;

private readonly SpriteSystem _spriteSystem;

Expand All @@ -30,6 +33,7 @@ public sealed class RadialSelectorMenuBUI : BoundUserInterface
private readonly HashSet<RadialContainer> _cachedContainers = new();

private bool _openCentered;
private readonly Vector2 ItemSize = Vector2.One * 64;

public RadialSelectorMenuBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
Expand Down Expand Up @@ -95,10 +99,7 @@ private void CreateMenu(List<RadialSelectorEntry> entries, string parentCategory
else if (entry.Prototype != null)
{
var name = GetName(entry.Prototype);
var icon = GetIcon(entry);
if (icon is null)
return;

var icon = GetTextures(entry);
var button = CreateButton(name, icon);
button.OnButtonUp += _ =>
{
Expand All @@ -115,37 +116,48 @@ private string GetName(string proto)
{
if (_protoManager.TryIndex(proto, out var prototype))
return prototype.Name;

if (_protoManager.TryIndex(proto, out ConstructionPrototype? constructionPrototype))
return constructionPrototype.Name;

return proto;
}

private Texture? GetIcon(RadialSelectorEntry entry)
private List<Texture> GetTextures(RadialSelectorEntry entry)
{
var result = new List<Texture>();
if (entry.Icon is not null)
{
result.Add(_spriteSystem.Frame0(entry.Icon));
return result;
}

if (_protoManager.TryIndex(entry.Prototype!, out var prototype))
return _spriteSystem.Frame0(prototype);
{
result.AddRange(SpriteComponent.GetPrototypeTextures(prototype, _resources).Select(o => o.Default));
return result;
}

if (_protoManager.TryIndex(entry.Prototype!, out ConstructionPrototype? constructionProto))
return _spriteSystem.Frame0(constructionProto.Icon);

if (entry.Icon is not null)
return _spriteSystem.Frame0(entry.Icon);
{
result.Add(_spriteSystem.Frame0(constructionProto.Icon));
return result;
}

// No icons provided and no icons found in prototypes. There's nothing we can do.
return null;
return result;
}

private RadialMenuTextureButton CreateButton(string name, Texture icon)
{
var itemSize = new Vector2(64f, 64f);
var button = new RadialMenuTextureButton
{
ToolTip = Loc.GetString(name),
StyleClasses = { "RadialMenuButton" },
SetSize = itemSize
SetSize = ItemSize
};

var iconScale = itemSize / icon.Size;
var iconScale = ItemSize / icon.Size;
var texture = new TextureRect
{
VerticalAlignment = Control.VAlignment.Center,
Expand All @@ -158,6 +170,28 @@ private RadialMenuTextureButton CreateButton(string name, Texture icon)
return button;
}

private RadialMenuTextureButton CreateButton(string name, List<Texture> icons)
{
var button = new RadialMenuTextureButton
{
ToolTip = Loc.GetString(name),
StyleClasses = { "RadialMenuButton" },
SetSize = ItemSize
};

var iconScale = ItemSize / icons[0].Size;
var texture = new LayeredTextureRect
{
VerticalAlignment = Control.VAlignment.Center,
HorizontalAlignment = Control.HAlignment.Center,
Textures = icons,
TextureScale = iconScale
};

button.AddChild(texture);
return button;
}

private void ClearExistingContainers()
{
foreach (var container in _cachedContainers)
Expand Down
19 changes: 18 additions & 1 deletion Content.Server/Abilities/Psionics/PsionicAbilitiesSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using System.Linq;
using Robust.Server.Player;
using Content.Server.Chat.Managers;
using Content.Server.Psionics.Glimmer;

namespace Content.Server.Abilities.Psionics
{
Expand All @@ -29,6 +28,7 @@ public sealed class PsionicAbilitiesSystem : EntitySystem
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly PsionicFamiliarSystem _psionicFamiliar = default!;

private ProtoId<WeightedRandomPrototype> _pool = "RandomPsionicPowerPool";
private const string GenericInitializationMessage = "generic-power-initialization-feedback";
Expand Down Expand Up @@ -59,6 +59,7 @@ private void OnPsionicShutdown(EntityUid uid, PsionicComponent component, Compon
|| HasComp<MindbrokenComponent>(uid))
return;

KillFamiliars(component);
RemoveAllPsionicPowers(uid);
}

Expand Down Expand Up @@ -215,6 +216,7 @@ public void RemoveAllPsionicPowers(EntityUid uid, bool mindbreak = false)

_popups.PopupEntity(Loc.GetString(psionic.MindbreakingFeedback, ("entity", MetaData(uid).EntityName)), uid, uid, PopupType.MediumCaution);

KillFamiliars(psionic);
RemComp<PsionicComponent>(uid);
RemComp<InnatePsionicPowersComponent>(uid);

Expand Down Expand Up @@ -368,5 +370,20 @@ private void RemovePsionicStatSources(EntityUid uid, PsionicPowerPrototype proto

RefreshPsionicModifiers(uid, psionic);
}

private void KillFamiliars(PsionicComponent component)
{
if (component.Familiars.Count <= 0)
return;

foreach (var familiar in component.Familiars)
{
if (!TryComp<PsionicFamiliarComponent>(familiar, out var familiarComponent)
|| !familiarComponent.DespawnOnMasterDeath)
continue;

_psionicFamiliar.DespawnFamiliar(familiar, familiarComponent);
}
}
}
}
140 changes: 140 additions & 0 deletions Content.Server/Abilities/Psionics/PsionicFamiliarSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using Content.Server.NPC;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Popups;
using Content.Shared.Abilities.Psionics;
using Content.Shared.Actions.Events;
using Content.Shared.Interaction.Events;
using Content.Shared.Mobs;
using Robust.Shared.Map;
using System.Numerics;

namespace Content.Server.Abilities.Psionics;

public sealed partial class PsionicFamiliarSystem : EntitySystem
{
[Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!;
[Dependency] private readonly NpcFactionSystem _factions = default!;
[Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly HTNSystem _htn = default!;
[Dependency] private readonly PopupSystem _popup = default!;

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

SubscribeLocalEvent<PsionicComponent, SummonPsionicFamiliarActionEvent>(OnSummon);
SubscribeLocalEvent<PsionicFamiliarComponent, ComponentShutdown>(OnFamiliarShutdown);
SubscribeLocalEvent<PsionicFamiliarComponent, AttackAttemptEvent>(OnFamiliarAttack);
SubscribeLocalEvent<PsionicFamiliarComponent, MobStateChangedEvent>(OnFamiliarDeath);
}

private void OnSummon(EntityUid uid, PsionicComponent psionicComponent, SummonPsionicFamiliarActionEvent args)
{
if (psionicComponent.Familiars.Count >= psionicComponent.FamiliarLimit
|| !_psionics.OnAttemptPowerUse(args.Performer, args.PowerName, args.ManaCost, args.CheckInsulation)
|| args.Handled || args.FamiliarProto is null)
return;

args.Handled = true;
var familiar = Spawn(args.FamiliarProto, Transform(uid).Coordinates);
EnsureComp<PsionicFamiliarComponent>(familiar, out var familiarComponent);
familiarComponent.Master = uid;
psionicComponent.Familiars.Add(familiar);
Dirty(familiar, familiarComponent);
Dirty(uid, psionicComponent);

InheritFactions(uid, familiar, familiarComponent);
HandleBlackboards(uid, familiar, args);
DoGlimmerEffects(uid, psionicComponent, args);
}

private void InheritFactions(EntityUid uid, EntityUid familiar, PsionicFamiliarComponent familiarComponent)
{
if (!familiarComponent.InheritMasterFactions
|| !TryComp<NpcFactionMemberComponent>(uid, out var masterFactions)
|| masterFactions.Factions.Count <= 0)
return;

EnsureComp<NpcFactionMemberComponent>(familiar, out var familiarFactions);
foreach (var faction in masterFactions.Factions)
{
if (familiarFactions.Factions.Contains(faction))
continue;

_factions.AddFaction(familiar, faction, true);
}
}

private void HandleBlackboards(EntityUid master, EntityUid familiar, SummonPsionicFamiliarActionEvent args)
{
if (!args.FollowMaster
|| !TryComp<HTNComponent>(familiar, out var htnComponent))
return;

_npc.SetBlackboard(familiar, NPCBlackboard.FollowTarget, new EntityCoordinates(master, Vector2.Zero), htnComponent);
_htn.Replan(htnComponent);
}

private void DoGlimmerEffects(EntityUid uid, PsionicComponent component, SummonPsionicFamiliarActionEvent args)
{
if (!args.DoGlimmerEffects
|| args.MinGlimmer == 0 && args.MaxGlimmer == 0)
return;

var minGlimmer = (int) Math.Round(MathF.MinMagnitude(args.MinGlimmer, args.MaxGlimmer)
* component.CurrentAmplification - component.CurrentDampening);
var maxGlimmer = (int) Math.Round(MathF.MaxMagnitude(args.MinGlimmer, args.MaxGlimmer)
* component.CurrentAmplification - component.CurrentDampening);

_psionics.LogPowerUsed(uid, args.PowerName, minGlimmer, maxGlimmer);
}

private void OnFamiliarShutdown(EntityUid uid, PsionicFamiliarComponent component, ComponentShutdown args)
{
if (!Exists(component.Master)
|| !TryComp<PsionicComponent>(component.Master, out var psionicComponent)
|| !psionicComponent.Familiars.Contains(uid))
return;

psionicComponent.Familiars.Remove(uid);
}

private void OnFamiliarAttack(EntityUid uid, PsionicFamiliarComponent component, AttackAttemptEvent args)
{
if (component.CanAttackMaster || args.Target is null
|| args.Target != component.Master)
return;

args.Cancel();
if (!Loc.TryGetString(component.AttackMasterText, out var attackFailMessage))
return;

_popup.PopupEntity(attackFailMessage, uid, uid, component.AttackPopupType);
}

private void OnFamiliarDeath(EntityUid uid, PsionicFamiliarComponent component, MobStateChangedEvent args)
{
if (!component.DespawnOnFamiliarDeath
|| args.NewMobState != MobState.Dead)
return;

DespawnFamiliar(uid, component);
}

public void DespawnFamiliar(EntityUid uid)
{
if (!TryComp<PsionicFamiliarComponent>(uid, out var familiarComponent))
return;

DespawnFamiliar(uid, familiarComponent);
}

public void DespawnFamiliar(EntityUid uid, PsionicFamiliarComponent component)
{
var popupText = Loc.GetString(component.DespawnText, ("entity", MetaData(uid).EntityName));
_popup.PopupEntity(popupText, uid, component.DespawnPopopType);
QueueDel(uid);
}
}
44 changes: 44 additions & 0 deletions Content.Server/Alert/Click/CheckHealth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Content.Server.Chat.Managers;
using Content.Shared.Alert;
using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.HealthExaminable;
using JetBrains.Annotations;
using Robust.Server.Player;
using Robust.Shared.Player;

namespace Content.Server.Alert.Click;

[UsedImplicitly]
[DataDefinition]
public sealed partial class CheckHealth : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var chatManager = IoCManager.Resolve<IChatManager>();
var entityManager = IoCManager.Resolve<IEntityManager>();
var playerManager = IoCManager.Resolve<IPlayerManager>();

var healthExaminableSystem = entityManager.System<HealthExaminableSystem>();

if (!entityManager.TryGetComponent(player, out HealthExaminableComponent? healthExaminable) ||
!entityManager.TryGetComponent(player, out DamageableComponent? damageable) ||
!playerManager.TryGetSessionByEntity(player, out var session))
return;

var baseMsg = Loc.GetString("health-alert-start");
SendMessage(chatManager, baseMsg, session);
var markup = healthExaminableSystem.GetMarkup(player, (player, healthExaminable), damageable).ToMarkup();
SendMessage(chatManager, markup, session);
}

private static void SendMessage(IChatManager chatManager, string msg, ICommonSession session)
{
chatManager.ChatMessageToOne(ChatChannel.Emotes,
msg,
msg,
EntityUid.Invalid,
false,
session.Channel);
}
}
6 changes: 6 additions & 0 deletions Content.Server/NPC/Components/NPCRetaliationComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ public sealed partial class NPCRetaliationComponent : Component
/// todo: this needs to support timeoffsetserializer at some point
[DataField("attackMemories")]
public Dictionary<EntityUid, TimeSpan> AttackMemories = new();

/// <summary>
/// Whether this NPC will retaliate against a "Friendly" NPC.
/// </summary>
[DataField]
public bool RetaliateFriendlies;
}
1 change: 0 additions & 1 deletion Content.Server/NPC/Components/NpcFactionMemberComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Content.Server.NPC.Components
{
[RegisterComponent]
[Access(typeof(NpcFactionSystem))]
public sealed partial class NpcFactionMemberComponent : Component
{
/// <summary>
Expand Down
Loading
Loading