Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/upstream/master' into upst…
Browse files Browse the repository at this point in the history
…ream-sync

# Conflicts:
#	Content.Shared/Preferences/Loadouts/RoleLoadout.cs
#	Resources/ServerInfo/Guidebook/Antagonist/MinorAntagonists.xml
#	Resources/ServerInfo/Guidebook/Antagonist/Nuclear Operatives.xml
#	Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml
#	Resources/ServerInfo/Guidebook/Antagonist/SpaceNinja.xml
#	Resources/ServerInfo/Guidebook/Antagonist/Traitors.xml
  • Loading branch information
Morb0 committed May 28, 2024
2 parents 6a16e2d + 0bca934 commit 4bf8b9e
Show file tree
Hide file tree
Showing 90 changed files with 2,296 additions and 7,295 deletions.
5 changes: 0 additions & 5 deletions Content.Client/Interaction/DragDropHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ public DragDropHelper(OnBeginDrag onBeginDrag, OnContinueDrag onContinueDrag, On
_cfg.OnValueChanged(CCVars.DragDropDeadZone, SetDeadZone, true);
}

~DragDropHelper()
{
_cfg.UnsubValueChanged(CCVars.DragDropDeadZone, SetDeadZone);
}

/// <summary>
/// Tell the helper that the mouse button was pressed down on
/// a target, thus a drag has the possibility to begin for this target.
Expand Down
5 changes: 3 additions & 2 deletions Content.Client/Lobby/UI/ObserveWarningWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
<BoxContainer Orientation="Vertical">
<Label Text="{Loc 'observe-warning-1'}"/>
<Label Text="{Loc 'observe-warning-2'}"/>
<BoxContainer Orientation="Horizontal" >
<BoxContainer Orientation="Horizontal">
<Button Name="NevermindButton" Text="{Loc 'observe-nevermind'}" SizeFlagsStretchRatio="1"/>
<Control HorizontalExpand="True" SizeFlagsStretchRatio="2" />
<cc:CommandButton Command="observe" Name="ObserveButton" StyleClasses="Caution" Text="{Loc 'observe-confirm'}" SizeFlagsStretchRatio="1"/>
<cc:CommandButton Command="observe" Name="ObserveButton" StyleClasses="Caution" Text="{Loc 'observe-confirm'}" SizeFlagsStretchRatio="1"/>
<cc:CommandButton Command="observe admin" Name="ObserveAsAdminButton" Text="{Loc 'observe-as-admin'}" SizeFlagsStretchRatio="1" Visible="False"/>
</BoxContainer>
</BoxContainer>
</DefaultWindow>
13 changes: 13 additions & 0 deletions Content.Client/Lobby/UI/ObserveWarningWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Content.Shared.Administration.Managers;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;

Expand All @@ -9,11 +11,22 @@ namespace Content.Client.Lobby.UI;
[UsedImplicitly]
public sealed partial class ObserveWarningWindow : DefaultWindow
{
[Dependency] private readonly ISharedAdminManager _adminManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;

public ObserveWarningWindow()
{
Title = Loc.GetString("observe-warning-window-title");
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var player = _playerManager.LocalSession;

if (player != null && _adminManager.IsAdmin(player))
{
ObserveButton.Text = Loc.GetString("observe-as-player");
ObserveAsAdminButton.Visible = true;
ObserveAsAdminButton.OnPressed += _ => { this.Close(); };
}

ObserveButton.OnPressed += _ => { this.Close(); };
NevermindButton.OnPressed += _ => { this.Close(); };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,4 @@ public IEnumerable<ActionButton> GetButtons()
yield return button;
}
}

~ActionButtonContainer()
{
UserInterfaceManager.GetUIController<ActionUIController>().RemoveActionContainer();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,4 @@ public ItemSlotButtonContainer()
{
_inventoryController = UserInterfaceManager.GetUIController<InventoryUIController>();
}

~ItemSlotButtonContainer()
{
_inventoryController.RemoveSlotGroup(SlotGroup);
}
}
25 changes: 11 additions & 14 deletions Content.Server/Anomaly/AnomalySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
using Robust.Shared.Physics.Events;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager;
using System.Linq;

namespace Content.Server.Anomaly;

