Skip to content

Commit

Permalink
Merge branch 'Rxup:master' into master
Browse files Browse the repository at this point in the history
superlowfpss authored Dec 10, 2024
2 parents 7816788 + ecbc219 commit dd0a3c1
Showing 316 changed files with 229,507 additions and 161,463 deletions.
4 changes: 2 additions & 2 deletions Content.Client/Access/UI/AccessOverriderWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -88,8 +88,8 @@ public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUser
button.Disabled = !interfaceEnabled;
if (interfaceEnabled)
{
button.Pressed = state.TargetAccessReaderIdAccessList?.Contains(accessName) ?? false;
button.Disabled = (!state.AllowedModifyAccessList?.Contains(accessName)) ?? true;
button.Pressed = state.TargetAccessReaderIdAccessList?.Select(x => x.Id).Contains(accessName) ?? false;
button.Disabled = (!state.AllowedModifyAccessList?.Select(x => x.Id).Contains(accessName)) ?? true;
}
}
}
12 changes: 6 additions & 6 deletions Content.Client/Actions/ActionsSystem.cs
Original file line number Diff line number Diff line change
@@ -258,13 +258,13 @@ public void UnlinkAllActions()

public void LinkAllActions(ActionsComponent? actions = null)
{
if (_playerManager.LocalEntity is not { } user ||
!Resolve(user, ref actions, false))
{
return;
}
if (_playerManager.LocalEntity is not { } user ||
!Resolve(user, ref actions, false))
{
return;
}

LinkActions?.Invoke(actions);
LinkActions?.Invoke(actions);
}

public override void Shutdown()
90 changes: 44 additions & 46 deletions Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs
Original file line number Diff line number Diff line change
@@ -1,65 +1,63 @@
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;

namespace Content.Client.Atmos.UI
namespace Content.Client.Atmos.UI;

/// <summary>
/// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
/// </summary>
[UsedImplicitly]
public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
{
/// <summary>
/// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
/// </summary>
[UsedImplicitly]
public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private const float MaxPressure = Atmospherics.MaxOutputPressure;
[ViewVariables]
private const float MaxPressure = Atmospherics.MaxOutputPressure;

[ViewVariables]
private GasPressurePumpWindow? _window;

[ViewVariables]
private GasPressurePumpWindow? _window;
public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}

public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();

protected override void Open()
{
base.Open();
_window = this.CreateWindow<GasPressurePumpWindow>();

_window = this.CreateWindow<GasPressurePumpWindow>();
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
Update();
}

_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
}
public void Update()
{
if (_window == null)
return;

private void OnToggleStatusButtonPressed()
{
if (_window is null) return;
SendMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
}
_window.Title = Identity.Name(Owner, EntMan);

private void OnPumpOutputPressurePressed(string value)
{
var pressure = UserInputParser.TryFloat(value, out var parsed) ? parsed : 0f;
if (pressure > MaxPressure) pressure = MaxPressure;
if (!EntMan.TryGetComponent(Owner, out GasPressurePumpComponent? pump))
return;

SendMessage(new GasPressurePumpChangeOutputPressureMessage(pressure));
}
_window.SetPumpStatus(pump.Enabled);
_window.MaxPressure = pump.MaxTargetPressure;
_window.SetOutputPressure(pump.TargetPressure);
}

/// <summary>
/// Update the UI state based on server-sent info
/// </summary>
/// <param name="state"></param>
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_window == null || state is not GasPressurePumpBoundUserInterfaceState cast)
return;
private void OnToggleStatusButtonPressed()
{
if (_window is null) return;
SendPredictedMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
}

_window.Title = (cast.PumpLabel);
_window.SetPumpStatus(cast.Enabled);
_window.SetOutputPressure(cast.OutputPressure);
}
private void OnPumpOutputPressurePressed(float value)
{
SendPredictedMessage(new GasPressurePumpChangeOutputPressureMessage(value));
}
}
22 changes: 9 additions & 13 deletions Content.Client/Atmos/UI/GasPressurePumpWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinSize="200 120" Title="Pressure Pump">
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc comp-gas-pump-ui-pump-status}"/>
<Control MinSize="5 0" />
<Label Text="{Loc comp-gas-pump-ui-pump-status}" Margin="0 0 5 0"/>
<Button Name="ToggleStatusButton"/>
<Control HorizontalExpand="True"/>
<Button HorizontalAlignment="Right" Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" Disabled="True" Margin="0 0 5 0"/>
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
</BoxContainer>

<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc comp-gas-pump-ui-pump-output-pressure}"/>
<Control MinSize="5 0" />
<LineEdit Name="PumpPressureOutputInput" MinSize="70 0" />
<Control MinSize="5 0" />
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
<Control MinSize="5 0" />
<Control HorizontalExpand="True" />
<Button Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" HorizontalAlignment="Right" Disabled="True"/>
<FloatSpinBox HorizontalExpand="True" Name="PumpPressureOutputInput" MinSize="70 0" />
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>
35 changes: 22 additions & 13 deletions Content.Client/Atmos/UI/GasPressurePumpWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Content.Client.Atmos.EntitySystems;
using Content.Client.UserInterface.Controls;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;

namespace Content.Client.Atmos.UI
{
/// <summary>
/// Client-side UI used to control a gas pressure pump.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class GasPressurePumpWindow : DefaultWindow
public sealed partial class GasPressurePumpWindow : FancyWindow
{
public bool PumpStatus = true;

public event Action? ToggleStatusButtonPressed;
public event Action<string>? PumpOutputPressureChanged;
public event Action<float>? PumpOutputPressureChanged;

public float MaxPressure
{
get => _maxPressure;
set
{
_maxPressure = value;

PumpPressureOutputInput.Value = MathF.Min(value, PumpPressureOutputInput.Value);
}
}

private float _maxPressure = Atmospherics.MaxOutputPressure;

public GasPressurePumpWindow()
{
@@ -30,23 +37,25 @@ public GasPressurePumpWindow()
ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();

PumpPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
PumpPressureOutputInput.OnValueChanged += _ => SetOutputPressureButton.Disabled = false;

SetOutputPressureButton.OnPressed += _ =>
{
PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Text ??= "");
PumpPressureOutputInput.Value = Math.Clamp(PumpPressureOutputInput.Value, 0f, _maxPressure);
PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Value);
SetOutputPressureButton.Disabled = true;
};

SetMaxPressureButton.OnPressed += _ =>
{
PumpPressureOutputInput.Text = Atmospherics.MaxOutputPressure.ToString(CultureInfo.CurrentCulture);
PumpPressureOutputInput.Value = _maxPressure;
SetOutputPressureButton.Disabled = false;
};
}

public void SetOutputPressure(float pressure)
{
PumpPressureOutputInput.Text = pressure.ToString(CultureInfo.CurrentCulture);
PumpPressureOutputInput.Value = pressure;
}

public void SetPumpStatus(bool enabled)
72 changes: 0 additions & 72 deletions Content.Client/Backmen/OfferItem/OfferItemIndicatorsOverlay.cs

This file was deleted.

53 changes: 0 additions & 53 deletions Content.Client/Backmen/OfferItem/OfferItemSystem.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

namespace Content.Client.Clothing;

public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
{
[Dependency] private readonly SharedItemSystem _itemSys = default!;

1 change: 0 additions & 1 deletion Content.Client/Input/ContentContexts.cs
Original file line number Diff line number Diff line change
@@ -89,7 +89,6 @@ public static void SetupContexts(IInputContextContainer contexts)
human.AddFunction(ContentKeyFunctions.ToggleStanding); // Ataraxia
human.AddFunction(ContentKeyFunctions.LookUp); // BACKMEN EDIT
human.AddFunction(CMKeyFunctions.CMUniqueAction); // BACKMEN EDIT
human.AddFunction(ContentKeyFunctions.OfferItem); // Ataraxia
human.AddFunction(ContentKeyFunctions.TargetHead);
human.AddFunction(ContentKeyFunctions.TargetTorso);
human.AddFunction(ContentKeyFunctions.TargetLeftArm);
10 changes: 0 additions & 10 deletions Content.Client/Inventory/ClientInventorySystem.cs
Original file line number Diff line number Diff line change
@@ -40,7 +40,6 @@ public override void Initialize()

SubscribeLocalEvent<InventorySlotsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<InventorySlotsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<InventorySlotsComponent, RefreshInventorySlotsEvent>(OnRefreshInventorySlots);
SubscribeLocalEvent<InventoryComponent, ComponentShutdown>(OnShutdown);

SubscribeLocalEvent<InventorySlotsComponent, DidEquipEvent>((_, comp, args) =>
@@ -182,15 +181,6 @@ public void UpdateSlot(EntityUid owner, InventorySlotsComponent component, strin
EntitySlotUpdate?.Invoke(newData);
}

public void OnRefreshInventorySlots(EntityUid owner, InventorySlotsComponent component, RefreshInventorySlotsEvent args)
{
if (!component.SlotData.TryGetValue(args.SlotName, out var slotData)
|| _playerManager.LocalEntity != owner)
return;

OnSlotRemoved?.Invoke(slotData);
}

public bool TryAddSlotDef(EntityUid owner, InventorySlotsComponent component, SlotDefinition newSlotDef)
{
SlotData newSlotData = newSlotDef; //convert to slotData
6 changes: 6 additions & 0 deletions Content.Client/Inventory/StrippableBoundUserInterface.cs
Original file line number Diff line number Diff line change
@@ -191,9 +191,15 @@ private void SlotPressed(GUIBoundKeyEventArgs ev, SlotControl slot)
return;

if (ev.Function == ContentKeyFunctions.ExamineEntity)
{
_examine.DoExamine(slot.Entity.Value);
ev.Handle();
}
else if (ev.Function == EngineKeyFunctions.UseSecondary)
{
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(slot.Entity.Value);
ev.Handle();
}
}

private void AddInventoryButton(EntityUid invUid, string slotId, InventoryComponent inv)
6 changes: 5 additions & 1 deletion Content.Client/Lobby/LobbyState.cs
Original file line number Diff line number Diff line change
@@ -122,7 +122,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)
@@ -142,6 +142,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}";
6 changes: 5 additions & 1 deletion Content.Client/Lobby/LobbyUIController.cs
Original file line number Diff line number Diff line change
@@ -6,6 +6,8 @@
using Content.Client.Lobby.UI;
using Content.Client.Players.PlayTimeTracking;
using Content.Client.Station;
using Content.Corvax.Interfaces.Client;
using Content.Corvax.Interfaces.Shared;
using Content.Shared.CCVar;
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
@@ -40,6 +42,7 @@ public sealed partial class LobbyUIController : UIController, IOnStateEntered<Lo
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly JobRequirementsManager _requirements = default!;
[Dependency] private readonly MarkingManager _markings = default!;
[Dependency] private readonly ISharedSponsorsManager _clientSponsorsManager = default!;
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
@@ -273,7 +276,8 @@ private void OpenSavePanel()
_prototypeManager,
_resourceCache,
_requirements,
_markings);
_markings,
_clientSponsorsManager);

