Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Content.Shared._Forge.QuestInstance;
using JetBrains.Annotations;
using Robust.Client.UserInterface;


namespace Content.Client._Forge.QuestInstance;


[UsedImplicitly]
public sealed class QuestBoardBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private QuestBoardWindow? _window;

public QuestBoardBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }

protected override void Open()
{
base.Open();

_window = this.CreateWindow<QuestBoardWindow>();
_window.OpenCentered();

_window.OnDifficultySelected += difficulty =>
{
SendMessage(new QuestBoardSelectDifficultyMessage(difficulty));
};
}

protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

if (state is QuestBoardBoundUserInterfaceState s)
_window?.UpdateState(s);
}
}

81 changes: 81 additions & 0 deletions Content.Client/_Forge/QuestInstance/QuestBoardWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
MinSize="380 320"
Title="{Loc 'quest-board-title'}">
<BoxContainer Orientation="Vertical" Margin="12" SeparationOverride="10">

<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1a140d"
BorderColor="#a88b5e"
BorderThickness="1 1 1 1" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical" Margin="10 8">
<Label Text="{Loc 'quest-board-title'}"
StyleClasses="LabelHeading" FontColorOverride="#e3c88f"
HorizontalAlignment="Center" />
<Label Name="StatusLabel"
Text=""
HorizontalAlignment="Center"
Margin="0 4 0 0" />
</BoxContainer>
</PanelContainer>

<controls:HLine Color="#6f5636" Thickness="1" Margin="0 0 0 2" />

<PanelContainer Name="CreateBox">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#17120d"
BorderColor="#8f6a33"
BorderThickness="1 1 1 1" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="6">
<Label Text="{Loc 'quest-board-select-difficulty'}"
StyleClasses="StatusFieldTitle"
HorizontalAlignment="Center"
Margin="0 0 0 6" />
<Button Name="EasyButton"
Text="{Loc 'quest-board-easy'}"
StyleClasses="Caution"
HorizontalExpand="True"
Margin="0 1"
MinSize="0 30" />
<Button Name="MediumButton"
Text="{Loc 'quest-board-medium'}"
StyleClasses="Caution"
HorizontalExpand="True"
Margin="0 1"
MinSize="0 30" />
<Button Name="HardButton"
Text="{Loc 'quest-board-hard'}"
StyleClasses="Caution"
HorizontalExpand="True"
Margin="0 1"
MinSize="0 30" />
</BoxContainer>
</PanelContainer>

<PanelContainer Name="JoinBox" Visible="False">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#18120e"
BorderColor="#a88b5e"
BorderThickness="1 1 1 1" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="6">
<Label Text="{Loc 'quest-board-instance-active'}"
StyleClasses="StatusFieldTitle"
HorizontalAlignment="Center"
Margin="0 0 0 6" />
<Button Name="JoinButton"
Text="{Loc 'quest-board-join'}"
StyleClasses="Caution"
HorizontalExpand="True"
Margin="0 1"
MinSize="0 30" />
</BoxContainer>
</PanelContainer>

</BoxContainer>
</controls:FancyWindow>

51 changes: 51 additions & 0 deletions Content.Client/_Forge/QuestInstance/QuestBoardWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Content.Client.UserInterface.Controls;
using Content.Shared._Forge.QuestInstance;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;


namespace Content.Client._Forge.QuestInstance;


[GenerateTypedNameReferences]
public sealed partial class QuestBoardWindow : FancyWindow
{
public QuestBoardWindow()
{
RobustXamlLoader.Load(this);

EasyButton.OnPressed += _ => OnDifficultySelected?.Invoke(QuestDifficulty.Easy);
MediumButton.OnPressed += _ => OnDifficultySelected?.Invoke(QuestDifficulty.Medium);
HardButton.OnPressed += _ => OnDifficultySelected?.Invoke(QuestDifficulty.Hard);
JoinButton.OnPressed += _ => OnDifficultySelected?.Invoke(QuestDifficulty.Easy);
}

public event Action<QuestDifficulty>? OnDifficultySelected;

public void UpdateState(QuestBoardBoundUserInterfaceState state)
{
if (state.HasActiveInstance)
{
CreateBox.Visible = false;
JoinBox.Visible = true;
StatusLabel.FontColorOverride = Color.FromHex("#ead2a2");

var minutes = state.RemainingSeconds / 60;
var seconds = state.RemainingSeconds % 60;
StatusLabel.Text = Loc.GetString(
"quest-board-status-active",
("players", state.ParticipantCount),
("minutes", minutes),
("seconds", seconds));
}
else
{
CreateBox.Visible = true;
JoinBox.Visible = false;
StatusLabel.FontColorOverride = Color.FromHex("#c7ae81");
StatusLabel.Text = Loc.GetString("quest-board-status-idle");
}
}
}


