Skip to content

Commit

Permalink
Merge pull request #225 from ss14-harmony/upstream20241204
Browse files Browse the repository at this point in the history
Upstream20241204
  • Loading branch information
KeldWolf authored Dec 5, 2024
2 parents d78051d + db3c93a commit 3094b94
Show file tree
Hide file tree
Showing 42 changed files with 135,182 additions and 4,046 deletions.
6 changes: 5 additions & 1 deletion Content.Client/Lobby/LobbyState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public override void FrameUpdate(FrameEventArgs e)
return;
}

Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
string text;

if (_gameTicker.Paused)
Expand All @@ -136,6 +136,10 @@ public override void FrameUpdate(FrameEventArgs e)
{
text = Loc.GetString(seconds < -5 ? "lobby-state-right-now-question" : "lobby-state-right-now-confirmation");
}
else if (difference.TotalHours >= 1)
{
text = $"{Math.Floor(difference.TotalHours)}:{difference.Minutes:D2}:{difference.Seconds:D2}";
}
else
{
text = $"{difference.Minutes}:{difference.Seconds:D2}";
Expand Down
23 changes: 23 additions & 0 deletions Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

namespace Content.Client.Silicons.Laws.Ui;
Expand All @@ -18,8 +19,13 @@ public sealed partial class LawDisplay : Control
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly EntityManager _entityManager = default!;

private static readonly TimeSpan PressCooldown = TimeSpan.FromSeconds(3);

private readonly Dictionary<Button, TimeSpan> _nextAllowedPress = new();

public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
{
RobustXamlLoader.Load(this);
Expand Down Expand Up @@ -47,9 +53,12 @@ public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
MinWidth = 75,
};

_nextAllowedPress[localButton] = TimeSpan.Zero;

localButton.OnPressed += _ =>
{
_chatManager.SendMessage($"{lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Local);
_nextAllowedPress[localButton] = _timing.CurTime + PressCooldown;
};

LawAnnouncementButtons.AddChild(localButton);
Expand All @@ -71,6 +80,8 @@ public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
MinWidth = 75,
};

_nextAllowedPress[radioChannelButton] = TimeSpan.Zero;

radioChannelButton.OnPressed += _ =>
{
switch (radioChannel)
Expand All @@ -80,9 +91,21 @@ public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
default:
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
}
_nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown;
};

LawAnnouncementButtons.AddChild(radioChannelButton);
}
}

protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);

var curTime = _timing.CurTime;
foreach (var (button, nextPress) in _nextAllowedPress)
{
button.Disabled = curTime < nextPress;
}
}
}
8 changes: 5 additions & 3 deletions Content.Client/Wires/UI/WiresMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,7 @@ public WiresMenu()
(_statusContainer = new GridContainer
{
Margin = new Thickness(8, 4),
// TODO: automatically change columns count.
Columns = 3
Rows = 2
})
}
}
Expand All @@ -227,7 +226,8 @@ public WiresMenu()
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
});
CloseButton.OnPressed += _ => Close();
SetSize = new Vector2(320, 200);
SetHeight = 200;
MinWidth = 320;
}


Expand Down Expand Up @@ -503,6 +503,8 @@ private sealed class StatusLight : Control

public StatusLight(StatusLightData data, IResourceCache resourceCache)
{
HorizontalAlignment = HAlignment.Right;

var hsv = Color.ToHsv(data.Color);
hsv.Z /= 2;
var dimColor = Color.FromHsv(hsv);
Expand Down
3 changes: 2 additions & 1 deletion Content.IntegrationTests/Tests/PostMapInitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public sealed class PostMapInitTest
"Xeno", // Xeno map playtest
"Barratry", // Update of old map
"dm01-entryway", // deathmatch PROMOD map
"Aspid" // Pseudo playtest, not merged to upstream yet.
"Aspid", // Pseudo playtest, not merged to upstream yet.
"Amber"
};

/// <summary>
Expand Down
62 changes: 29 additions & 33 deletions Content.Server/Fluids/EntitySystems/DrainSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,6 @@ public override void Update(float frameTime)
}
drain.Accumulator -= drain.DrainFrequency;

// Disable ambient sound from emptying manually
if (!drain.AutoDrain)
{
_ambientSoundSystem.SetAmbience(uid, false);
continue;
}

if (!managerQuery.TryGetComponent(uid, out var manager))
continue;

Expand All @@ -160,41 +153,44 @@ public override void Update(float frameTime)
// This will ensure that UnitsPerSecond is per second...
var amount = drain.UnitsPerSecond * drain.DrainFrequency;

_puddles.Clear();
_lookup.GetEntitiesInRange(Transform(uid).Coordinates, drain.Range, _puddles);

if (_puddles.Count == 0)
if (drain.AutoDrain)
{
_ambientSoundSystem.SetAmbience(uid, false);
continue;
}
_puddles.Clear();
_lookup.GetEntitiesInRange(Transform(uid).Coordinates, drain.Range, _puddles);

_ambientSoundSystem.SetAmbience(uid, true);

amount /= _puddles.Count;

foreach (var puddle in _puddles)
{
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
// but queuedelete should be pretty safe.
if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, puddle.Comp.SolutionName, ref puddle.Comp.Solution, out var puddleSolution))
if (_puddles.Count == 0)
{
EntityManager.QueueDeleteEntity(puddle);
_ambientSoundSystem.SetAmbience(uid, false);
continue;
}

// Removes the lowest of:
// the drain component's units per second adjusted for # of puddles
// the puddle's remaining volume (making it cleanly zero)
// the drain's remaining volume in its buffer.
var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));
_ambientSoundSystem.SetAmbience(uid, true);