_profileEditor.OnOpenGuidebook += _guide.OpenHelp;

17 changes: 16 additions & 1 deletion Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@
using Content.Client.Sprite;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Corvax.Interfaces.Client;
using Content.Corvax.Interfaces.Shared;
using Content.Shared.CCVar;
using Content.Shared.Clothing;
using Content.Shared.Corvax.CCCVars;
@@ -50,6 +52,7 @@ public sealed partial class HumanoidProfileEditor : BoxContainer
private readonly MarkingManager _markingManager;
private readonly JobRequirementsManager _requirements;
private readonly LobbyUIController _controller;
private readonly ISharedSponsorsManager _clientSponsorsManager;

private FlavorText.FlavorText? _flavorText;
private TextEdit? _flavorTextEdit;
@@ -114,7 +117,8 @@ public HumanoidProfileEditor(
IPrototypeManager prototypeManager,
IResourceManager resManager,
JobRequirementsManager requirements,
MarkingManager markings)
MarkingManager markings,
ISharedSponsorsManager clientSponsorsManager)
{
RobustXamlLoader.Load(this);
_sawmill = logManager.GetSawmill("profile.editor");
@@ -124,6 +128,7 @@ public HumanoidProfileEditor(
_playerManager = playerManager;
_prototypeManager = prototypeManager;
_markingManager = markings;
_clientSponsorsManager = clientSponsorsManager;
_preferencesManager = preferencesManager;
_resManager = resManager;
_requirements = requirements;
@@ -590,6 +595,16 @@ public void RefreshTraits()
if (selector == null)
continue;

//backmen-start: sponsor traits
if (selector.Trait.SponsorOnly && !_clientSponsorsManager.GetClientPrototypes().Contains(selector.Trait.ID))
{
selector.Checkbox.Label.FontColorOverride = Color.Gray;
selector.Checkbox.Disabled = true;
selector.Checkbox.Pressed = false;
selector.Checkbox.Label.Text += $" ({Loc.GetString("sponsor-only")})";
}
//backmen-end: sponsor traits

if (category is { MaxTraitPoints: >= 0 } &&
selector.Cost + selectionCount > category.MaxTraitPoints)
{
2 changes: 2 additions & 0 deletions Content.Client/Lobby/UI/Roles/TraitPreferenceSelector.xaml.cs
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ namespace Content.Client.Lobby.UI.Roles;
public sealed partial class TraitPreferenceSelector : Control
{
public int Cost;
public readonly TraitPrototype Trait;

public bool Preference
{
@@ -23,6 +24,7 @@ public TraitPreferenceSelector(TraitPrototype trait)
{
RobustXamlLoader.Load(this);

Trait = trait;
var text = trait.Cost != 0 ? $"[{trait.Cost}] " : "";
text += Loc.GetString(trait.Name);

1 change: 0 additions & 1 deletion Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
Original file line number Diff line number Diff line change
@@ -208,7 +208,6 @@ void HandleToggleAutoGetUp(BaseButton.ButtonToggledEventArgs args) // BACKMEN ED
AddButton(ContentKeyFunctions.SaveItemLocation);
AddButton(ContentKeyFunctions.ToggleStanding); // backmen: Laying System
AddButton(ContentKeyFunctions.LookUp); // BACKMEN EDIT
AddButton(ContentKeyFunctions.OfferItem); // Ataraxia
AddCheckBox("ui-options-function-hold-look-up", _cfg.GetCVar(BackmenCCvars.CCVars.HoldLookUp), HandleHoldLookUp); // WD EDIT

AddHeader("ui-options-header-interaction-adv");
2 changes: 1 addition & 1 deletion Content.Client/Overlays/StencilOverlay.Weather.cs
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ private void DrawWeather(in OverlayDrawArgs args, WeatherPrototype weatherProto,
var matty = Matrix3x2.Multiply(matrix, invMatrix);
worldHandle.SetTransform(matty);

foreach (var tile in grid.Comp.GetTilesIntersecting(worldAABB))
foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
{
// Ignored tiles for stencil
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
4 changes: 3 additions & 1 deletion Content.Client/Overlays/StencilOverlay.cs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ public sealed partial class StencilOverlay : Overlay
[Dependency] private readonly IPrototypeManager _protoManager = default!;
private readonly ParallaxSystem _parallax;
private readonly SharedTransformSystem _transform;
private readonly SharedMapSystem _map;
private readonly SpriteSystem _sprite;
private readonly WeatherSystem _weather;

@@ -33,11 +34,12 @@ public sealed partial class StencilOverlay : Overlay

private readonly ShaderInstance _shader;

public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SpriteSystem sprite, WeatherSystem weather)
public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SharedMapSystem map, SpriteSystem sprite, WeatherSystem weather)
{
ZIndex = ParallaxSystem.ParallaxZIndex + 1;
_parallax = parallax;
_transform = transform;
_map = map;
_sprite = sprite;
_weather = weather;
IoCManager.InjectDependencies(this);
3 changes: 2 additions & 1 deletion Content.Client/Overlays/StencilOverlaySystem.cs
Original file line number Diff line number Diff line change
@@ -10,13 +10,14 @@ public sealed class StencilOverlaySystem : EntitySystem
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly ParallaxSystem _parallax = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly WeatherSystem _weather = default!;

public override void Initialize()
{
base.Initialize();
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _sprite, _weather));
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _map, _sprite, _weather));
}

public override void Shutdown()
23 changes: 23 additions & 0 deletions Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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);
@@ -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);
@@ -71,6 +80,8 @@ public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
MinWidth = 75,
};

_nextAllowedPress[radioChannelButton] = TimeSpan.Zero;

radioChannelButton.OnPressed += _ =>
{
switch (radioChannel)
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -26,8 +26,8 @@ public DefaultGameScreen()

Chat.OnResized += ChatOnResized;
Chat.OnChatResizeFinish += ChatOnResizeFinish;

MainViewport.OnResized += ResizeActionContainer;
MainViewport.OnResized += ResizeAlertsContainer;
Inventory.OnResized += ResizeActionContainer;
}

@@ -37,6 +37,12 @@ private void ResizeActionContainer()
Actions.ActionsContainer.MaxGridHeight = MainViewport.Size.Y - indent;
}

private void ResizeAlertsContainer()
{
float indent = Chat.Size.Y + Targeting.Size.Y + 120;
Alerts.AlertContainer.MaxGridHeight = Math.Max(MainViewport.Size.Y - indent, 1);
}

private void ChatOnResizeFinish(Vector2 _)
{
var marginBottom = Chat.GetValue<float>(MarginBottomProperty);
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
MinSize="64 64">
<GridContainer Columns="1" HorizontalAlignment="Right" VerticalAlignment="Top">
<PanelContainer >
<BoxContainer Name="AlertContainer" Access="Public" Orientation="Vertical" />
<GridContainer Name="AlertContainer" Columns="1" HorizontalAlignment="Right" VerticalAlignment="Center" Access="Public" />
</PanelContainer>
<partStatus:PartStatusControl Name="PartStatus" Access="Protected"/>
</GridContainer>
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ public sealed partial class AlertsUI : UIWidget
public AlertsUI()
{
RobustXamlLoader.Load(this);
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
}

public void SyncControls(AlertsSystem alertsSystem,
Original file line number Diff line number Diff line change
@@ -83,22 +83,27 @@ private void HandPressed(GUIBoundKeyEventArgs args, SlotControl hand)
if (args.Function == EngineKeyFunctions.UIClick)
{
_handsSystem.UIHandClick(_playerHandsComponent, hand.SlotName);
args.Handle();
}
else if (args.Function == EngineKeyFunctions.UseSecondary)
{
_handsSystem.UIHandOpenContextMenu(hand.SlotName);
args.Handle();
}
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
{
_handsSystem.UIHandActivate(hand.SlotName);
args.Handle();
}
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
{
_handsSystem.UIHandAltActivateItem(hand.SlotName);
args.Handle();
}
else if (args.Function == ContentKeyFunctions.ExamineEntity)
{
_handsSystem.UIInventoryExamine(hand.SlotName);
args.Handle();
}
}

8 changes: 5 additions & 3 deletions Content.Client/Wires/UI/WiresMenu.cs
Original file line number Diff line number Diff line change
@@ -206,8 +206,7 @@ public WiresMenu()
(_statusContainer = new GridContainer
{
Margin = new Thickness(8, 4),
// TODO: automatically change columns count.
Columns = 3
Rows = 2
})
}
}
@@ -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;
}