Expand Down Expand Up @@ -69,20 +67,21 @@ private void OnMapInit(Entity<AnomalyComponent> anomaly, ref MapInitEvent args)
ChangeAnomalyStability(anomaly, Random.NextFloat(anomaly.Comp.InitialStabilityRange.Item1 , anomaly.Comp.InitialStabilityRange.Item2), anomaly.Comp);
ChangeAnomalySeverity(anomaly, Random.NextFloat(anomaly.Comp.InitialSeverityRange.Item1, anomaly.Comp.InitialSeverityRange.Item2), anomaly.Comp);

ShuffleParticlesEffect(anomaly.Comp);
ShuffleParticlesEffect(anomaly);
anomaly.Comp.Continuity = _random.NextFloat(anomaly.Comp.MinContituty, anomaly.Comp.MaxContituty);
SetBehavior(anomaly, GetRandomBehavior());
}

public void ShuffleParticlesEffect(AnomalyComponent anomaly)
public void ShuffleParticlesEffect(Entity<AnomalyComponent> anomaly)
{
var particles = new List<AnomalousParticleType>
{ AnomalousParticleType.Delta, AnomalousParticleType.Epsilon, AnomalousParticleType.Zeta, AnomalousParticleType.Sigma };

anomaly.SeverityParticleType = Random.PickAndTake(particles);
anomaly.DestabilizingParticleType = Random.PickAndTake(particles);
anomaly.WeakeningParticleType = Random.PickAndTake(particles);
anomaly.TransformationParticleType = Random.PickAndTake(particles);
anomaly.Comp.SeverityParticleType = Random.PickAndTake(particles);
anomaly.Comp.DestabilizingParticleType = Random.PickAndTake(particles);
anomaly.Comp.WeakeningParticleType = Random.PickAndTake(particles);
anomaly.Comp.TransformationParticleType = Random.PickAndTake(particles);
Dirty(anomaly);
}

private void OnShutdown(Entity<AnomalyComponent> anomaly, ref ComponentShutdown args)
Expand Down Expand Up @@ -198,22 +197,20 @@ private void SetBehavior(Entity<AnomalyComponent> anomaly, ProtoId<AnomalyBehavi
if (anomaly.Comp.CurrentBehavior != null)
RemoveBehavior(anomaly, anomaly.Comp.CurrentBehavior.Value);

//event broadcast
var ev = new AnomalyBehaviorChangedEvent(anomaly, anomaly.Comp.CurrentBehavior, behaviorProto);
anomaly.Comp.CurrentBehavior = behaviorProto;
RaiseLocalEvent(anomaly, ref ev, true);

var behavior = _prototype.Index(behaviorProto);

EntityManager.AddComponents(anomaly, behavior.Components);

var ev = new AnomalyBehaviorChangedEvent(anomaly, anomaly.Comp.CurrentBehavior, behaviorProto);
RaiseLocalEvent(anomaly, ref ev, true);
}

private void RemoveBehavior(Entity<AnomalyComponent> anomaly, ProtoId<AnomalyBehaviorPrototype> behaviorProto)
{
if (anomaly.Comp.CurrentBehavior == null)
return;

var behavior = _prototype.Index(anomaly.Comp.CurrentBehavior.Value);
var behavior = _prototype.Index(behaviorProto);

EntityManager.RemoveComponents(anomaly, behavior.Components);
}
Expand Down
20 changes: 10 additions & 10 deletions Content.Server/Anomaly/Effects/ShuffleParticlesAnomalySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ public override void Initialize()
SubscribeLocalEvent<ShuffleParticlesAnomalyComponent, StartCollideEvent>(OnStartCollide);
}

private void OnStartCollide(EntityUid uid, ShuffleParticlesAnomalyComponent shuffle, StartCollideEvent args)
private void OnStartCollide(Entity<ShuffleParticlesAnomalyComponent> ent, ref StartCollideEvent args)
{
if (!TryComp<AnomalyComponent>(uid, out var anomaly))
if (!TryComp<AnomalyComponent>(ent, out var anomaly))
return;

if (shuffle.ShuffleOnParticleHit && _random.Prob(shuffle.Prob))
_anomaly.ShuffleParticlesEffect(anomaly);

if (!TryComp<AnomalousParticleComponent>(args.OtherEntity, out var particle))
if (!HasComp<AnomalousParticleComponent>(args.OtherEntity))
return;

if (ent.Comp.ShuffleOnParticleHit && _random.Prob(ent.Comp.Prob))
_anomaly.ShuffleParticlesEffect((ent, anomaly));
}