drainSolution.AddSolution(transferSolution, _prototypeManager);
amount /= _puddles.Count;

if (puddleSolution.Volume <= 0)
foreach (var puddle in _puddles)
{
QueueDel(puddle);
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
// but queuedelete should be pretty safe.
if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, puddle.Comp.SolutionName, ref puddle.Comp.Solution, out var puddleSolution))
{
EntityManager.QueueDeleteEntity(puddle);
continue;
}

// Removes the lowest of:
// the drain component's units per second adjusted for # of puddles
// the puddle's remaining volume (making it cleanly zero)
// the drain's remaining volume in its buffer.
var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));

drainSolution.AddSolution(transferSolution, _prototypeManager);

if (puddleSolution.Volume <= 0)
{
QueueDel(puddle);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions Content.Shared/Fluids/Components/DrainComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public sealed partial class DrainComponent : Component
public float Accumulator = 0f;

/// <summary>
/// Does this drain automatically absorb surrouding puddles? Or is it a drain designed to empty
/// solutions in it manually?
/// If true, automatically transfers solutions from nearby puddles and drains them. True for floor drains;
/// false for things like toilets and sinks.
/// </summary>
[DataField]
public bool AutoDrain = true;
Expand Down
19 changes: 17 additions & 2 deletions Content.Shared/Lock/LockSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,24 @@ public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = nul
});
}

_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
Lock(uid, user, lockComp);
return true;
}

/// <summary>
/// Forces a given entity to be locked, does not activate a do-after.
/// </summary>
public void Lock(EntityUid uid, EntityUid? user, LockComponent? lockComp = null)
{
if (!Resolve(uid, ref lockComp))
return;

if (user is { Valid: true })
{
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
("entityName", Identity.Name(uid, EntityManager))), uid, user);
}

_audio.PlayPredicted(lockComp.LockSound, uid, user);

lockComp.Locked = true;
Expand All @@ -141,7 +157,6 @@ public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = nul

var ev = new LockToggledEvent(true);
RaiseLocalEvent(uid, ref ev, true);
return true;
}

/// <summary>
Expand Down
34 changes: 34 additions & 0 deletions Content.Shared/Storage/Components/StoreOnCollideComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Content.Shared.Storage.EntitySystems;
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;

namespace Content.Shared.Storage.Components;

// Use where you want an entity to store other entities on collide
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(StoreOnCollideSystem))]
public sealed partial class StoreOnCollideComponent : Component
{
/// <summary>
/// Entities that are allowed in the storage on collide
/// </summary>
[DataField]
public EntityWhitelist? Whitelist;

/// <summary>
/// Should this storage lock on collide, provided they have a lock component?
/// </summary>
[DataField]
public bool LockOnCollide;

/// <summary>
/// Should the behavior be disabled when the storage is first opened?
/// </summary>
[DataField]
public bool DisableWhenFirstOpened;

/// <summary>
/// If the behavior is disabled or not
/// </summary>
[DataField, AutoNetworkedField]
public bool Disabled;
}
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,14 @@ public bool TryCloseStorage(EntityUid target)
return true;
}

public bool IsOpen(EntityUid target, SharedEntityStorageComponent? component = null)
{
if (!ResolveStorage(target, ref component))
return false;

return component.Open;
}

public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, SharedEntityStorageComponent? component = null)
{
if (!ResolveStorage(target, ref component))
Expand Down
71 changes: 71 additions & 0 deletions Content.Shared/Storage/EntitySystems/StoreOnCollideSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Content.Shared.Lock;
using Content.Shared.Storage.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Network;
using Robust.Shared.Physics.Events;
using Robust.Shared.Timing;

namespace Content.Shared.Storage.EntitySystems;

internal sealed class StoreOnCollideSystem : EntitySystem
{
[Dependency] private readonly SharedEntityStorageSystem _storage = default!;
[Dependency] private readonly LockSystem _lock = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly INetManager _netMan = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StoreOnCollideComponent, StartCollideEvent>(OnCollide);
SubscribeLocalEvent<StoreOnCollideComponent, StorageAfterOpenEvent>(AfterOpen);
// TODO: Add support to stop colliding after throw, wands will need a WandComp
}

// We use Collide instead of Projectile to support different types of interactions
private void OnCollide(Entity<StoreOnCollideComponent> ent, ref StartCollideEvent args)
{
TryStoreTarget(ent, args.OtherEntity);

TryLockStorage(ent);
}

private void AfterOpen(Entity<StoreOnCollideComponent> ent, ref StorageAfterOpenEvent args)
{
var comp = ent.Comp;

if (comp is { DisableWhenFirstOpened: true, Disabled: false })
comp.Disabled = true;
}

private void TryStoreTarget(Entity<StoreOnCollideComponent> ent, EntityUid target)
{
var storageEnt = ent.Owner;
var comp = ent.Comp;

if (_netMan.IsClient || _gameTiming.ApplyingState)
return;

if (ent.Comp.Disabled || storageEnt == target || Transform(target).Anchored || _storage.IsOpen(storageEnt) || _whitelist.IsWhitelistFail(comp.Whitelist, target))
return;

_storage.Insert(target, storageEnt);

}

private void TryLockStorage(Entity<StoreOnCollideComponent> ent)
{
var storageEnt = ent.Owner;
var comp = ent.Comp;

if (_netMan.IsClient || _gameTiming.ApplyingState)
return;

if (ent.Comp.Disabled)
return;

if (comp.LockOnCollide && !_lock.IsLocked(storageEnt))
_lock.Lock(storageEnt, storageEnt);
}
}
Loading

0 comments on commit 3094b94

Please sign in to comment.