@@ -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);
3 changes: 2 additions & 1 deletion Content.IntegrationTests/Tests/PostMapInitTest.cs
Original file line number Diff line number Diff line change
@@ -94,7 +94,8 @@ public sealed class PostMapInitTest
"Reach",
"Train",
"Oasis",
"Cog"
"Cog",
"Amber"
};

/// <summary>
8 changes: 6 additions & 2 deletions Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ public sealed class GasProducerAnomalySystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedMapSystem _map = default!;

public override void Initialize()
{
@@ -56,8 +57,11 @@ private void ReleaseGas(EntityUid uid, Gas gas, float mols, float radius, int co
return;

var localpos = xform.Coordinates.Position;
var tilerefs = grid.GetLocalTilesIntersecting(
new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray();
var tilerefs = _map.GetLocalTilesIntersecting(
xform.GridUid.Value,
grid,
new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius)))
.ToArray();

if (tilerefs.Length == 0)
return;
4 changes: 2 additions & 2 deletions Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
Original file line number Diff line number Diff line change
@@ -238,7 +238,7 @@ public override void Update(float frameTime)
if (pressure <= Atmospherics.HazardLowPressure)
{
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false, canSever: false); // backmen
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false, canSever: false, partMultiplier: 0.5f); // backmen
if (!barotrauma.TakingDamage)
{
barotrauma.TakingDamage = true;
@@ -252,7 +252,7 @@ public override void Update(float frameTime)
var damageScale = MathF.Min(((pressure / Atmospherics.HazardHighPressure) - 1) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);

// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false, canSever: false); // backmen
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false, canSever: false, partMultiplier: 0.5f); // backmen
RaiseLocalEvent(uid, new MoodEffectEvent("MobHighPressure")); // backmen: mood

if (!barotrauma.TakingDamage)
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
using Content.Server.Power.EntitySystems;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.DeviceNetwork;
using Content.Shared.Power;
using Content.Shared.Tag;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,169 +1,57 @@
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Binary.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Audio;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Power;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Player;

namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
[UsedImplicitly]
public sealed class GasPressurePumpSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;

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

SubscribeLocalEvent<GasPressurePumpComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceUpdateEvent>(OnPumpUpdated);
SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceDisabledEvent>(OnPumpLeaveAtmosphere);
SubscribeLocalEvent<GasPressurePumpComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<GasPressurePumpComponent, ActivateInWorldEvent>(OnPumpActivate);
SubscribeLocalEvent<GasPressurePumpComponent, PowerChangedEvent>(OnPowerChanged);
// Bound UI subscriptions
SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpChangeOutputPressureMessage>(OnOutputPressureChangeMessage);
SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpToggleStatusMessage>(OnToggleStatusMessage);
}

private void OnInit(EntityUid uid, GasPressurePumpComponent pump, ComponentInit args)
{
UpdateAppearance(uid, pump);
}

private void OnExamined(EntityUid uid, GasPressurePumpComponent pump, ExaminedEvent args)
{
if (!EntityManager.GetComponent<TransformComponent>(uid).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
return;

if (Loc.TryGetString("gas-pressure-pump-system-examined", out var str,
("statusColor", "lightblue"), // TODO: change with pressure?
("pressure", pump.TargetPressure)
))
{
args.PushMarkup(str);
}
}

private void OnPowerChanged(EntityUid uid, GasPressurePumpComponent component, ref PowerChangedEvent args)
{
UpdateAppearance(uid, component);
}

private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args)
{
if (!pump.Enabled
|| (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
|| !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
{
_ambientSoundSystem.SetAmbience(uid, false);
return;
}

var outputStartingPressure = outlet.Air.Pressure;
namespace Content.Server.Atmos.Piping.Binary.EntitySystems;

if (outputStartingPressure >= pump.TargetPressure)
{
_ambientSoundSystem.SetAmbience(uid, false);
return; // No need to pump gas if target has been reached.
}

if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
{
// We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
var pressureDelta = pump.TargetPressure - outputStartingPressure;
var transferMoles = (pressureDelta * outlet.Air.Volume) / (inlet.Air.Temperature * Atmospherics.R);

var removed = inlet.Air.Remove(transferMoles);
_atmosphereSystem.Merge(outlet.Air, removed);
_ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
}
}

private void OnPumpLeaveAtmosphere(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceDisabledEvent args)
{
pump.Enabled = false;
UpdateAppearance(uid, pump);

DirtyUI(uid, pump);
_userInterfaceSystem.CloseUi(uid, GasPressurePumpUiKey.Key);
}

private void OnPumpActivate(EntityUid uid, GasPressurePumpComponent pump, ActivateInWorldEvent args)
{
if (args.Handled || !args.Complex)
return;

if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;
[UsedImplicitly]
public sealed class GasPressurePumpSystem : SharedGasPressurePumpSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;

if (Transform(uid).Anchored)
{
_userInterfaceSystem.OpenUi(uid, GasPressurePumpUiKey.Key, actor.PlayerSession);
DirtyUI(uid, pump);
}
else
{
_popup.PopupCursor(Loc.GetString("comp-gas-pump-ui-needs-anchor"), args.User);
}
public override void Initialize()
{
base.Initialize();

args.Handled = true;
}
SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceUpdateEvent>(OnPumpUpdated);
}

private void OnToggleStatusMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpToggleStatusMessage args)
private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args)
{
if (!pump.Enabled
|| (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
|| !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
{
pump.Enabled = args.Enabled;
_adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium,
$"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}");
DirtyUI(uid, pump);
UpdateAppearance(uid, pump);
_ambientSoundSystem.SetAmbience(uid, false);
return;
}

private void OnOutputPressureChangeMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpChangeOutputPressureMessage args)
{
pump.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure);
_adminLogger.Add(LogType.AtmosPressureChanged, LogImpact.Medium,
$"{ToPrettyString(args.Actor):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa");
DirtyUI(uid, pump);

}
var outputStartingPressure = outlet.Air.Pressure;

private void DirtyUI(EntityUid uid, GasPressurePumpComponent? pump)
if (outputStartingPressure >= pump.TargetPressure)
{
if (!Resolve(uid, ref pump))
return;

_userInterfaceSystem.SetUiState(uid, GasPressurePumpUiKey.Key,
new GasPressurePumpBoundUserInterfaceState(EntityManager.GetComponent<MetaDataComponent>(uid).EntityName, pump.TargetPressure, pump.Enabled));
_ambientSoundSystem.SetAmbience(uid, false);
return; // No need to pump gas if target has been reached.
}

private void UpdateAppearance(EntityUid uid, GasPressurePumpComponent? pump = null, AppearanceComponent? appearance = null)
if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
{
if (!Resolve(uid, ref pump, ref appearance, false))
return;
// We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
var pressureDelta = pump.TargetPressure - outputStartingPressure;
var transferMoles = (pressureDelta * outlet.Air.Volume) / (inlet.Air.Temperature * Atmospherics.R);

bool pumpOn = pump.Enabled && (TryComp<ApcPowerReceiverComponent>(uid, out var power) && power.Powered);
_appearance.SetData(uid, PumpVisuals.Enabled, pumpOn, appearance);
var removed = inlet.Air.Remove(transferMoles);
_atmosphereSystem.Merge(outlet.Air, removed);
_ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
}
}
}
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Audio;
using Content.Shared.Examine;
using JetBrains.Annotations;
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Atmos.Visuals;
using Content.Shared.Audio;
using Content.Shared.Database;
12 changes: 0 additions & 12 deletions Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
Original file line number Diff line number Diff line change
@@ -67,15 +67,3 @@ public readonly struct AtmosDeviceUpdateEvent(float dt, Entity<GridAtmosphereCom
/// </summary>
public readonly Entity<MapAtmosphereComponent?>? Map = map;
}

/// <summary>
/// Raised directed on an atmos device when it is enabled.
/// </summary>
[ByRefEvent]
public record struct AtmosDeviceEnabledEvent;

/// <summary>
/// Raised directed on an atmos device when it is enabled.
/// </summary>
[ByRefEvent]
public record struct AtmosDeviceDisabledEvent;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Shared.Atmos.Piping.Components;
using JetBrains.Annotations;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Atmos.Piping.Trinary.Components;
using Content.Shared.Audio;
using Content.Shared.Database;
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Atmos.Piping.Trinary.Components;
using Content.Shared.Audio;
using Content.Shared.Database;
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Audio;
using JetBrains.Annotations;

Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Atmos.Piping.Unary;
using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Atmos.Visuals;
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Unary.Visuals;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Piping.Components;
using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Audio;
using Content.Shared.DeviceNetwork;
228 changes: 39 additions & 189 deletions Content.Server/Backmen/Arachne/ArachneSystem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Server.Backmen.Cocoon;
using Content.Shared.Backmen.Arachne;
using Content.Shared.Actions;
using Content.Shared.Coordinates.Helpers;
@@ -68,17 +69,8 @@ public override void Initialize()
base.Initialize();
SubscribeLocalEvent<ArachneComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ArachneComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ArachneComponent, GetVerbsEvent<InnateVerb>>(AddCocoonVerb);