private void OnPulse(EntityUid uid, ShuffleParticlesAnomalyComponent shuffle, AnomalyPulseEvent args)
private void OnPulse(Entity<ShuffleParticlesAnomalyComponent> ent, ref AnomalyPulseEvent args)
{
if (!TryComp<AnomalyComponent>(uid, out var anomaly))
if (!TryComp<AnomalyComponent>(ent, out var anomaly))
return;

if (shuffle.ShuffleOnPulse && _random.Prob(shuffle.Prob))
if (ent.Comp.ShuffleOnPulse && _random.Prob(ent.Comp.Prob))
{
_anomaly.ShuffleParticlesEffect(anomaly);
_anomaly.ShuffleParticlesEffect((ent, anomaly));
}
}
}
Expand Down
23 changes: 18 additions & 5 deletions Content.Server/Antag/AntagSelectionSystem.API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,26 @@ public bool TryGetNextAvailableDefinition(Entity<AntagSelectionComponent> ent,
/// Gets the number of antagonists that should be present for a given rule based on the provided pool.
/// A null pool will simply use the player count.
/// </summary>
public int GetTargetAntagCount(Entity<AntagSelectionComponent> ent, AntagSelectionPlayerPool? pool = null)
public int GetTargetAntagCount(Entity<AntagSelectionComponent> ent, int? playerCount = null)
{
var count = 0;
foreach (var def in ent.Comp.Definitions)
{
count += GetTargetAntagCount(ent, pool, def);
count += GetTargetAntagCount(ent, playerCount, def);
}

return count;
}

public int GetTotalPlayerCount(IList<ICommonSession> pool)
{
var count = 0;
foreach (var session in pool)
{
if (session.Status is SessionStatus.Disconnected or SessionStatus.Zombie)
continue;

count++;
}

return count;
Expand All @@ -67,14 +81,13 @@ public int GetTargetAntagCount(Entity<AntagSelectionComponent> ent, AntagSelecti
/// Gets the number of antagonists that should be present for a given antag definition based on the provided pool.
/// A null pool will simply use the player count.
/// </summary>
public int GetTargetAntagCount(Entity<AntagSelectionComponent> ent, AntagSelectionPlayerPool? pool, AntagSelectionDefinition def)
public int GetTargetAntagCount(Entity<AntagSelectionComponent> ent, int? playerCount, AntagSelectionDefinition def)
{
// TODO ANTAG
// make pool non-nullable
// Review uses and ensure that people are INTENTIONALLY including players in the lobby if this is a mid-round
// antag selection.
var poolSize = pool?.Count ?? _playerManager.Sessions
.Count(s => s.State.Status is not SessionStatus.Disconnected and not SessionStatus.Zombie);
var poolSize = playerCount ?? GetTotalPlayerCount(_playerManager.Sessions);

// factor in other definitions' affect on the count.
var countOffset = 0;
Expand Down
14 changes: 11 additions & 3 deletions Content.Server/Antag/AntagSelectionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,18 +203,26 @@ public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSessi
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, AntagSelectionDefinition def)
{
var playerPool = GetPlayerPool(ent, pool, def);
var count = GetTargetAntagCount(ent, playerPool, def);
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);

// if there is both a spawner and players getting picked, let it fall back to a spawner.
var noSpawner = def.SpawnerPrototype == null;
for (var i = 0; i < count; i++)
{
var session = (ICommonSession?) null;
if (def.PickPlayer)
{
if (!playerPool.TryPickAndTake(RobustRandom, out session))
if (!playerPool.TryPickAndTake(RobustRandom, out session) && noSpawner)
{
Log.Warning($"Couldn't pick a player for {ToPrettyString(ent):rule}, no longer choosing antags for this definition");
break;
}

if (ent.Comp.SelectedSessions.Contains(session))
if (session != null && ent.Comp.SelectedSessions.Contains(session))
{
Log.Warning($"Somehow picked {session} for an antag when this rule already selected them previously");
continue;
}
}

MakeAntag(ent, session, def);
Expand Down
1 change: 1 addition & 0 deletions Content.Server/Antag/Components/AntagSelectionComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public partial struct AntagSelectionDefinition()

/// <summary>
/// Whether or not players should be picked to inhabit this antag or not.
/// If no players are left and <see cref="SpawnerPrototype"/> is set, it will make a ghost role.
/// </summary>
[DataField]
public bool PickPlayer = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Content.Server.Atmos.EntitySystems;

namespace Content.Server.Atmos.Components;

/// <summary>
/// This is used for restricting anchoring pipes so that they do not overlap.
/// </summary>
[RegisterComponent, Access(typeof(PipeRestrictOverlapSystem))]
public sealed partial class PipeRestrictOverlapComponent : Component;
123 changes: 123 additions & 0 deletions Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System.Linq;
using Content.Server.Atmos.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Popups;
using Content.Shared.Atmos;
using Content.Shared.Construction.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;

namespace Content.Server.Atmos.EntitySystems;

/// <summary>
/// This handles restricting pipe-based entities from overlapping outlets/inlets with other entities.
/// </summary>
public sealed class PipeRestrictOverlapSystem : EntitySystem
{
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly TransformSystem _xform = default!;

private readonly List<EntityUid> _anchoredEntities = new();
private EntityQuery<NodeContainerComponent> _nodeContainerQuery;

/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorStateChangedEvent>(OnAnchorStateChanged);
SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorAttemptEvent>(OnAnchorAttempt);

_nodeContainerQuery = GetEntityQuery<NodeContainerComponent>();
}

private void OnAnchorStateChanged(Entity<PipeRestrictOverlapComponent> ent, ref AnchorStateChangedEvent args)
{
if (!args.Anchored)
return;

if (HasComp<AnchorableComponent>(ent) && CheckOverlap(ent))
{
_popup.PopupEntity(Loc.GetString("pipe-restrict-overlap-popup-blocked", ("pipe", ent.Owner)), ent);
_xform.Unanchor(ent, Transform(ent));
}
}

private void OnAnchorAttempt(Entity<PipeRestrictOverlapComponent> ent, ref AnchorAttemptEvent args)
{
if (args.Cancelled)
return;

if (!_nodeContainerQuery.TryComp(ent, out var node))
return;

var xform = Transform(ent);
if (CheckOverlap((ent, node, xform)))
{
_popup.PopupEntity(Loc.GetString("pipe-restrict-overlap-popup-blocked", ("pipe", ent.Owner)), ent, args.User);
args.Cancel();
}
}

[PublicAPI]
public bool CheckOverlap(EntityUid uid)
{
if (!_nodeContainerQuery.TryComp(uid, out var node))
return false;

return CheckOverlap((uid, node, Transform(uid)));
}

public bool CheckOverlap(Entity<NodeContainerComponent, TransformComponent> ent)
{
if (ent.Comp2.GridUid is not { } grid || !TryComp<MapGridComponent>(grid, out var gridComp))
return false;

var indices = _map.TileIndicesFor(grid, gridComp, ent.Comp2.Coordinates);
_anchoredEntities.Clear();
_map.GetAnchoredEntities((grid, gridComp), indices, _anchoredEntities);

foreach (var otherEnt in _anchoredEntities)
{
// this should never actually happen but just for safety
if (otherEnt == ent.Owner)
continue;

if (!_nodeContainerQuery.TryComp(otherEnt, out var otherComp))
continue;

if (PipeNodesOverlap(ent, (otherEnt, otherComp, Transform(otherEnt))))
return true;
}

return false;
}

public bool PipeNodesOverlap(Entity<NodeContainerComponent, TransformComponent> ent, Entity<NodeContainerComponent, TransformComponent> other)
{
var entDirs = GetAllDirections(ent).ToList();
var otherDirs = GetAllDirections(other).ToList();

foreach (var dir in entDirs)
{
foreach (var otherDir in otherDirs)
{
if ((dir & otherDir) != 0)
return true;
}
}

return false;

IEnumerable<PipeDirection> GetAllDirections(Entity<NodeContainerComponent, TransformComponent> pipe)
{
foreach (var node in pipe.Comp1.Nodes.Values)
{
// we need to rotate the pipe manually like this because the rotation doesn't update for pipes that are unanchored.
if (node is PipeNode pipeNode)
yield return pipeNode.OriginalPipeDirection.RotatePipeDirection(pipe.Comp2.LocalRotation);
}
}
}
}
Loading

0 comments on commit 4bf8b9e

Please sign in to comment.