84 changes: 84 additions & 0 deletions Content.Client/_Forge/Weather/WeatherAudioCleanupSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Content.Shared._Forge.QuestInstance;
using Content.Shared.Weather;
using Robust.Client.Player;
using Robust.Shared.Audio.Components;
using Robust.Shared.Audio.Systems;

namespace Content.Client.Weather;

public sealed class WeatherAudioCleanupSystem : EntitySystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IPlayerManager _player = default!;

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

SubscribeLocalEvent<WeatherComponent, ComponentShutdown>(OnWeatherShutdown);
SubscribeNetworkEvent<QuestInstanceWeatherAudioCleanupEvent>(OnQuestInstanceWeatherCleanup);
}

private void OnQuestInstanceWeatherCleanup(QuestInstanceWeatherAudioCleanupEvent ev)
{
var keepMapUid = ResolveKeepMapUid(ev.KeepMapUid);
CleanupWeatherAudio(keepMapUid);
}

private EntityUid? ResolveKeepMapUid(NetEntity? keepMapNetUid)
{
if (keepMapNetUid is { } keepNet && TryGetEntity(keepNet, out var keepMapUid) && !Deleted(keepMapUid))
return keepMapUid;

if (_player.LocalEntity is { } playerUid && !Deleted(playerUid))
return Transform(playerUid).MapUid;

return null;
}

private void OnWeatherShutdown(EntityUid uid, WeatherComponent component, ComponentShutdown args)
{
StopAllStreams(component);
}

private void CleanupWeatherAudio(EntityUid? keepMapUid)
{
var query = EntityQueryEnumerator<WeatherComponent, TransformComponent>();
while (query.MoveNext(out _, out var weather, out var xform))
{
if (!HasActiveStreams(weather))
continue;

if (keepMapUid != null && xform.MapUid == keepMapUid)
continue;

StopAllStreams(weather);
}
}

private static bool HasActiveStreams(WeatherComponent component)
{
foreach (var data in component.Weather.Values)
{
if (data.Stream != null)
return true;
}

return false;
}

private void StopAllStreams(WeatherComponent component)
{
foreach (var data in component.Weather.Values)
{
if (data.Stream is not { } streamUid)
continue;

if (TryComp(streamUid, out AudioComponent? audioComp))
_audio.SetState(streamUid, AudioState.Stopped, true, audioComp);

_audio.Stop(streamUid);
data.Stream = null;
}
}
}
50 changes: 50 additions & 0 deletions Content.Server/_Forge/QuestInstance/QuestBoardComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Robust.Shared.Map;
using Robust.Shared.Network;


namespace Content.Server._Forge.QuestInstance;

[RegisterComponent]
public sealed partial class QuestBoardComponent : Component
{
[DataField]
public bool HasActiveInstance;

[DataField]
public HashSet<NetUserId> Participants = new();

[DataField]
public HashSet<EntityUid> PresentPlayers = new();

[DataField]
public Dictionary<EntityUid, EntityCoordinates> ReturnCoords = new();

[DataField]
public HashSet<int> SentWarnings = new();

[DataField]
public List<EntityCoordinates> PendingBarrierCoords = new();

[DataField]
public string BarrierProto = "QuestInvisibleWall";

[DataField]
public TimeSpan EndAt;

[DataField]
public TimeSpan JoinUntil;

[DataField]
public int JoinWindowSeconds;

public TimeSpan NextMaintenanceAt;

[DataField]
public EntityUid MapUid = EntityUid.Invalid;

[DataField]
public EntityCoordinates SpawnCoords = EntityCoordinates.Invalid;

[DataField]
public int[] WarningThresholdsSeconds = Array.Empty<int>();
}
Loading
Loading