SubscribeLocalEvent<CocoonComponent, EntInsertedIntoContainerMessage>(OnCocEntInserted);
SubscribeLocalEvent<CocoonComponent, EntRemovedFromContainerMessage>(OnCocEntRemoved);
SubscribeLocalEvent<CocoonComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<CocoonComponent, GetVerbsEvent<AlternativeVerb>>(AddSuccVerb);

SubscribeLocalEvent<SpinWebActionEvent>(OnSpinWeb);

SubscribeLocalEvent<ArachneComponent, ArachneWebDoAfterEvent>(OnWebDoAfter);
SubscribeLocalEvent<ArachneComponent, ArachneCocoonDoAfterEvent>(OnCocoonDoAfter);
}

private void OnShutdown(EntityUid uid, ArachneComponent component, ComponentShutdown args)
@@ -91,116 +83,10 @@ private void OnShutdown(EntityUid uid, ArachneComponent component, ComponentShut

private void OnInit(EntityUid uid, ArachneComponent component, ComponentInit args)
{
_actions.AddAction(uid, ref component.SpinWeb ,ActionSpinWeb);
}

private void AddCocoonVerb(EntityUid uid, ArachneComponent component, GetVerbsEvent<InnateVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

if (args.Target == uid)
return;

if (!TryComp<BloodstreamComponent>(args.Target, out var bloodstream))
return;

if (bloodstream.BloodReagent != component.WebBloodReagent)
return;

InnateVerb verb = new()
{
Act = () =>
{
StartCocooning(uid, component, args.Target);
},
Text = Loc.GetString("cocoon"),
Priority = 2
};
args.Verbs.Add(verb);
}

private void OnCocEntInserted(EntityUid uid, CocoonComponent component, EntInsertedIntoContainerMessage args)
{
_blindableSystem.UpdateIsBlind(args.Entity);
EnsureComp<StunnedComponent>(args.Entity);

if (TryComp<ReplacementAccentComponent>(args.Entity, out var currentAccent))
{
component.WasReplacementAccent = true;
component.OldAccent = currentAccent.Accent;
currentAccent.Accent = "mumble";
}
else
{
component.WasReplacementAccent = false;
var replacement = EnsureComp<ReplacementAccentComponent>(args.Entity);
replacement.Accent = "mumble";
}
}

private void OnCocEntRemoved(EntityUid uid, CocoonComponent component, EntRemovedFromContainerMessage args)
{
if (component.WasReplacementAccent && TryComp<ReplacementAccentComponent>(args.Entity, out var replacement))
{
replacement.Accent = component.OldAccent;
} else
{
RemComp<ReplacementAccentComponent>(args.Entity);
}

RemComp<StunnedComponent>(args.Entity);
_blindableSystem.UpdateIsBlind(args.Entity);
_actions.AddAction(uid, ref component.SpinWeb, ActionSpinWeb);
}

private void OnDamageChanged(EntityUid uid, CocoonComponent component, DamageChangedEvent args)
{
if (!args.DamageIncreased)
return;

if (args.DamageDelta == null)
return;

var body = _itemSlots.GetItemOrNull(uid, BodySlot);

if (body == null)
return;

var damage = args.DamageDelta * component.DamagePassthrough;
_damageableSystem.TryChangeDamage(body, damage);
}

private void AddSuccVerb(EntityUid uid, CocoonComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

if (!TryComp<BloodSuckerComponent>(args.User, out var sucker))
return;

if (!sucker.WebRequired)
return;

var victim = _itemSlots.GetItemOrNull(uid, BodySlot);

if (victim == null)
return;

if (!TryComp<BloodstreamComponent>(victim, out var stream))
return;

AlternativeVerb verb = new()
{
Act = () =>
{
_bloodSuckerSystem.StartSuccDoAfter(args.User, victim.Value, sucker, stream, false); // start doafter
},
Text = Loc.GetString("action-name-suck-blood"),
Icon = new SpriteSpecifier.Texture(new ("/Textures/Nyanotrasen/Icons/verbiconfangs.png")),
Priority = 2
};
args.Verbs.Add(verb);
}

private void OnEntRemoved(EntityUid uid, WebComponent web, EntRemovedFromContainerMessage args)
{
@@ -226,12 +112,19 @@ private void OnSpinWeb(SpinWebActionEvent args)
{
if (hunger.CurrentThreshold <= Shared.Nutrition.Components.HungerThreshold.Peckish)
{
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-hungry"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-hungry"),
args.Performer,
args.Performer,
Shared.Popups.PopupType.MediumCaution);
return;
}

if (thirst.CurrentThirstThreshold <= ThirstThreshold.Thirsty)
{
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-thirsty"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-thirsty"),
args.Performer,
args.Performer,
Shared.Popups.PopupType.MediumCaution);
return;
}
}
@@ -240,7 +133,10 @@ private void OnSpinWeb(SpinWebActionEvent args)

if (!HasComp<MapGridComponent>(_transform.GetGrid(coords)))
{
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-space"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-space"),
args.Performer,
args.Performer,
Shared.Popups.PopupType.MediumCaution);
return;
}

@@ -249,19 +145,31 @@ private void OnSpinWeb(SpinWebActionEvent args)
{
PhysicsComponent? physics = null; // We use this to check if it's impassable
if ((HasComp<WebComponent>(entity)) || // Is there already a web there?
((Resolve(entity, ref physics, false) && (physics.CollisionLayer & (int) CollisionGroup.Impassable) != 0) // Is it impassable?
&& !(TryComp<DoorComponent>(entity, out var door) && door.State != DoorState.Closed))) // Is it a door that's open and so not actually impassable?
((Resolve(entity, ref physics, false) &&
(physics.CollisionLayer & (int)CollisionGroup.Impassable) != 0) // Is it impassable?
&& !(TryComp<DoorComponent>(entity, out var door) &&
door.State != DoorState.Closed))) // Is it a door that's open and so not actually impassable?
{
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-blocked"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-blocked"),
args.Performer,
args.Performer,
Shared.Popups.PopupType.MediumCaution);
return;
}
}

_popupSystem.PopupEntity(Loc.GetString("spin-web-start-third-person", ("spider", Identity.Entity(args.Performer, EntityManager))), args.Performer,
Filter.PvsExcept(args.Performer).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)),
_popupSystem.PopupEntity(
Loc.GetString("spin-web-start-third-person", ("spider", Identity.Entity(args.Performer, EntityManager))),
args.Performer,
Filter.PvsExcept(args.Performer)
.RemoveWhereAttachedEntity(entity =>
!_examine.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)),
true,
Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spin-web-start-second-person"), args.Performer, args.Performer, Shared.Popups.PopupType.Medium);
_popupSystem.PopupEntity(Loc.GetString("spin-web-start-second-person"),
args.Performer,
args.Performer,
Shared.Popups.PopupType.Medium);

var ev = new ArachneWebDoAfterEvent(GetNetCoordinates(coords));
var doAfterArgs = new DoAfterArgs(EntityManager, args.Performer, arachne.WebDelay, ev, args.Performer)
@@ -272,34 +180,8 @@ private void OnSpinWeb(SpinWebActionEvent args)
_doAfter.TryStartDoAfter(doAfterArgs);
}

private void StartCocooning(EntityUid uid, ArachneComponent component, EntityUid target)
{
_popupSystem.PopupEntity(Loc.GetString("cocoon-start-third-person", ("target", Identity.Entity(target, EntityManager)), ("spider", Identity.Entity(uid, EntityManager))), uid,
// TODO: We need popup occlusion lmao
Filter.PvsExcept(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)),
true,
Shared.Popups.PopupType.MediumCaution);

_popupSystem.PopupEntity(Loc.GetString("cocoon-start-second-person", ("target", Identity.Entity(target, EntityManager))), uid, uid, Shared.Popups.PopupType.Medium);

var delay = component.CocoonDelay;

if (HasComp<KnockedDownComponent>(target))
delay *= component.CocoonKnockdownMultiplier;

// Is it good practice to use empty data just to disambiguate doafters
// Who knows, there's no docs!
var ev = new ArachneCocoonDoAfterEvent();

var args = new DoAfterArgs(EntityManager, uid, delay, ev, uid, target: target)
{
BreakOnMove = true,
};

_doAfter.TryStartDoAfter(args);
}

[ValidatePrototypeId<EntityPrototype>] private const string ArachneWeb = "ArachneWeb";

private void OnWebDoAfter(EntityUid uid, ArachneComponent component, ArachneWebDoAfterEvent args)
{
if (args.Handled || args.Cancelled)
@@ -310,47 +192,15 @@ private void OnWebDoAfter(EntityUid uid, ArachneComponent component, ArachneWebD
_thirstSystem.ModifyThirst(uid, thirst, -20);

Spawn(ArachneWeb, GetCoordinates(args.Coords).SnapToGrid());
_popupSystem.PopupEntity(Loc.GetString("spun-web-third-person", ("spider", Identity.Entity(uid, EntityManager))), uid,
Filter.PvsExcept(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)),
_popupSystem.PopupEntity(
Loc.GetString("spun-web-third-person", ("spider", Identity.Entity(uid, EntityManager))),
uid,
Filter.PvsExcept(uid)
.RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)),
true,
Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spun-web-second-person"), uid, uid, Shared.Popups.PopupType.Medium);
args.Handled = true;
}

private void OnCocoonDoAfter(EntityUid uid, ArachneComponent component, ArachneCocoonDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
return;

var spawnProto = HasComp<HumanoidAppearanceComponent>(args.Args.Target) ? "CocoonedHumanoid" : "CocoonSmall";
Transform(args.Args.Target.Value).AttachToGridOrMap();
var cocoon = Spawn(spawnProto, Transform(args.Args.Target.Value).Coordinates);

if (!TryComp<ItemSlotsComponent>(cocoon, out var slots))
return;

// todo: our species should use scale visuals probably...
// TODO: We need a client-accessible notion of scale influence here.
/* if (spawnProto == "CocoonedHumanoid" && TryComp<SpriteComponent>(args.Args.Target.Value, out var sprite)) */
/* { */
/* // why the fuck is this only available as a console command. */
/* _host.ExecuteCommand(null, "scale " + cocoon + " " + sprite.Scale.Y); */
if (TryComp<PhysicsComponent>(args.Args.Target.Value, out var physics))
{
var scale = Math.Clamp(1 / (35 / physics.FixturesMass), 0.35, 2.5);
_host.ExecuteCommand(null, "scale " + cocoon + " " + scale);
}

_inventorySystem.TryUnequip(args.Args.Target.Value, "ears", true, true);

_itemSlots.SetLock(cocoon, BodySlot, false, slots);
_itemSlots.TryInsert(cocoon, BodySlot, args.Args.Target.Value, args.Args.User);
_itemSlots.SetLock(cocoon, BodySlot, true, slots);

var impact = (spawnProto == "CocoonedHumanoid") ? LogImpact.High : LogImpact.Medium;

_adminLogger.Add(LogType.Action, impact, $"{ToPrettyString(args.Args.User):player} cocooned {ToPrettyString(args.Args.Target.Value):target}");
args.Handled = true;
}
}
12 changes: 0 additions & 12 deletions Content.Server/Backmen/Arachne/CocoonComponent.cs

This file was deleted.

1 change: 1 addition & 0 deletions Content.Server/Backmen/Arrivals/ArrivalsProtectSystem.cs
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
using Content.Server.Emp;
using Content.Server.Gravity;
using Content.Server.Power.EntitySystems;
using Content.Shared.Atmos.Components;
using Content.Shared.Backmen.Arrivals;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.EntitySystems;
7 changes: 4 additions & 3 deletions Content.Server/Backmen/Blob/BlobObserverSystem.cs
Original file line number Diff line number Diff line change
@@ -206,14 +206,15 @@ private void OnChemSelected(EntityUid uid, BlobObserverComponent component, Blob
{
if (component.Core == null || !TryComp<BlobCoreComponent>(component.Core.Value, out var blobCoreComponent))
return;

if (component.SelectedChemId == args.SelectedId)
return;

if (!_blobCoreSystem.TryUseAbility(component.Core.Value, blobCoreComponent.SwapChemCost))
return;

if (!ChangeChem(uid, args.SelectedId, component))
return;

_blobCoreSystem.TryUseAbility(component.Core.Value, blobCoreComponent.SwapChemCost);
}

private bool ChangeChem(EntityUid uid, BlobChemType newChem, BlobObserverComponent component)
105 changes: 0 additions & 105 deletions Content.Server/Backmen/Mood/MoodComponent.cs
Original file line number Diff line number Diff line change
@@ -5,109 +5,4 @@

namespace Content.Server.Backmen.Mood;

[RegisterComponent]
public sealed partial class MoodComponent : Component
{
[DataField]
public float CurrentMoodLevel;

[DataField]
public MoodThreshold CurrentMoodThreshold;

[DataField]
public MoodThreshold LastThreshold;

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, string> CategorisedEffects = new();

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, float> UncategorisedEffects = new();

/// <summary>
/// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral).
/// Change this ONLY BY 0.001 AT A TIME.
/// </summary>
[DataField]
public float SpeedBonusGrowth = 1.003f;

/// <summary>
/// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric.
/// </summary>
[DataField]
public float MinimumSpeedModifier = 0.75f;

/// <summary>
/// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence.
/// </summary>
[DataField]
public float MaximumSpeedModifier = 1.15f;

[DataField]
public float IncreaseCritThreshold = 1.2f;

[DataField]
public float DecreaseCritThreshold = 0.9f;

[ViewVariables(VVAccess.ReadOnly)]
public FixedPoint2 CritThresholdBeforeModify;

[DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, float>))]
public Dictionary<MoodThreshold, float> MoodThresholds = new()
{
{ MoodThreshold.Perfect, 100f },
{ MoodThreshold.Exceptional, 80f },
{ MoodThreshold.Great, 70f },
{ MoodThreshold.Good, 60f },
{ MoodThreshold.Neutral, 50f },
{ MoodThreshold.Meh, 40f },
{ MoodThreshold.Bad, 30f },
{ MoodThreshold.Terrible, 20f },
{ MoodThreshold.Horrible, 10f },
{ MoodThreshold.Dead, 0f }
};

[DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, ProtoId<AlertPrototype>>))]
public Dictionary<MoodThreshold, ProtoId<AlertPrototype>> MoodThresholdsAlerts = new()
{
{ MoodThreshold.Dead, "MoodDead" },
{ MoodThreshold.Horrible, "MoodHorrible" },
{ MoodThreshold.Terrible, "MoodTerrible" },
{ MoodThreshold.Bad, "MoodBad" },
{ MoodThreshold.Meh, "MoodMeh" },
{ MoodThreshold.Neutral, "MoodNeutral" },
{ MoodThreshold.Good, "MoodGood" },
{ MoodThreshold.Great, "MoodGreat" },
{ MoodThreshold.Exceptional, "MoodExceptional" },
{ MoodThreshold.Perfect, "MoodPerfect" },
{ MoodThreshold.Insane, "MoodInsane" }
};

/// <summary>
/// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%.
/// </summary>
[DataField(customTypeSerializer: typeof(DictionarySerializer<string, float>))]
public Dictionary<string, float> HealthMoodEffectsThresholds = new()
{
{ "HealthHeavyDamage", 0.8f },
{ "HealthSevereDamage", 0.5f },
{ "HealthOkayDamage", 0.35f },
{ "HealthLightDamage", 0.1f },
{ "HealthNoDamage", 0.05f }
};
}

[Serializable]
public enum MoodThreshold : ushort
{
Insane = 1,
Horrible = 2,
Terrible = 3,
Bad = 4,
Meh = 5,
Neutral = 6,
Good = 7,
Great = 8,
Exceptional = 9,
Perfect = 10,
Dead = 0
}
46 changes: 26 additions & 20 deletions Content.Server/Backmen/Mood/MoodSystem.cs
Original file line number Diff line number Diff line change
@@ -155,8 +155,12 @@ private void OnRefreshMoveSpeed(EntityUid uid, MoodComponent component, RefreshM

private void OnTraitStartup(EntityUid uid, MoodModifyTraitComponent component, ComponentStartup args)
{
if (component.MoodId != null)
RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}"));
if (!TryComp<MoodComponent>(uid, out var mood))
return;

mood.GoodMoodMultiplier = component.GoodMoodMultiplier;
mood.BadMoodMultiplier = component.BadMoodMultiplier;
RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}"));
}

private void OnMoodEffect(EntityUid uid, MoodComponent component, MoodEffectEvent args)
@@ -308,12 +312,18 @@ private void RefreshMood(EntityUid uid, MoodComponent component)
if (!_prototypeManager.TryIndex<MoodEffectPrototype>(protoId, out var prototype))
continue;

amount += prototype.MoodChange;
if (prototype.MoodChange > 0)
amount += prototype.MoodChange * component.GoodMoodMultiplier;
else
amount += prototype.MoodChange * component.BadMoodMultiplier;
}

foreach (var (_, value) in component.UncategorisedEffects)
{
amount += value;
if (value > 0)
amount += value * component.GoodMoodMultiplier;
else
amount += value * component.BadMoodMultiplier;
}

SetMood(uid, amount, component, refresh: true);
@@ -326,7 +336,6 @@ private void OnInit(EntityUid uid, MoodComponent component, ComponentStartup arg
&& _mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var critThreshold, mobThresholdsComponent))
component.CritThresholdBeforeModify = critThreshold.Value;

EnsureComp<NetMoodComponent>(uid);
RefreshMood(uid, component);
}

@@ -359,12 +368,8 @@ private void SetMood(EntityUid uid, float amount, MoodComponent? component = nul

component.CurrentMoodLevel = newMoodLevel;

if (TryComp<NetMoodComponent>(uid, out var mood))
{
mood.CurrentMoodLevel = component.CurrentMoodLevel;
mood.NeutralMoodThreshold = component.MoodThresholds.GetValueOrDefault(MoodThreshold.Neutral);
}

component.NeutralMoodThreshold = component.MoodThresholds.GetValueOrDefault(MoodThreshold.Neutral);
Dirty(uid, component);
UpdateCurrentThreshold(uid, component);
}

@@ -388,10 +393,10 @@ private void DoMoodThresholdsEffects(EntityUid uid, MoodComponent? component = n
|| component.CurrentMoodThreshold == component.LastThreshold && !force)
return;

var modifier = GetMovementThreshold(component.CurrentMoodThreshold);
var modifier = GetMovementThreshold(component.CurrentMoodThreshold, component);

// Modify mob stats
if (modifier != GetMovementThreshold(component.LastThreshold))
if (modifier != GetMovementThreshold(component.LastThreshold, component))
{
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
SetCritThreshold(uid, component, modifier);
@@ -451,14 +456,15 @@ private MoodThreshold GetMoodThreshold(MoodComponent component, float? moodLevel
return result;
}

private int GetMovementThreshold(MoodThreshold threshold)
private int GetMovementThreshold(MoodThreshold threshold, MoodComponent component)
{
return threshold switch
{
>= MoodThreshold.Good => 1,
<= MoodThreshold.Meh => -1,
_ => 0
};
if (threshold >= component.BuffsMoodThreshold)
return 1;

if (threshold <= component.ConsMoodThreshold)
return -1;

return 0;
}

private string GetMoodName(MoodThreshold threshold)
58 changes: 0 additions & 58 deletions Content.Server/Backmen/OfferItem/OfferItemSystem.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Content.Server/Backmen/Research/Oracle/OracleSystem.cs
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ public sealed class OracleSystem : EntitySystem
[ValidatePrototypeId<ReagentPrototype>]
public readonly IReadOnlyList<ProtoId<ReagentPrototype>> RewardReagents = new ProtoId<ReagentPrototype>[]
{
"LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "Wine", "Blood", "Ichor", "FluorosulfuricAcid"
"LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "LotophagoiOil", "Wine", "Blood", "Ichor", "SlermQueenPlus"
};

[ViewVariables(VVAccess.ReadWrite)]
46 changes: 29 additions & 17 deletions Content.Server/Backmen/Surgery/SurgerySystem.cs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
using Content.Shared.Backmen.Surgery.Tools;
using Content.Shared.Bed.Sleep;
using Content.Shared.Medical.Surgery;
using Content.Shared.Verbs;

namespace Content.Server.Backmen.Surgery;

@@ -42,7 +43,7 @@ public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<SurgeryToolComponent, AfterInteractEvent>(OnToolAfterInteract);
SubscribeLocalEvent<SurgeryToolComponent, GetVerbsEvent<UtilityVerb>>(OnUtilityVerb);
SubscribeLocalEvent<SurgeryTargetComponent, SurgeryStepDamageEvent>(OnSurgeryStepDamage);
// You might be wondering "why aren't we using StepEvent for these two?" reason being that StepEvent fires off regardless of success on the previous functions
// so this would heal entities even if you had a used or incorrect organ.
@@ -101,30 +102,41 @@ private void SetDamage(EntityUid body,
targetPart: _body.GetTargetBodyPart(partComp));
}

private void OnToolAfterInteract(Entity<SurgeryToolComponent> ent, ref AfterInteractEvent args)
private void AttemptStartSurgery(Entity<SurgeryToolComponent> ent, EntityUid user, EntityUid target)
{
var user = args.User;
if (args.Handled
|| !args.CanReach
|| args.Target == null
|| !HasComp<SurgeryTargetComponent>(args.Target)
|| !TryComp<SurgeryTargetComponent>(args.User, out var surgery)
|| !surgery.CanOperate
|| !IsLyingDown(args.Target.Value, args.User))
{
if (!IsLyingDown(target, user))
return;
}

if (user == args.Target && !_config.GetCVar(Shared.Backmen.CCVar.CCVars.CanOperateOnSelf))
if (user == target && !_config.GetCVar(Shared.Backmen.CCVar.CCVars.CanOperateOnSelf))
{
_popup.PopupEntity(Loc.GetString("surgery-error-self-surgery"), user, user);
return;
}

args.Handled = true;
_ui.OpenUi(args.Target.Value, SurgeryUIKey.Key, user);
Log.Debug("UI opened");
RefreshUI(args.Target.Value);
_ui.OpenUi(target, SurgeryUIKey.Key, user);
RefreshUI(target);
}

private void OnUtilityVerb(Entity<SurgeryToolComponent> ent, ref GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanInteract
|| !args.CanAccess
|| !HasComp<SurgeryTargetComponent>(args.Target))
return;

var user = args.User;
var target = args.Target;

var verb = new UtilityVerb()
{
Act = () => AttemptStartSurgery(ent, user, target),
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/"), "scalpel"),
Text = Loc.GetString("surgery-verb-text"),
Message = Loc.GetString("surgery-verb-message"),
DoContactInteraction = true
};

args.Verbs.Add(verb);
}

private void OnSurgeryStepDamage(Entity<SurgeryTargetComponent> ent, ref SurgeryStepDamageEvent args) =>
Original file line number Diff line number Diff line change
@@ -7,5 +7,11 @@ namespace Content.Server.Backmen.Traits.Assorted;
public sealed partial class MoodModifyTraitComponent : Component
{
[DataField]
public string? MoodId = null;
public string? MoodId;

[DataField]
public float GoodMoodMultiplier = 1.0f;

[DataField]
public float BadMoodMultiplier = 1.0f;
}
5 changes: 4 additions & 1 deletion Content.Server/Body/Commands/AddHandCommand.cs
Original file line number Diff line number Diff line change
@@ -133,7 +133,10 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)
if (attachAt == default)
attachAt = bodySystem.GetBodyChildren(entity, body).First();

var slotId = part.GetHashCode().ToString();
// Shitmed Change Start
var slotId = $"{part.Symmetry.ToString().ToLower()} {part.GetHashCode().ToString()}";
part.SlotId = part.GetHashCode().ToString();
// Shitmed Change End

if (!bodySystem.TryCreatePartSlotAndAttach(attachAt.Id, slotId, hand, BodyPartType.Hand, attachAt.Component, part))
{
9 changes: 8 additions & 1 deletion Content.Server/Body/Commands/AttachBodyPartCommand.cs
Original file line number Diff line number Diff line change
@@ -98,8 +98,15 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

var slotId = $"AttachBodyPartVerb-{partUid}";
// Shitmed Change Start
var slotId = "";
if (part.Symmetry != BodyPartSymmetry.None)
slotId = $"{part.Symmetry.ToString().ToLower()} {part.GetHashCode().ToString()}";
else
slotId = $"{part.GetHashCode().ToString()}";

part.SlotId = part.GetHashCode().ToString();
// Shitmed Change End
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (body.RootContainer.ContainedEntity != null)
{
2 changes: 0 additions & 2 deletions Content.Server/Content.Server.csproj
Original file line number Diff line number Diff line change
@@ -29,8 +29,6 @@
<ItemGroup>
<Folder Include="Tools\Systems\" />
<Folder Include="Objectives\Interfaces\" />
<Folder Include="_Shitmed\Body\Organ\" />
<Folder Include="_Shitmed\Body\Systems\" />
</ItemGroup>
<ItemGroup>
<Compile Update="Backmen\Species\Shadowkin\Systems\ShadowkinPowerSystem.Darken.cs">
4 changes: 4 additions & 0 deletions Content.Server/DeviceLinking/Systems/LogicGateSystem.cs
Original file line number Diff line number Diff line change
@@ -102,10 +102,12 @@ private void OnSignalReceived(EntityUid uid, LogicGateComponent comp, ref Signal
if (args.Port == comp.InputPortA)
{
comp.StateA = state;
_appearance.SetData(uid, LogicGateVisuals.InputA, state == SignalState.High); //If A == High => Sets input A sprite to True
}
else if (args.Port == comp.InputPortB)
{
comp.StateB = state;
_appearance.SetData(uid, LogicGateVisuals.InputB, state == SignalState.High); //If B == High => Sets input B sprite to True
}

UpdateOutput(uid, comp);
@@ -143,6 +145,8 @@ private void UpdateOutput(EntityUid uid, LogicGateComponent comp)
break;
}

_appearance.SetData(uid, LogicGateVisuals.Output, output);

// only send a payload if it actually changed
if (output != comp.LastOutput)
{
43 changes: 41 additions & 2 deletions Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Map.Events;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

@@ -66,6 +66,42 @@ public override void Initialize()
SubscribeLocalEvent<NetworkConfiguratorComponent, BoundUserInterfaceCheckRangeEvent>(OnUiRangeCheck);

SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);

SubscribeLocalEvent<BeforeSaveEvent>(OnMapSave);
}

private void OnMapSave(BeforeSaveEvent ev)
{
var enumerator = AllEntityQuery<NetworkConfiguratorComponent>();
while (enumerator.MoveNext(out var uid, out var conf))
{
if (CompOrNull<TransformComponent>(conf.ActiveDeviceList)?.MapUid != ev.Map)
continue;

// The linked device list is (probably) being saved. Make sure that the configurator is also being saved
// (i.e., not in the hands of a mapper/ghost). In the future, map saving should raise a separate event
// containing a set of all entities that are about to be saved, which would make checking this much easier.
// This is a shitty bandaid, and will force close the UI during auto-saves.
// TODO Map serialization refactor

var xform = Transform(uid);
if (xform.MapUid == ev.Map && IsSaveable(uid))
continue;

_uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure);
DebugTools.AssertNull(conf.ActiveDeviceList);
}

bool IsSaveable(EntityUid uid)
{
while (uid.IsValid())
{
if (Prototype(uid)?.MapSavable == false)
return false;
uid = Transform(uid).ParentUid;
}
return true;
}
}

private void OnUiRangeCheck(Entity<NetworkConfiguratorComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
@@ -485,6 +521,9 @@ private void OpenDeviceListUi(EntityUid configuratorUid, EntityUid? targetUid, E
if (!TryComp(targetUid, out DeviceListComponent? list))
return;

if (TryComp(configurator.ActiveDeviceList, out DeviceListComponent? oldList))
oldList.Configurators.Remove(configuratorUid);

list.Configurators.Add(configuratorUid);
configurator.ActiveDeviceList = targetUid;
Dirty(configuratorUid, configurator);
@@ -758,7 +797,7 @@ private void OnConfigButtonPressed(EntityUid uid, NetworkConfiguratorComponent c
{
if (query.TryGetComponent(device, out var comp))
{
component.Devices[addr] = device;
component.Devices.Add(addr, device);
comp.Configurators.Add(uid);
}
}
3 changes: 2 additions & 1 deletion Content.Server/Dragon/DragonSystem.cs
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ public sealed partial class DragonSystem : EntitySystem
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;

private EntityQuery<CarpRiftsConditionComponent> _objQuery;
@@ -156,7 +157,7 @@ private void OnSpawnRift(EntityUid uid, DragonComponent component, DragonSpawnRi
}

// cant put a rift on solars
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
{
if (!tile.IsSpace(_tileDef))
continue;
62 changes: 29 additions & 33 deletions Content.Server/Fluids/EntitySystems/DrainSystem.cs
Original file line number Diff line number Diff line change
@@ -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;

@@ -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);
}
}
}

9 changes: 7 additions & 2 deletions Content.Server/Fluids/EntitySystems/PuddleSystem.cs
Original file line number Diff line number Diff line change
@@ -340,7 +340,7 @@ private void OnSolutionUpdate(Entity<PuddleComponent> entity, ref SolutionContai

_deletionQueue.Remove(entity);
UpdateSlip(entity, entity.Comp, args.Solution);
UpdateSlow(entity, args.Solution);
UpdateSlow(entity, args.Solution); // backmen: footsteps
UpdateEvaporation(entity, args.Solution);
UpdateAppearance(entity, entity.Comp);
}
@@ -421,8 +421,13 @@ private void UpdateSlip(EntityUid entityUid, PuddleComponent component, Solution
}
}

private void UpdateSlow(EntityUid uid, Solution solution)
private void UpdateSlow(Entity<PuddleComponent> uid, Solution solution) // backmen: footsteps
{
// start-backmen: footsteps
if (!uid.Comp.ViscosityAffectsMovement)
return;
// end-backmen: footsteps

var maxViscosity = 0f;
foreach (var (reagent, _) in solution.Contents)
{
6 changes: 4 additions & 2 deletions Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.GridPreloader;
using Content.Server.StationEvents.Events;
using Content.Shared.GameTicking.Components;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;

namespace Content.Server.GameTicking.Rules;

public sealed class LoadMapRuleSystem : GameRuleSystem<LoadMapRuleComponent>
public sealed class LoadMapRuleSystem : StationEventSystem<LoadMapRuleComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly MapSystem _map = default!;
@@ -75,5 +75,7 @@ protected override void Added(EntityUid uid, LoadMapRuleComponent comp, GameRule

var ev = new RuleLoadedGridsEvent(mapId, grids);
RaiseLocalEvent(uid, ref ev);

base.Added(uid, comp, rule, args);
}
}
6 changes: 3 additions & 3 deletions Content.Server/Ghost/Roles/MakeRaffledGhostRoleCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Content.Server.Administration;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Raffles;
@@ -77,13 +77,13 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)

if (isProto)
{
if (!_protoManager.TryIndex<GhostRoleRaffleSettingsPrototype>(args[4], out var proto))
if (!_protoManager.TryIndex<GhostRoleRaffleSettingsPrototype>(args[3], out var proto))
{
var validProtos = string.Join(", ",
_protoManager.EnumeratePrototypes<GhostRoleRaffleSettingsPrototype>().Select(p => p.ID)
);

shell.WriteLine($"{args[4]} is not a valid raffle settings prototype. Valid options: {validProtos}");
shell.WriteLine($"{args[3]} is not a valid raffle settings prototype. Valid options: {validProtos}");
return;
}

3 changes: 2 additions & 1 deletion Content.Server/Medical/DefibrillatorSystem.cs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
using Content.Server.PowerCell;
using Content.Server.Traits.Assorted;
using Content.Shared.Backmen.Chat;
using Content.Shared.Backmen.Targeting;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
@@ -201,7 +202,7 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo
else
{
if (_mobState.IsDead(target, mob))
_damageable.TryChangeDamage(target, component.ZapHeal, true, origin: uid);
_damageable.TryChangeDamage(target, component.ZapHeal, true, origin: uid, targetPart: TargetBodyPart.Torso); // backmen: surgery

if (_mobThreshold.TryGetThresholdForState(target, MobState.Dead, out var threshold) &&
TryComp<DamageableComponent>(target, out var damageableComponent) &&
3 changes: 2 additions & 1 deletion Content.Server/Nuke/NukeSystem.cs
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ public sealed class NukeSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
@@ -190,7 +191,7 @@ private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component,

var worldPos = _transform.GetWorldPosition(xform);

foreach (var tile in grid.GetTilesIntersecting(new Circle(worldPos, component.RequiredFloorRadius), false))
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(worldPos, component.RequiredFloorRadius), false))
{
if (!tile.IsSpace(_tileDefManager))
continue;
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ private async Task PostGen(BiomeDunGen dunGen, DungeonData data, Dungeon dungeon
}
}

if (tile is not null && biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile.Value, seed, _grid, out var entityProto))
if (biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile ?? tileRef.Value.Tile, seed, _grid, out var entityProto))
{
var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector));
var xform = xformQuery.Get(ent);
5 changes: 3 additions & 2 deletions Content.Server/Projectiles/ProjectileSystem.cs
Original file line number Diff line number Diff line change
@@ -45,7 +45,6 @@ private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref St
RaiseLocalEvent(uid, ref ev);

var otherName = ToPrettyString(target);
var direction = args.OurBody.LinearVelocity.Normalized();
var modifiedDamage = _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: component.Shooter);
var deleted = Deleted(target);

@@ -64,7 +63,9 @@ private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref St
if (!deleted)
{
_guns.PlayImpactSound(target, modifiedDamage, component.SoundHit, component.ForceSound);
_sharedCameraRecoil.KickCamera(target, direction);

if (!args.OurBody.LinearVelocity.IsLengthZero())
_sharedCameraRecoil.KickCamera(target, args.OurBody.LinearVelocity.Normalized());
}

component.DamagedEntity = true;
5 changes: 3 additions & 2 deletions Content.Server/Respawn/SpecialRespawnSystem.cs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
@@ -105,7 +106,7 @@ private void OnTermination(EntityUid uid, SpecialRespawnComponent component, ref

var found = false;

foreach (var tile in grid.GetTilesIntersecting(circle))
foreach (var tile in _map.GetTilesIntersecting(entityGridUid.Value, grid, circle))
{
if (tile.IsSpace(_tileDefinitionManager)
|| _turf.IsTileBlocked(tile, CollisionGroup.MobMask)
@@ -176,7 +177,7 @@ public bool TryFindRandomTile(EntityUid targetGrid, EntityUid targetMap, int max
var mapTarget = grid.WorldToTile(mapPos);
var circle = new Circle(mapPos, 2);

foreach (var newTileRef in grid.GetTilesIntersecting(circle))
foreach (var newTileRef in _map.GetTilesIntersecting(targetGrid, grid, circle))
{
if (newTileRef.IsSpace(_tileDefinitionManager) || _turf.IsTileBlocked(newTileRef, CollisionGroup.MobMask) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget))
continue;
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ public sealed partial class RevenantSystem
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;

private void InitializeAbilities()
{
@@ -228,8 +229,12 @@ private void OnDefileAction(EntityUid uid, RevenantComponent component, Revenant
var xform = Transform(uid);
if (!TryComp<MapGridComponent>(xform.GridUid, out var map))
return;
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray();
var tiles = _mapSystem.GetTilesIntersecting(
xform.GridUid.Value,
map,
Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
new Vector2(component.DefileRadius * 2, component.DefileRadius)))
.ToArray();

_random.Shuffle(tiles);

2 changes: 1 addition & 1 deletion Content.Server/Salvage/SpawnSalvageMissionJob.cs
Original file line number Diff line number Diff line change
@@ -193,7 +193,7 @@ protected override async Task<bool> Process()

List<Vector2i> reservedTiles = new();

foreach (var tile in grid.GetTilesIntersecting(new Circle(Vector2.Zero, landingPadRadius), false))
foreach (var tile in _map.GetTilesIntersecting(mapUid, grid, new Circle(Vector2.Zero, landingPadRadius), false))
{
if (!_biome.TryGetBiomeTile(mapUid, grid, tile.GridIndices, out _))
continue;
Original file line number Diff line number Diff line change
@@ -308,7 +308,7 @@ public void ConsumeTilesInRange(EntityUid uid, float range, TransformComponent?
foreach (var grid in grids)
{
// TODO: Remover grid.Owner when this iterator returns entityuids as well.
AttemptConsumeTiles(uid, grid.Comp.GetTilesIntersecting(circle), grid, grid, eventHorizon);
AttemptConsumeTiles(uid, _mapSystem.GetTilesIntersecting(grid.Owner, grid.Comp, circle), grid, grid, eventHorizon);
}
}

10 changes: 5 additions & 5 deletions Content.Server/StationEvents/EventManagerSystem.cs
Original file line number Diff line number Diff line change
@@ -148,20 +148,20 @@ public bool TryBuildLimitedEvents(EntityTableSelector limitedEventsTable, out Di
return null;
}

var sumOfWeights = 0;
var sumOfWeights = 0.0f;

foreach (var stationEvent in availableEvents.Values)
{
sumOfWeights += (int) stationEvent.Weight;
sumOfWeights += stationEvent.Weight;
}

sumOfWeights = _random.Next(sumOfWeights);
sumOfWeights = _random.NextFloat(sumOfWeights);

foreach (var (proto, stationEvent) in availableEvents)
{
sumOfWeights -= (int) stationEvent.Weight;
sumOfWeights -= stationEvent.Weight;

if (sumOfWeights <= 0)
if (sumOfWeights <= 0.0f)
{
return proto.ID;
}
2 changes: 1 addition & 1 deletion Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
@@ -212,7 +212,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?

var hitName = ToPrettyString(hitEntity);
if (dmg != null)
dmg = Damageable.TryChangeDamage(hitEntity, dmg, origin: user);
dmg = Damageable.TryChangeDamage(hitEntity, dmg, origin: user, canEvade: true); // backmen: surgery

// check null again, as TryChangeDamage returns modified damage values
if (dmg != null)
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
using Content.Shared.Maps;
using Content.Shared.Physics;
using Content.Shared.Throwing;
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
@@ -17,7 +16,8 @@ public sealed class ThrowArtifactSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;

/// <inheritdoc/>
public override void Initialize()
@@ -30,7 +30,9 @@ private void OnActivated(EntityUid uid, ThrowArtifactComponent component, Artifa
var xform = Transform(uid);
if (TryComp<MapGridComponent>(xform.GridUid, out var grid))
{
var tiles = grid.GetTilesIntersecting(
var tiles = _mapSystem.GetTilesIntersecting(
xform.GridUid.Value,
grid,
Box2.CenteredAround(_transform.GetWorldPosition(xform), new Vector2(component.Range * 2, component.Range)));

foreach (var tile in tiles)
8 changes: 6 additions & 2 deletions Content.Shared/Anomaly/SharedAnomalySystem.cs
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ public abstract class SharedAnomalySystem : EntitySystem
[Dependency] protected readonly SharedPopupSystem Popup = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;

public override void Initialize()
{
@@ -358,8 +359,11 @@ public override void Update(float frameTime)
var amount = (int) (MathHelper.Lerp(settings.MinAmount, settings.MaxAmount, severity * stability * powerModifier) + 0.5f);

var localpos = xform.Coordinates.Position;
var tilerefs = grid.GetLocalTilesIntersecting(
new Box2(localpos + new Vector2(-settings.MaxRange, -settings.MaxRange), localpos + new Vector2(settings.MaxRange, settings.MaxRange))).ToList();
var tilerefs = _map.GetLocalTilesIntersecting(
xform.GridUid.Value,
grid,
new Box2(localpos + new Vector2(-settings.MaxRange, -settings.MaxRange), localpos + new Vector2(settings.MaxRange, settings.MaxRange)))
.ToList();

if (tilerefs.Count == 0)
return null;
Original file line number Diff line number Diff line change
@@ -1,47 +1,21 @@
using Robust.Shared.Serialization;

namespace Content.Shared.Atmos.Piping.Binary.Components
{
[Serializable, NetSerializable]
public enum GasPressurePumpUiKey
{
Key,
}

[Serializable, NetSerializable]
public sealed class GasPressurePumpBoundUserInterfaceState : BoundUserInterfaceState
{
public string PumpLabel { get; }
public float OutputPressure { get; }
public bool Enabled { get; }

public GasPressurePumpBoundUserInterfaceState(string pumpLabel, float outputPressure, bool enabled)
{
PumpLabel = pumpLabel;
OutputPressure = outputPressure;
Enabled = enabled;
}
}
namespace Content.Shared.Atmos.Piping.Binary.Components;

[Serializable, NetSerializable]
public sealed class GasPressurePumpToggleStatusMessage : BoundUserInterfaceMessage
{
public bool Enabled { get; }

public GasPressurePumpToggleStatusMessage(bool enabled)
{
Enabled = enabled;
}
}
[Serializable, NetSerializable]
public enum GasPressurePumpUiKey : byte
{
Key,
}

[Serializable, NetSerializable]
public sealed class GasPressurePumpChangeOutputPressureMessage : BoundUserInterfaceMessage
{
public float Pressure { get; }
[Serializable, NetSerializable]
public sealed class GasPressurePumpToggleStatusMessage(bool enabled) : BoundUserInterfaceMessage
{
public bool Enabled { get; } = enabled;
}

public GasPressurePumpChangeOutputPressureMessage(float pressure)
{
Pressure = pressure;
}
}
[Serializable, NetSerializable]
public sealed class GasPressurePumpChangeOutputPressureMessage(float pressure) : BoundUserInterfaceMessage
{
public float Pressure { get; } = pressure;
}
2 changes: 1 addition & 1 deletion Content.Shared/Backmen/Disease/DiseasePrototype.cs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ public sealed partial class DiseasePrototype : IPrototype, IInheritingPrototype
public string ID { get; private set; } = default!;

[DataField("name")]
public string Name { get; private set; } = string.Empty;
public LocId Name { get; private set; } = string.Empty;

[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<DiseasePrototype>))]
public string[]? Parents { get; private set; }
3 changes: 2 additions & 1 deletion Content.Shared/Backmen/Magic/BkmMagicSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Shared.Backmen.Magic.Events;
using Content.Shared.Backmen.Targeting;
using Content.Shared.Body.Components;
using Content.Shared.Damage;

@@ -22,6 +23,6 @@ private void OnHealSpell(HealSpellEvent ev)
if (!HasComp<BodyComponent>(ev.Target))
return;

DamageableSystem.TryChangeDamage(ev.Target, ev.HealAmount, true, origin: ev.Target);
DamageableSystem.TryChangeDamage(ev.Target, ev.HealAmount, true, origin: ev.Target, targetPart: TargetBodyPart.All); // backmen: surgery
}
}
134 changes: 128 additions & 6 deletions Content.Shared/Backmen/Mood/SharedMoodComponent.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,137 @@
using Content.Shared.Alert;
using Content.Shared.FixedPoint;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;

namespace Content.Shared.Backmen.Mood;

/// <summary>
/// This component exists solely to network CurrentMoodLevel, so that clients can make use of its value for math Prediction.
/// All mood logic is otherwise handled by the Server, and the client is not allowed to know the identity of its mood events.
/// </summary>
[RegisterComponent, AutoGenerateComponentState]
public sealed partial class NetMoodComponent : Component
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class MoodComponent : Component
{
public override bool SendOnlyToOwner => true;

[DataField, AutoNetworkedField]
public float CurrentMoodLevel;

[DataField, AutoNetworkedField]
public float NeutralMoodThreshold;

[DataField]
public MoodThreshold CurrentMoodThreshold;

[DataField]
public MoodThreshold LastThreshold;

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, string> CategorisedEffects = new();

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, float> UncategorisedEffects = new();

/// <summary>
/// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral).
/// Change this ONLY BY 0.001 AT A TIME.
/// </summary>
[DataField]
public float SpeedBonusGrowth = 1.003f;

/// <summary>
/// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric.
/// </summary>
[DataField]
public float MinimumSpeedModifier = 0.90f;

/// <summary>
/// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence.
/// </summary>
[DataField]
public float MaximumSpeedModifier = 1.15f;

[DataField]
public float IncreaseCritThreshold = 1.2f;

[DataField]
public float DecreaseCritThreshold = 0.9f;

/// <summary>
/// Multiplier for positive mood effects.
/// </summary>
[DataField]
public float GoodMoodMultiplier = 1.0f;

/// <summary>
/// Multiplier for negative mood effects.
/// </summary>
[DataField]
public float BadMoodMultiplier = 1.0f;

[DataField]
public MoodThreshold BuffsMoodThreshold = MoodThreshold.Good;

[DataField]
public MoodThreshold ConsMoodThreshold = MoodThreshold.Bad;

[ViewVariables(VVAccess.ReadOnly)]
public FixedPoint2 CritThresholdBeforeModify;

[DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, float>))]
public Dictionary<MoodThreshold, float> MoodThresholds = new()
{
{ MoodThreshold.Perfect, 100f },
{ MoodThreshold.Exceptional, 80f },
{ MoodThreshold.Great, 70f },
{ MoodThreshold.Good, 60f },
{ MoodThreshold.Neutral, 50f },
{ MoodThreshold.Meh, 40f },
{ MoodThreshold.Bad, 30f },
{ MoodThreshold.Terrible, 20f },
{ MoodThreshold.Horrible, 10f },
{ MoodThreshold.Dead, 0f }
};

[DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, ProtoId<AlertPrototype>>))]
public Dictionary<MoodThreshold, ProtoId<AlertPrototype>> MoodThresholdsAlerts = new()
{
{ MoodThreshold.Dead, "MoodDead" },
{ MoodThreshold.Horrible, "MoodHorrible" },
{ MoodThreshold.Terrible, "MoodTerrible" },
{ MoodThreshold.Bad, "MoodBad" },
{ MoodThreshold.Meh, "MoodMeh" },
{ MoodThreshold.Neutral, "MoodNeutral" },
{ MoodThreshold.Good, "MoodGood" },
{ MoodThreshold.Great, "MoodGreat" },
{ MoodThreshold.Exceptional, "MoodExceptional" },
{ MoodThreshold.Perfect, "MoodPerfect" },
{ MoodThreshold.Insane, "MoodInsane" }
};

/// <summary>
/// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%.
/// </summary>
[DataField(customTypeSerializer: typeof(DictionarySerializer<string, float>))]
public Dictionary<string, float> HealthMoodEffectsThresholds = new()
{
{ "HealthHeavyDamage", 0.8f },
{ "HealthSevereDamage", 0.5f },
{ "HealthOkayDamage", 0.35f },
{ "HealthLightDamage", 0.1f },
{ "HealthNoDamage", 0.05f }
};
}

[Serializable]
public enum MoodThreshold : ushort
{
Insane = 1,
Horrible = 2,
Terrible = 3,
Bad = 4,
Meh = 5,
Neutral = 6,
Good = 7,
Great = 8,
Exceptional = 9,
Perfect = 10,
Dead = 0
}
26 changes: 0 additions & 26 deletions Content.Shared/Backmen/OfferItem/OfferItemComponent.cs

This file was deleted.

This file was deleted.

Loading

0 comments on commit dd0a3c1

Please sign in to comment.