mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e2dffdb2 | ||
|
|
22e287ec45 | ||
|
|
9a0a4abf5d | ||
|
|
0b685a52b6 | ||
|
|
52d3b54d2c |
@@ -12,21 +12,12 @@ jobs:
|
||||
- name: Setup submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
pushd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
- name: Pull engine updates
|
||||
uses: space-wizards/submodule-dependency@v0.1.5
|
||||
- name: Update Engine Submodules
|
||||
run: |
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
pushd Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
with:
|
||||
|
||||
@@ -24,11 +24,7 @@ jobs:
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
pushd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
|
||||
- name: Pull engine updates
|
||||
uses: space-wizards/submodule-dependency@v0.1.5
|
||||
|
||||
@@ -36,10 +32,6 @@ jobs:
|
||||
run: |
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
pushd Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
|
||||
@@ -24,10 +24,6 @@ jobs:
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
pushd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Pull engine updates
|
||||
uses: space-wizards/submodule-dependency@v0.1.5
|
||||
@@ -36,10 +32,6 @@ jobs:
|
||||
run: |
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
pushd Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
|
||||
@@ -20,7 +20,6 @@ jobs:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
with:
|
||||
@@ -31,12 +30,6 @@ jobs:
|
||||
cd RobustToolbox
|
||||
git fetch --depth=1
|
||||
|
||||
- name: Get Engine Tag
|
||||
run: |
|
||||
cd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
|
||||
- name: Install dependencies
|
||||
run: dotnet restore
|
||||
|
||||
|
||||
@@ -39,10 +39,6 @@ jobs:
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
pushd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Pull engine updates
|
||||
uses: space-wizards/submodule-dependency@v0.1.5
|
||||
@@ -51,10 +47,6 @@ jobs:
|
||||
run: |
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
pushd Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
|
||||
@@ -17,20 +17,12 @@ jobs:
|
||||
- name: Setup submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
pushd RobustToolbox/Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
- name: Pull engine updates
|
||||
uses: space-wizards/submodule-dependency@v0.1.5
|
||||
- name: Update Engine Submodules
|
||||
run: |
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
pushd Lidgren.Network/Lidgren.Network
|
||||
git fetch
|
||||
git checkout 726dd552a4b104fb2b701848705f1250a073f060
|
||||
popd
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
with:
|
||||
|
||||
+18
-78
@@ -73,88 +73,28 @@ If you are adding a lot of C# code, then take advantage of partial classes. Put
|
||||
|
||||
Otherwise, **add comments on or around any changed lines.**
|
||||
|
||||
### Single-Line Changes
|
||||
Format should look like this.
|
||||
A comment on a new imported namespace:
|
||||
```cs
|
||||
/* Importing Namespaces - Include optional comment if its not obvious what its being used for. */
|
||||
using Content.Server._DV.Psionics.Glimmer; // DeltaV
|
||||
using Content.Shared.Damage.Systems; // DeltaV - Addition of HandHeldArmor
|
||||
|
||||
/* Changing an upstream line - Same line as the change */
|
||||
if (!TryComp<EyeComponent>(ent, out var eye) || _disabled) // DeltaV - check if disabled
|
||||
|
||||
/* Adding - Either same line or above the line. */
|
||||
EnsureComp<PotentialPsionicComponent>(entity); // Deltav - Psionics
|
||||
|
||||
/* "Deleting" - Don't actually delete, just comment out and say why. This only applies to upstream code. */
|
||||
// args.StatusIcons.Add(_prototype.Index(component.Icon)); // DeltaV - commented out. status icon now added above
|
||||
using Content.Server.Psionics.Glimmer; // DeltaV
|
||||
```
|
||||
|
||||
> * Its pretty obvious in the example above that importing `Content.Server._DV.Psionics.Glimmer` means we'll be interacting with glimmer so putting `// DeltaV - Add Glimmer` is needlessly redundant.
|
||||
> * It's not as obvious what the `Content.Shared.Damage.Systems` namespace is used for, since its so broad, so adding a comment what feature is using it helps.
|
||||
> * Actual code changes should almost always include the comment after ``// DeltaV`.
|
||||
|
||||
### Multi-Line Changes
|
||||
Depending on how much you are editing, putting a comment on EACH line may be excessive, so if you have a larger block of code you are changing, denote it like so:
|
||||
A pair of comments enclosing a block of added code:
|
||||
```cs
|
||||
// BEGIN DeltaV - Remove innate radio and radios from pockets
|
||||
for (var i = 1; i <= 4; i++) // Arachnids have 4 pockets
|
||||
private EntityUid Slice(...)
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(target, $"pocket{i}", out var headset) && HasComp<HeadsetComponent>(headset))
|
||||
_inventory.TryUnequip(target, $"pocket{i}", true, true);
|
||||
...
|
||||
|
||||
_transform.SetLocalRotation(sliceUid, 0);
|
||||
|
||||
// DeltaV - start of deep frier stuff
|
||||
var slicedEv = new FoodSlicedEvent(user, uid, sliceUid);
|
||||
RaiseLocalEvent(uid, ref slicedEv);
|
||||
// DeltaV - end of deep frier stuff
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
RemComp<ActiveRadioComponent>(target); // If the zombie has an innate radio, get rid of it.
|
||||
// END DeltaV
|
||||
```
|
||||
|
||||
> * Denoting these with a BEGIN and END clearly shows they are block of code without having to read the entire comment. This makes it easier to tell when you're dealing with single-line comments versus a block with merging in conflicts.
|
||||
> * Case and order of the first two words is less of a concern. `// DeltaV Begin` or `// Begin DeltaV` will work fine too.
|
||||
> * Try to make your blocks as small as possible, but use your discretion.
|
||||
> * If you deleting multiple lines, use line comments (``//``) if its a few lines but if its a larger block (like commenting out an entire function), it is preferable to use block comments (`/* */`).
|
||||
|
||||
#### Soft Exceptions to the Multi-Line "Rules"
|
||||
Some multi-line changes can use a single-line comment in certain scenarios. But if you are UNSURE, just use `// BEGIN DeltaV` and `// END DeltaV` comments like the previous section does and it'll be fine.
|
||||
|
||||
I'll give some examples.
|
||||
```cs
|
||||
/* This change comments out 3 lines but only needs a single line comment because commenting out the if statement implies that its logic will be commented out too. */
|
||||
// if (obj.WasModified<TraitPrototype>()) // DeltaV - Refreshed in TraitsTab
|
||||
// {
|
||||
// _profileEditor.RefreshTraits();
|
||||
// }
|
||||
|
||||
/* Same principle here. This adds two lines but the if statement implies the next line so commenting both lines isn't really needed. */
|
||||
if (_flight.IsFlying(entity.Owner)) // DeltaV - Harpy Flight
|
||||
return true;
|
||||
```
|
||||
### New Methods or Component Variables
|
||||
Sometimes, you'll need to implement a whole new method or component variable and instead of wrapping it in `// BEGIN DeltaV` and `// END DeltaV`, you can just denote that it's a DeltaV function in the summary block before the function. This denotes the WHOLE function as a DeltaV addition.
|
||||
|
||||
```cs
|
||||
/* New Method Example */
|
||||
/// <summary>
|
||||
/// DeltaV - Handle revealing ninja if cloaked when attacked by a hitscan attack.
|
||||
/// </summary>
|
||||
private void OnNinjaAttacked(Entity<SpaceNinjaComponent> ent, ref DamageChangedEvent args)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* New Component Variable Example */
|
||||
/// <summary>
|
||||
/// DeltaV - If disabled the action will not disable when no charges remain. Use if you want to handle no charges differently.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DisableWhenEmpty = true;
|
||||
```
|
||||
|
||||
In short:
|
||||
* Use `// BEGIN DeltaV` and `// END Delta` to denote a *block* of changes.
|
||||
* Keep blocks as small as possible.
|
||||
* Use `// DeltaV` on or before the line if its not a block of changes.
|
||||
* Use exceptions when they make sense.
|
||||
|
||||
### Changing Upstream Localization Fluent .ftl files
|
||||
|
||||
**Move all changed locale strings to a new DeltaV file** - use a `.ftl` file in the `_DV` folder. Comment out the old strings in the upstream file, and explain that they were moved.
|
||||
@@ -164,10 +104,10 @@ Example:
|
||||
Commented out old string in `Resources\Locale\en-US\xenoarchaeology\artifact-analyzer.ftl`
|
||||
```
|
||||
# DeltaV - moved to _DV file
|
||||
# analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
||||
# [true] {$info}
|
||||
# *[false] Unlock nodes to gain info
|
||||
# }[/color][/font]
|
||||
#analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
||||
# [true] {$info}
|
||||
# *[false] Unlock nodes to gain info
|
||||
#}[/color][/font]
|
||||
```
|
||||
|
||||
The new version of the string in `Resources\Locale\en-US\_DV\xenoarchaeology\artifact-analyzer.ftl`
|
||||
|
||||
@@ -7,7 +7,6 @@ using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Radio.Components; // DeltaV - Client-side Radio Colors
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -159,15 +158,6 @@ namespace Content.Client.Examine
|
||||
// since there's probably one open already if it's coming in from the server.
|
||||
var entity = GetEntity(ev.EntityUid);
|
||||
|
||||
|
||||
// BEGIN DeltaV - Client-Side Radio Colors
|
||||
// This *seems* a bit hacky, but we basically don't want to overwrite what's been pushed on the client-side,
|
||||
// because the server will send us the server-side colors (default). I've yet to find a scenario where the
|
||||
// server and client don't match, so until then, this is probably fine, if a little hacky.
|
||||
if (HasComp<EncryptionKeyHolderComponent>(entity) || HasComp<EncryptionKeyComponent>(entity))
|
||||
return;
|
||||
// END DeltaV
|
||||
|
||||
OpenTooltip(player.Value, entity, ev.CenterAtCursor, ev.OpenAtOldTooltip, ev.KnowTarget);
|
||||
UpdateTooltipInfo(player.Value, entity, ev.Message, ev.Verbs, getVerbs: false);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.Medical.CrewMonitoring"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:crewMonitoring="clr-namespace:Content.Client._DV.CrewMonitoring"
|
||||
Title="{Loc crew-monitoring-ui-title}"
|
||||
Resizable="False"
|
||||
SetSize="1210 700"
|
||||
MinSize="1210 700">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
|
||||
<ui:CrewMonitoringNavMapControl Name="NavMap" HorizontalExpand="True" VerticalExpand="True" Margin="5 20" Visible="False" />
|
||||
<crewMonitoring:CrewMonitoringShuttleControl Name="ShuttleMap" HorizontalExpand="True" VerticalExpand="True" Margin="5 20" Visible="False" />
|
||||
|
||||
<ui:CrewMonitoringNavMapControl Name="NavMap" HorizontalExpand="True" VerticalExpand="True" Margin="5 20"/>
|
||||
<BoxContainer Orientation="Vertical" Margin="0 0 10 0">
|
||||
<controls:StripeBack>
|
||||
<PanelContainer>
|
||||
|
||||
@@ -5,7 +5,6 @@ using Content.Client.Pinpointer.UI;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Medical.SuitSensor;
|
||||
using Content.Shared.Station; // DeltaV - crew monitoring radar
|
||||
using Content.Shared.StatusIcon;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -28,7 +27,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
private readonly SpriteSystem _spriteSystem;
|
||||
private readonly SharedStationSystem _station; // DeltaV - crew monitoring radar
|
||||
|
||||
private NetEntity? _trackedEntity;
|
||||
private bool _tryToScrollToListFocus;
|
||||
@@ -41,10 +39,8 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
|
||||
_transformSystem = _entManager.System<SharedTransformSystem>();
|
||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||
_station = _entManager.System<SharedStationSystem>(); // DeltaV - crew monitoring radar
|
||||
|
||||
NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
|
||||
ShuttleMap.NavMap = NavMap; // DeltaV - crew monitoring radar
|
||||
}
|
||||
|
||||
public void Set(string stationName, EntityUid? mapUid)
|
||||
@@ -54,10 +50,8 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
if (_entManager.TryGetComponent<TransformComponent>(mapUid, out var xform))
|
||||
NavMap.MapUid = xform.GridUid;
|
||||
|
||||
// Begin DeltaV - handle navmap visibility based on current position
|
||||
// else
|
||||
// NavMap.Visible = false;
|
||||
// End DeltaV - handle navmap visibility based on current position
|
||||
else
|
||||
NavMap.Visible = false;
|
||||
|
||||
StationName.AddStyleClass("LabelBig");
|
||||
StationName.Text = stationName;
|
||||
@@ -68,19 +62,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
// Begin DeltaV - handle navmap visibility based on current position
|
||||
if (_station.GetOwningStation(ShuttleMap.Owner) is not null)
|
||||
{
|
||||
NavMap.Visible = true;
|
||||
ShuttleMap.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NavMap.Visible = false;
|
||||
ShuttleMap.Visible = true;
|
||||
}
|
||||
// End DeltaV - handle navmap visibility based on current position
|
||||
|
||||
if (_tryToScrollToListFocus)
|
||||
TryToScrollToFocus();
|
||||
}
|
||||
@@ -88,7 +69,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
public void ShowSensors(List<SuitSensorStatus> sensors, EntityUid monitor, EntityCoordinates? monitorCoords)
|
||||
{
|
||||
ClearOutDatedData();
|
||||
ShuttleMap.Owner = monitor; // DeltaV - crew monitoring radar
|
||||
|
||||
// No server label
|
||||
if (sensors.Count == 0)
|
||||
@@ -324,7 +304,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
||||
jobContainer.AddChild(jobLabel);
|
||||
|
||||
// Add user coordinates to the navmap
|
||||
if (coordinates != null && _blipTexture != null) // DeltaV - don't filter the navmap visibility
|
||||
if (coordinates != null && NavMap.Visible && _blipTexture != null)
|
||||
{
|
||||
NavMap.TrackedEntities.TryAdd(sensor.SuitSensorUid,
|
||||
new NavMapBlip
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<tabs:AudioTab Name="AudioTab" />
|
||||
<tabs:AccessibilityTab Name="AccessibilityTab" />
|
||||
<tabs:AdminOptionsTab Name="AdminOptionsTab" />
|
||||
<dtabs:RadioTab Name="RadioTab" /> <!-- DeltaV - Client-side Radio Options -->
|
||||
<dtabs:DeltaTab Name="DeltaTab" /> <!-- DeltaV -->
|
||||
</TabContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -21,8 +21,7 @@ namespace Content.Client.Options.UI
|
||||
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
|
||||
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
|
||||
Tabs.SetTabTitle(5, Loc.GetString("ui-options-tab-admin"));
|
||||
Tabs.SetTabTitle(6, Loc.GetString("ui-options-tab-radio")); // DeltaV - Radio Channel Colors
|
||||
Tabs.SetTabTitle(7, Loc.GetString("ui-options-tab-deltav")); // DeltaV specific settings
|
||||
Tabs.SetTabTitle(6, Loc.GetString("ui-options-tab-deltav")); // DeltaV specific settings
|
||||
|
||||
UpdateTabs();
|
||||
}
|
||||
@@ -37,7 +36,6 @@ namespace Content.Client.Options.UI
|
||||
AccessibilityTab.Control.ReloadValues();
|
||||
AudioTab.Control.ReloadValues();
|
||||
AdminOptionsTab.Control.ReloadValues();
|
||||
RadioTab.Control.ReloadValues(); // DeltaV - Radio Channel Colors
|
||||
DeltaTab.Control.ReloadValues(); // DeltaV
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ public partial class NavMapControl : MapGridControl
|
||||
|
||||
// Constants
|
||||
protected float UpdateTime = 1.0f;
|
||||
public float MaxSelectableDistance = 10f; // DeltaV - accessible to CrewMonitoringShuttleControl
|
||||
public float MinDragDistance = 5f; // DeltaV - accessible to CrewMonitoringShuttleControl
|
||||
protected float MaxSelectableDistance = 10f;
|
||||
protected float MinDragDistance = 5f;
|
||||
protected static float MinDisplayedRange = 8f;
|
||||
protected static float MaxDisplayedRange = 128f;
|
||||
protected static float DefaultDisplayedRange = 48f;
|
||||
@@ -193,13 +193,6 @@ public partial class NavMapControl : MapGridControl
|
||||
_recenter.Disabled = false;
|
||||
}
|
||||
|
||||
// Begin DeltaV - we need access to that from outside
|
||||
public void TrackEntity(NetEntity? entity)
|
||||
{
|
||||
TrackedEntitySelectedAction?.Invoke(entity);
|
||||
}
|
||||
// End DeltaV - we need access to that from outside
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
|
||||
@@ -159,6 +159,35 @@ namespace Content.Client.Stylesheets
|
||||
|
||||
public static readonly Color ChatBackgroundColor = Color.FromHex("#25252ADD");
|
||||
|
||||
// DeltaV - AAC button variables
|
||||
public static readonly string CommandButtonClass = "CommandButton";
|
||||
public static readonly string EngineeringButtonClass = "EngineeringButton";
|
||||
public static readonly string EpistemicsButtonClass = "EpistemicsButton";
|
||||
public static readonly string JusticeButtonClass = "JusticeButton";
|
||||
public static readonly string LogisticsButtonClass = "LogisticsButton";
|
||||
public static readonly string MedicalButtonClass = "MedicalButton";
|
||||
public static readonly string SecurityButtonClass = "SecurityButton";
|
||||
public static readonly string ServiceButtonClass = "ServiceButton";
|
||||
|
||||
// DeltaV - AAC button colors
|
||||
public static readonly Color CommandButtonColorDefault = Color.FromHex("#404A58");
|
||||
public static readonly Color CommandColorHovered = Color.FromHex("#4F587B");
|
||||
public static readonly Color EngineeringButtonColorDefault = Color.FromHex("#77684B");
|
||||
public static readonly Color EngineeringColorHovered = Color.FromHex("#776D71");
|
||||
public static readonly Color EpistemicsButtonColorDefault = Color.FromHex("#6F5973");
|
||||
public static readonly Color EpistemicsColorHovered = Color.FromHex("#71638E");
|
||||
public static readonly Color LogisticsButtonColorDefault = Color.FromHex("#61503A");
|
||||
public static readonly Color LogisticsColorHovered = Color.FromHex("#675C64");
|
||||
public static readonly Color JusticeButtonColorDefault = Color.FromHex("#4F3D4C");
|
||||
public static readonly Color JusticeColorHovered = Color.FromHex("#5C4B5A");
|
||||
public static readonly Color MedicalButtonColorDefault = Color.FromHex("#49687D");
|
||||
public static readonly Color MedicalColorHovered = Color.FromHex("#556E95");
|
||||
public static readonly Color SecurityButtonColorDefault = Color.FromHex("#724449");
|
||||
public static readonly Color SecurityColorHovered = Color.FromHex("#745370");
|
||||
public static readonly Color ServiceButtonColorDefault = Color.FromHex("#607952");
|
||||
public static readonly Color ServiceColorHovered = Color.FromHex("#667A76");
|
||||
// End DeltaV
|
||||
|
||||
public const string StyleClassCrewManifestGender = "CrewManifestGender"; //Delta-V - Manifest pronouns
|
||||
|
||||
// i'm not sure what the missing symbols were referencing, and this is getting obseleted anyway so:
|
||||
@@ -1648,6 +1677,88 @@ namespace Content.Client.Stylesheets
|
||||
BackgroundColor = FancyTreeSelectedRowColor,
|
||||
}),
|
||||
|
||||
// DeltaV - AAC button styles
|
||||
Element<ContainerButton>()
|
||||
.Class(CommandButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, CommandButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(CommandButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, CommandColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(EngineeringButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, EngineeringButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(EngineeringButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, EngineeringColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(EpistemicsButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, EpistemicsButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(EpistemicsButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, EpistemicsColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(LogisticsButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, LogisticsButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(LogisticsButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, LogisticsColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(MedicalButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, MedicalButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(MedicalButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, MedicalColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(SecurityButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, SecurityButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(SecurityButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, SecurityColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(ServiceButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, ServiceButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(ServiceButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, ServiceColorHovered),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(JusticeButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
.Prop(Control.StylePropertyModulateSelf, JusticeButtonColorDefault),
|
||||
|
||||
Element<ContainerButton>()
|
||||
.Class(JusticeButtonClass)
|
||||
.Pseudo(ContainerButton.StylePseudoClassHover)
|
||||
.Prop(Control.StylePropertyModulateSelf, JusticeColorHovered),
|
||||
// End DeltaV
|
||||
|
||||
// Silicon law edit ui
|
||||
Element<Label>().Class(SiliconLawContainer.StyleClassSiliconLawPositionLabel)
|
||||
.Prop(Label.StylePropertyFontColor, NanoGold),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text.RegularExpressions; // DeltaV - Client-Side Radio Channel Colors
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Chat;
|
||||
using Content.Client.Chat.Managers;
|
||||
@@ -840,38 +839,8 @@ public sealed partial class ChatUIController : UIController
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - Regex expression to match on the chat message text in order to replace it with another color.
|
||||
/// </summary>
|
||||
private static readonly Regex RadioChatColorRegex = new(@"color=#?([a-fA-F0-9]{8})", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - Replaces the channel color hex code in a message with the client-side hex color
|
||||
/// overridden by <see cref="Content.Client._DV.Radio.RadioChannelColorSystem"/> .
|
||||
/// </summary>
|
||||
/// <param name="message">The message to find and replace the color hex code in.</param>
|
||||
/// <param name="channelProtoId">The proto ID of the channel. Basically the replacement color.</param>
|
||||
/// <returns>The message with the color hex code replaced, if it exists.</returns>
|
||||
private string ReplaceRadioChannelColorFromServer(string message, string channelProtoId)
|
||||
{
|
||||
if (_prototypeManager.Resolve<RadioChannelPrototype>(channelProtoId, out var channel))
|
||||
{
|
||||
return RadioChatColorRegex.Replace(message, $"color={channel.Color.ToHex()}");
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true)
|
||||
{
|
||||
// BEGIN DeltaV
|
||||
// Needs to happen before ANY other color or pattern matching so that we don't screw up the other colors in the message.
|
||||
if (msg.Channel == ChatChannel.Radio && msg.RadioChannelProtoId is { } channel)
|
||||
{
|
||||
msg.WrappedMessage = ReplaceRadioChannelColorFromServer(msg.WrappedMessage, channel);
|
||||
}
|
||||
// END DeltaV
|
||||
|
||||
// color the name unless it's something like "the old man"
|
||||
if ((msg.Channel == ChatChannel.Local || msg.Channel == ChatChannel.Whisper) && _chatNameColorsEnabled)
|
||||
{
|
||||
|
||||
@@ -12,19 +12,6 @@ namespace Content.Client._DV.AACTablet.UI;
|
||||
[CommonSheetlet]
|
||||
public sealed class AACSheetlet<T> : Sheetlet<T> where T : PalettedStylesheet, IButtonConfig
|
||||
{
|
||||
private static readonly (string StyleClass, Color Normal, Color Hover)[] SubjectButtonColors =
|
||||
[
|
||||
// Department colors
|
||||
("CommandButton", Color.FromHex("#404A58"), Color.FromHex("#4F587B")),
|
||||
("EngineeringButton", Color.FromHex("#77684B"), Color.FromHex("#776D71")),
|
||||
("EpistemicsButton", Color.FromHex("#6F5973"), Color.FromHex("#71638E")),
|
||||
("JusticeButton", Color.FromHex("#4F3D4C"), Color.FromHex("#5C4B5A")),
|
||||
("LogisticsButton", Color.FromHex("#61503A"), Color.FromHex("#675C64")),
|
||||
("MedicalButton", Color.FromHex("#49687D"), Color.FromHex("#556E95")),
|
||||
("SecurityButton", Color.FromHex("#724449"), Color.FromHex("#745370")),
|
||||
("ServiceButton", Color.FromHex("#607952"), Color.FromHex("#667A76")),
|
||||
];
|
||||
|
||||
public override StyleRule[] GetRules(T sheet, object config)
|
||||
{
|
||||
// Create style boxes
|
||||
@@ -94,21 +81,6 @@ public sealed class AACSheetlet<T> : Sheetlet<T> where T : PalettedStylesheet, I
|
||||
.Prop(Control.StylePropertyModulateSelf, Color.DarkRed),
|
||||
]);
|
||||
|
||||
SubjectColorRules(rules);
|
||||
|
||||
return rules.ToArray();
|
||||
}
|
||||
// AAC - Makes sure colors are applied to subject buttons
|
||||
private static void SubjectColorRules(List<StyleRule> rules)
|
||||
{
|
||||
foreach (var (styleClass, normal, hover) in SubjectButtonColors)
|
||||
{
|
||||
rules.AddRange([
|
||||
E<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(styleClass)
|
||||
.PseudoNormal().Prop(Control.StylePropertyModulateSelf, normal),
|
||||
E<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(styleClass)
|
||||
.PseudoHovered().Prop(Control.StylePropertyModulateSelf, hover),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public sealed partial class AACWindow : FancyWindow
|
||||
MaxSize = new Vector2(ButtonWidth, ButtonWidth),
|
||||
ClipText = false,
|
||||
HorizontalExpand = true,
|
||||
StyleClasses = { ContainerButton.StyleClassButton, styleClass }
|
||||
StyleClasses = { styleClass }
|
||||
};
|
||||
|
||||
var buttonLabel = new RichTextLabel
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Pinpointer.UI;
|
||||
using Content.Client.Shuttles.UI;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
namespace Content.Client._DV.CrewMonitoring;
|
||||
|
||||
public sealed class CrewMonitoringShuttleControl : BaseShuttleControl
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
private readonly SharedShuttleSystem _shuttles;
|
||||
private readonly SharedTransformSystem _transform;
|
||||
|
||||
public EntityUid? Owner;
|
||||
public NavMapControl? NavMap;
|
||||
|
||||
private List<Entity<MapGridComponent>> _grids = new();
|
||||
|
||||
public CrewMonitoringShuttleControl() : base(64f, 256f, 256f)
|
||||
{
|
||||
_shuttles = EntManager.System<SharedShuttleSystem>();
|
||||
_transform = EntManager.System<SharedTransformSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
DrawBacking(handle);
|
||||
DrawCircles(handle);
|
||||
|
||||
if (Owner is not { } owner || NavMap is not { } navMap)
|
||||
return;
|
||||
|
||||
var xformQuery = EntManager.GetEntityQuery<TransformComponent>();
|
||||
var fixturesQuery = EntManager.GetEntityQuery<FixturesComponent>();
|
||||
var bodyQuery = EntManager.GetEntityQuery<PhysicsComponent>();
|
||||
var iffQuery = EntManager.GetEntityQuery<IFFComponent>();
|
||||
|
||||
if (!xformQuery.TryGetComponent(owner, out var xform)
|
||||
|| xform.MapID == MapId.Nullspace)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var coordinates = new EntityCoordinates(owner, Vector2.Zero);
|
||||
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
var ourEntRot = Angle.Zero;
|
||||
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
||||
Matrix3x2.Invert(ourEntMatrix, out var worldToShuttle);
|
||||
var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
var worldToView = worldToShuttle * shuttleToView;
|
||||
|
||||
var viewBounds = new Box2Rotated(new Box2(-WorldRange, -WorldRange, WorldRange, WorldRange).Translated(mapPos.Position), ourEntRot, mapPos.Position);
|
||||
var viewAABB = viewBounds.CalcBoundingBox();
|
||||
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(xform.MapID, new Box2(mapPos.Position - MaxRadarRangeVector, mapPos.Position + MaxRadarRangeVector), ref _grids, approx: true, includeMap: false);
|
||||
|
||||
foreach (var grid in _grids)
|
||||
{
|
||||
if (!fixturesQuery.HasComponent(grid))
|
||||
continue;
|
||||
|
||||
var body = bodyQuery.GetComponent(grid);
|
||||
iffQuery.TryComp(grid, out var iff);
|
||||
|
||||
if (!_shuttles.CanDraw(grid, body, iff))
|
||||
continue;
|
||||
|
||||
var curGridToWorld = _transform.GetWorldMatrix(grid);
|
||||
var curGridToView = curGridToWorld * worldToShuttle * shuttleToView;
|
||||
|
||||
var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB);
|
||||
if (!gridAABB.Intersects(viewAABB))
|
||||
continue;
|
||||
|
||||
var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
|
||||
DrawGrid(handle, curGridToView, grid, labelColor);
|
||||
}
|
||||
|
||||
var curTime = Timing.RealTime;
|
||||
var blinkFrequency = 1f / 1f;
|
||||
var lit = curTime.TotalSeconds % blinkFrequency > blinkFrequency / 2f;
|
||||
var box = SizeBox;
|
||||
|
||||
foreach (var (coord, value) in navMap.TrackedCoordinates)
|
||||
{
|
||||
if (!lit || !value.Visible)
|
||||
continue;
|
||||
|
||||
var blipPos = _transform.ToMapCoordinates(coord);
|
||||
|
||||
if (mapPos.MapId == MapId.Nullspace)
|
||||
continue;
|
||||
|
||||
handle.DrawCircle(Vector2.Clamp(Vector2.Transform(blipPos.Position, worldToView), box.TopLeft, box.BottomRight), float.Sqrt(MinimapScale) * 2f, value.Color);
|
||||
}
|
||||
|
||||
foreach (var blip in navMap.TrackedEntities.Values)
|
||||
{
|
||||
if (blip.Blinks && !lit)
|
||||
continue;
|
||||
|
||||
var blipPos = _transform.ToMapCoordinates(blip.Coordinates);
|
||||
|
||||
if (mapPos.MapId == MapId.Nullspace)
|
||||
continue;
|
||||
|
||||
handle.DrawCircle(Vector2.Clamp(Vector2.Transform(blipPos.Position, worldToView), box.TopLeft, box.BottomRight), float.Sqrt(MinimapScale) * 2f, blip.Color);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
|
||||
if (Owner is not { } owner || NavMap is null)
|
||||
return;
|
||||
|
||||
if (!EntManager.TryGetComponent<TransformComponent>(owner, out var xform) || xform.MapID == MapId.Nullspace)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ourEntRot = Angle.Zero;
|
||||
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
||||
Matrix3x2.Invert(ourEntMatrix, out var worldToShuttle);
|
||||
var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
var worldToView = worldToShuttle * shuttleToView;
|
||||
Matrix3x2.Invert(worldToView, out var viewToWorld);
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
if (NavMap.TrackedEntities.Count == 0)
|
||||
return;
|
||||
|
||||
if ((StartDragPosition - args.PointerLocation.Position).Length() > NavMap.MinDragDistance)
|
||||
return;
|
||||
|
||||
var localPosition = args.PointerLocation.Position - GlobalPixelPosition;
|
||||
var worldPosition = Vector2.Transform(localPosition, viewToWorld);
|
||||
|
||||
var closestEntity = NetEntity.Invalid;
|
||||
var closestDistance = float.PositiveInfinity;
|
||||
|
||||
foreach (var (currentEntity, blip) in NavMap.TrackedEntities)
|
||||
{
|
||||
if (!blip.Selectable)
|
||||
continue;
|
||||
|
||||
var currentDistance = (_transform.ToMapCoordinates(blip.Coordinates).Position - worldPosition).Length();
|
||||
|
||||
if (closestDistance < currentDistance || currentDistance * MinimapScale > NavMap.MaxSelectableDistance)
|
||||
continue;
|
||||
|
||||
closestEntity = currentEntity;
|
||||
closestDistance = currentDistance;
|
||||
}
|
||||
|
||||
if (closestDistance > NavMap.MaxSelectableDistance || !closestEntity.IsValid())
|
||||
return;
|
||||
|
||||
NavMap.TrackEntity(closestEntity);
|
||||
}
|
||||
else if (args.Function == EngineKeyFunctions.UIRightClick)
|
||||
{
|
||||
NavMap.TrackEntity(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<tabs:RadioTab xmlns="https://spacestation14.io"
|
||||
xmlns:tabs="clr-namespace:Content.Client._DV.Options.UI.Tabs"
|
||||
xmlns:ui="clr-namespace:Content.Client.Options.UI">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<!-- Common -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-common'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioCommonColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-common'}"/>
|
||||
<Button Name="ResetCommonColorButton" Text="{Loc 'ui-options-radio-reset-common'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Command -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-command'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioCommandColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-command'}"/>
|
||||
<Button Name="ResetCommandColorButton" Text="{Loc 'ui-options-radio-reset-command'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Security -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-security'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioSecurityColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-security'}"/>
|
||||
<Button Name="ResetSecurityColorButton" Text="{Loc 'ui-options-radio-reset-security'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Medical -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-medical'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioMedicalColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-medical'}"/>
|
||||
<Button Name="ResetMedicalColorButton" Text="{Loc 'ui-options-radio-reset-medical'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Engineering -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-engineering'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioEngineeringColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-engineering'}"/>
|
||||
<Button Name="ResetEngineeringColorButton" Text="{Loc 'ui-options-radio-reset-engineering'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Science -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-science'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioScienceColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-science'}"/>
|
||||
<Button Name="ResetScienceColorButton" Text="{Loc 'ui-options-radio-reset-science'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Cargo -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-cargo'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioCargoColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-cargo'}"/>
|
||||
<Button Name="ResetCargoColorButton" Text="{Loc 'ui-options-radio-reset-cargo'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Service -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-service'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioServiceColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-service'}"/>
|
||||
<Button Name="ResetServiceColorButton" Text="{Loc 'ui-options-radio-reset-service'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- Binary -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-binary'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioBinaryColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-binary'}"/>
|
||||
<Button Name="ResetBinaryColorButton" Text="{Loc 'ui-options-radio-reset-binary'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- DeltaV - Justice -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-justice'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioJusticeColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-justice'}"/>
|
||||
<Button Name="ResetJusticeColorButton" Text="{Loc 'ui-options-radio-reset-justice'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
|
||||
<!-- DeltaV - Prison -->
|
||||
<Label Text="{Loc 'ui-options-radio-header-prison'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="RadioPrisonColorSlider"
|
||||
Example="{Loc 'ui-options-radio-example-prison'}"/>
|
||||
<Button Name="ResetPrisonColorButton" Text="{Loc 'ui-options-radio-reset-prison'}" MaxWidth="300" Margin="0 4 0 0" />
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
</BoxContainer>
|
||||
</tabs:RadioTab>
|
||||
@@ -1,55 +0,0 @@
|
||||
using Content.Client.Options.UI;
|
||||
using Content.Shared._DV.CCVars;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._DV.Options.UI.Tabs;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RadioTab : Control
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _config = default!; // DeltaV
|
||||
|
||||
public RadioTab()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
// Having so many color sliders on one page is a lot. We should only really try
|
||||
// to have common/departmental channels here, or it just becomes WAAAAY too much.
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorCommon, RadioCommonColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorCommand, RadioCommandColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorSecurity, RadioSecurityColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorMedical, RadioMedicalColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorEngineering, RadioEngineeringColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorScience, RadioScienceColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorCargo, RadioCargoColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorService, RadioServiceColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorBinary, RadioBinaryColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorJustice, RadioJusticeColorSlider);
|
||||
Control.AddOptionColorSlider(DCCVars.RadioColorPrison, RadioPrisonColorSlider);
|
||||
|
||||
ResetCommonColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorCommon);
|
||||
ResetCommandColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorCommand);
|
||||
ResetSecurityColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorSecurity);
|
||||
ResetMedicalColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorMedical);
|
||||
ResetEngineeringColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorEngineering);
|
||||
ResetScienceColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorScience);
|
||||
ResetCargoColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorCargo);
|
||||
ResetServiceColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorService);
|
||||
ResetBinaryColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorBinary);
|
||||
ResetJusticeColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorJustice);
|
||||
ResetPrisonColorButton.OnPressed += _ => OnResetColorButton(DCCVars.RadioColorPrison);
|
||||
|
||||
Control.Initialize();
|
||||
}
|
||||
|
||||
private void OnResetColorButton(CVarDef<string> cvar)
|
||||
{
|
||||
_config.SetCVar(cvar, cvar.DefaultValue);
|
||||
Control.ReloadValues();
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using Content.Shared._DV.CCVars;
|
||||
using Content.Shared.Radio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._DV.Radio;
|
||||
|
||||
public sealed partial class RadioChannelColorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
// Feels like there should be a better way to do this but I'd rather not add a client-side cvar ID or reference
|
||||
// to a prototype in Content.Shared, since I don't want people thinking they can ever use it on the server-side.
|
||||
private static readonly ProtoId<RadioChannelPrototype> CommonChannelProto = "Common";
|
||||
private static readonly ProtoId<RadioChannelPrototype> CommandChannelProto = "Command";
|
||||
private static readonly ProtoId<RadioChannelPrototype> SecurityChannelProto = "Security";
|
||||
private static readonly ProtoId<RadioChannelPrototype> MedicalChannelProto = "Medical";
|
||||
private static readonly ProtoId<RadioChannelPrototype> EngineeringChannelProto = "Engineering";
|
||||
private static readonly ProtoId<RadioChannelPrototype> ScienceChannelProto = "Science";
|
||||
private static readonly ProtoId<RadioChannelPrototype> CargoChannelProto = "Supply";
|
||||
private static readonly ProtoId<RadioChannelPrototype> ServiceChannelProto = "Service";
|
||||
private static readonly ProtoId<RadioChannelPrototype> BinaryChannelProto = "Binary";
|
||||
private static readonly ProtoId<RadioChannelPrototype> JusticeChannelProto = "Justice";
|
||||
private static readonly ProtoId<RadioChannelPrototype> PrisonChannelProto = "Prison";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_config.OnValueChanged(DCCVars.RadioColorCommon, (value) => { SetChannelColor(CommonChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorCommand, (value) => { SetChannelColor(CommandChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorSecurity, (value) => { SetChannelColor(SecurityChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorMedical, (value) => { SetChannelColor(MedicalChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorEngineering, (value) => { SetChannelColor(EngineeringChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorScience, (value) => { SetChannelColor(ScienceChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorCargo, (value) => { SetChannelColor(CargoChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorService, (value) => { SetChannelColor(ServiceChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorBinary, (value) => { SetChannelColor(BinaryChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorJustice, (value) => { SetChannelColor(JusticeChannelProto, value); }, true);
|
||||
_config.OnValueChanged(DCCVars.RadioColorPrison, (value) => { SetChannelColor(PrisonChannelProto, value); }, true);
|
||||
}
|
||||
|
||||
private void SetChannelColor(ProtoId<RadioChannelPrototype> channel, string newColor)
|
||||
{
|
||||
if (Color.TryParse(newColor, out var color))
|
||||
_proto.Index(channel).Color = color;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Content.Shared.Labels.Components;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
public static class NameHelpers
|
||||
{
|
||||
extension(IEntityManager self)
|
||||
{
|
||||
public string PaperName(EntityUid paper)
|
||||
{
|
||||
if (self.TryGetComponent<LabelComponent>(paper, out var label) && label.CurrentLabel is { } labelText)
|
||||
return labelText;
|
||||
|
||||
return self.GetComponent<MetaDataComponent>(paper).EntityName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using System.IO;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Fax;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class StationAiFaxBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
[Dependency] private readonly IFileDialogManager _fileDialogManager = default!;
|
||||
|
||||
private StationAiFaxWindow? _window;
|
||||
private List<StationAiFaxPageWindow> _windows = new();
|
||||
|
||||
private bool _dialogIsOpen;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<StationAiFaxWindow>();
|
||||
_window.FileButtonPressed += OnFileButtonPressed;
|
||||
_window.BlankButtonPressed += OnBlankButtonPressed;
|
||||
_window.OpenSendWindowPressed += OnOpenSendWindowPressed;
|
||||
_window.ExaminePressed += OnExaminePressed;
|
||||
_window.ShredPressed += OnShredPressed;
|
||||
_window.DuplicatePressed += OnDuplicatePressed;
|
||||
|
||||
UpdateFaxes(EntMan.System<SharedContainerSystem>().EnsureContainer<Container>(Owner, StationAiFaxComponent.Container, out _));
|
||||
}
|
||||
|
||||
private async void OnFileButtonPressed()
|
||||
{
|
||||
if (_dialogIsOpen)
|
||||
return;
|
||||
|
||||
_dialogIsOpen = true;
|
||||
var filters = new FileDialogFilters(new FileDialogFilters.Group("txt"));
|
||||
await using var file = await _fileDialogManager.OpenFile(filters, FileAccess.Read);
|
||||
_dialogIsOpen = false;
|
||||
|
||||
if (_window == null || _window.Disposed || file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(file);
|
||||
|
||||
var firstLine = await reader.ReadLineAsync();
|
||||
string? label = null;
|
||||
var content = await reader.ReadToEndAsync();
|
||||
|
||||
if (firstLine is { })
|
||||
{
|
||||
if (firstLine.StartsWith('#'))
|
||||
{
|
||||
label = firstLine[1..].Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
content = firstLine + "\n" + content;
|
||||
}
|
||||
}
|
||||
|
||||
SendMessage(new FaxFileMessage(
|
||||
label?[..Math.Min(label.Length, FaxFileMessageValidation.MaxLabelSize)],
|
||||
content[..Math.Min(content.Length, FaxFileMessageValidation.MaxContentSize)],
|
||||
false));
|
||||
}
|
||||
|
||||
private void OnBlankButtonPressed()
|
||||
{
|
||||
SendMessage(new FaxFileMessage(null, string.Empty, false));
|
||||
}
|
||||
|
||||
private void OnOpenSendWindowPressed(EntityUid entity)
|
||||
{
|
||||
var window = new StationAiFaxPageWindow(entity, EntMan);
|
||||
_windows.Add(window);
|
||||
|
||||
window.RefreshButtonPressed += OnRefreshButtonPressed;
|
||||
window.PeerSelected += OnPeerSelected;
|
||||
window.SendButtonPressed += OnSendDocument;
|
||||
|
||||
if (UiSystem.TryGetUiState<FaxUiState>(Owner, UiKey, out var state))
|
||||
{
|
||||
window.UpdateState(state);
|
||||
}
|
||||
|
||||
window.OpenCentered();
|
||||
}
|
||||
|
||||
private void OnSendDocument(EntityUid entity)
|
||||
{
|
||||
SendMessage(new StationAiFaxSendMessage(EntMan.GetNetEntity(entity)));
|
||||
}
|
||||
|
||||
private void OnExaminePressed(EntityUid entity)
|
||||
{
|
||||
SendPredictedMessage(new StationAiFaxExamineMessage(EntMan.GetNetEntity(entity)));
|
||||
}
|
||||
|
||||
private void OnShredPressed(EntityUid entity)
|
||||
{
|
||||
SendPredictedMessage(new StationAiFaxShredMessage(EntMan.GetNetEntity(entity)));
|
||||
}
|
||||
|
||||
private void OnDuplicatePressed(EntityUid entity)
|
||||
{
|
||||
SendPredictedMessage(new StationAiFaxDuplicateMessage(EntMan.GetNetEntity(entity)));
|
||||
}
|
||||
|
||||
private void OnRefreshButtonPressed()
|
||||
{
|
||||
SendMessage(new FaxRefreshMessage());
|
||||
}
|
||||
|
||||
private void OnPeerSelected(string address)
|
||||
{
|
||||
SendMessage(new FaxDestinationMessage(address));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is not FaxUiState cast)
|
||||
return;
|
||||
|
||||
_window?.UpdateState(cast);
|
||||
foreach (var window in _windows)
|
||||
{
|
||||
window.UpdateState(cast);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFaxes(Container container)
|
||||
{
|
||||
_window?.UpdateFaxes(container);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<PanelContainer xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client._DV.UserInterfaces"
|
||||
xmlns:xe="clr-namespace:Content.Client.UserInterface.XamlExtensions"
|
||||
StyleClasses="PanelLight"
|
||||
HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="8">
|
||||
<Label Name="PaperName" HorizontalExpand="True" />
|
||||
|
||||
<ui:IconButton Name="Shred" StyleClasses="OpenRight" Icon="{xe:Tex '/Textures/Interface/shredder.svg.192dpi.png'}" />
|
||||
<ui:IconButton Name="Duplicate" StyleClasses="OpenBoth" Icon="{xe:Tex '/Textures/Interface/files.svg.192dpi.png'}" />
|
||||
<ui:IconButton Name="Examine" StyleClasses="OpenBoth" Icon="{xe:Tex '/Textures/Interface/eye.svg.192dpi.png'}" />
|
||||
<ui:IconButton Name="Send" StyleClasses="OpenLeft" Icon="{xe:Tex '/Textures/Interface/send.svg.192dpi.png'}" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
@@ -1,27 +0,0 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class StationAiFaxItem : PanelContainer
|
||||
{
|
||||
public string? Text { get => PaperName.Text; set => PaperName.Text = value; }
|
||||
public bool CanSend { get => !Duplicate.Disabled; set => Duplicate.Disabled = !value; }
|
||||
|
||||
public event Action? ShredPressed;
|
||||
public event Action? DuplicatePressed;
|
||||
public event Action? ExaminePressed;
|
||||
public event Action? SendPressed;
|
||||
|
||||
public StationAiFaxItem()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Shred.OnPressed += _ => ShredPressed?.Invoke();
|
||||
Duplicate.OnPressed += _ => DuplicatePressed?.Invoke();
|
||||
Examine.OnPressed += _ => ExaminePressed?.Invoke();
|
||||
Send.OnPressed += _ => SendPressed?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<controls:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'fax-machine-ui-page-window'}"
|
||||
MinSize="380 220">
|
||||
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'fax-machine-ui-sending'}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalExpand="True" />
|
||||
|
||||
<Label Name="SendingLabel"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Align="Right"/>
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'fax-machine-ui-from'}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalExpand="True" />
|
||||
|
||||
<Label Name="FromLabel"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Align="Right"/>
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer
|
||||
Orientation="Horizontal">
|
||||
|
||||
<Label Text="{Loc 'fax-machine-ui-to'}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalExpand="True"/>
|
||||
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<OptionButton Name="PeerSelector"
|
||||
StyleClasses="OpenRight" />
|
||||
|
||||
<Button StyleClasses="OpenLeft"
|
||||
Name="RefreshButton"
|
||||
ToolTip="{Loc 'fax-machine-ui-refresh-button'}">
|
||||
<TextureButton
|
||||
MouseFilter="Ignore"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Scale="0.9 0.9"
|
||||
StyleClasses="RefreshButton" />
|
||||
</Button>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<BoxContainer Orientation="Horizontal" SeparationOverride="8" Margin="8">
|
||||
<Button Name="SendButton"
|
||||
Text="{Loc 'fax-machine-ui-send-button'}"
|
||||
HorizontalExpand="True"
|
||||
Disabled="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Fax;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class StationAiFaxPageWindow : FancyWindow
|
||||
{
|
||||
public event Action? RefreshButtonPressed;
|
||||
public event Action<string>? PeerSelected;
|
||||
public event Action<EntityUid>? SendButtonPressed;
|
||||
|
||||
public StationAiFaxPageWindow(EntityUid uid, IEntityManager entityManager)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
SendingLabel.Text = entityManager.PaperName(uid);
|
||||
|
||||
RefreshButton.OnPressed += _ => RefreshButtonPressed?.Invoke();
|
||||
SendButton.OnPressed += _ => SendButtonPressed?.Invoke(uid);
|
||||
PeerSelector.OnItemSelected += args =>
|
||||
PeerSelected?.Invoke((string) args.Button.GetItemMetadata(args.Id)!);
|
||||
}
|
||||
|
||||
public void UpdateState(FaxUiState state)
|
||||
{
|
||||
SendButton.Disabled = !state.CanSendCooldown;
|
||||
FromLabel.Text = state.DeviceName;
|
||||
|
||||
if (state.AvailablePeers.Count == 0)
|
||||
{
|
||||
PeerSelector.AddItem(Loc.GetString("fax-machine-ui-no-peers"));
|
||||
PeerSelector.Disabled = true;
|
||||
}
|
||||
|
||||
if (PeerSelector.Disabled && state.AvailablePeers.Count != 0)
|
||||
{
|
||||
PeerSelector.Clear();
|
||||
PeerSelector.Disabled = false;
|
||||
}
|
||||
|
||||
// always must be selected destination
|
||||
if (string.IsNullOrEmpty(state.DestinationAddress) && state.AvailablePeers.Count != 0)
|
||||
{
|
||||
PeerSelected?.Invoke(state.AvailablePeers.First().Key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.AvailablePeers.Count != 0)
|
||||
{
|
||||
PeerSelector.Clear();
|
||||
|
||||
foreach (var (address, name) in state.AvailablePeers)
|
||||
{
|
||||
var id = AddPeerSelect(name, address);
|
||||
if (address == state.DestinationAddress)
|
||||
PeerSelector.Select(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int AddPeerSelect(string name, string address)
|
||||
{
|
||||
PeerSelector.AddItem(name);
|
||||
PeerSelector.SetItemMetadata(PeerSelector.ItemCount - 1, address);
|
||||
return PeerSelector.ItemCount - 1;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Fax;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
public sealed class StationAiFaxSystem : SharedStationAiFaxSystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StationAiFaxComponent, EntRemovedFromContainerMessage>(OnRemoved);
|
||||
}
|
||||
|
||||
protected override void OnInserted(Entity<StationAiFaxComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
base.OnInserted(ent, ref args);
|
||||
|
||||
if (!_userInterface.TryGetOpenUi<StationAiFaxBoundUserInterface>(ent.Owner, FaxUiKey.Key, out var bui))
|
||||
return;
|
||||
|
||||
bui.UpdateFaxes(_container.EnsureContainer<Container>(ent, StationAiFaxComponent.Container, out _));
|
||||
}
|
||||
|
||||
private void OnRemoved(Entity<StationAiFaxComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (!_userInterface.TryGetOpenUi<StationAiFaxBoundUserInterface>(ent.Owner, FaxUiKey.Key, out var bui))
|
||||
return;
|
||||
|
||||
bui.UpdateFaxes(_container.EnsureContainer<Container>(ent, StationAiFaxComponent.Container, out _));
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<controls:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'fax-machine-ui-window'}"
|
||||
MinSize="500 600">
|
||||
|
||||
<BoxContainer Orientation="Vertical" Name="NoFaxes" HorizontalAlignment="Center" VerticalAlignment="Center" SeparationOverride="8">
|
||||
<Label StyleClasses="PlaceholderText" Text="{Loc 'fax-machine-ui-no-faxes'}" Align="Center" />
|
||||
|
||||
<BoxContainer Orientation="Vertical" HorizontalAlignment="Center">
|
||||
<Button Name="NoFaxesBlank" Text="{Loc 'fax-machine-ui-add-blank-file'}" HorizontalExpand="True" StyleClasses="OpenLeft" />
|
||||
<Button Name="NoFaxesUpload" Text="{Loc 'fax-machine-ui-upload-file'}" HorizontalExpand="True" StyleClasses="OpenRight" />
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Vertical" Name="YesFaxes" HorizontalExpand="True" VerticalExpand="True">
|
||||
<PanelContainer StyleClasses="PanelDark" VerticalExpand="True" HorizontalExpand="True">
|
||||
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
|
||||
<BoxContainer Name="FaxList" Margin="8" VerticalAlignment="Top" HorizontalExpand="True" SeparationOverride="8" Orientation="Vertical" />
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" SeparationOverride="8" Margin="8">
|
||||
<Button Name="YesFaxesBlank" Text="{Loc 'fax-machine-ui-add-blank-file'}" HorizontalAlignment="Center" />
|
||||
<Button Name="YesFaxesUpload" Text="{Loc 'fax-machine-ui-upload-file'}" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
@@ -1,92 +0,0 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Fax;
|
||||
using Content.Shared.Labels.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._DV.Silicons;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class StationAiFaxWindow : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public event Action? BlankButtonPressed;
|
||||
public event Action? FileButtonPressed;
|
||||
public event Action<EntityUid>? OpenSendWindowPressed;
|
||||
public event Action<EntityUid>? ExaminePressed;
|
||||
public event Action<EntityUid>? ShredPressed;
|
||||
public event Action<EntityUid>? DuplicatePressed;
|
||||
|
||||
public bool CanSend
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (field == value)
|
||||
return;
|
||||
|
||||
field = value;
|
||||
foreach (var item in FaxList.Children)
|
||||
{
|
||||
var castItem = (StationAiFaxItem)item;
|
||||
castItem.CanSend = value;
|
||||
}
|
||||
|
||||
NoFaxesBlank.Disabled = !value;
|
||||
NoFaxesUpload.Disabled = !value;
|
||||
YesFaxesBlank.Disabled = !value;
|
||||
YesFaxesUpload.Disabled = !value;
|
||||
}
|
||||
}
|
||||
|
||||
public StationAiFaxWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
NoFaxesBlank.OnPressed += _ => BlankButtonPressed?.Invoke();
|
||||
NoFaxesUpload.OnPressed += _ => FileButtonPressed?.Invoke();
|
||||
|
||||
YesFaxesBlank.OnPressed += _ => BlankButtonPressed?.Invoke();
|
||||
YesFaxesUpload.OnPressed += _ => FileButtonPressed?.Invoke();
|
||||
}
|
||||
|
||||
public void UpdateFaxes(Robust.Shared.Containers.Container container)
|
||||
{
|
||||
FaxList.RemoveAllChildren();
|
||||
foreach (var item in container.ContainedEntities)
|
||||
{
|
||||
var page = new StationAiFaxItem
|
||||
{
|
||||
Text = _entityManager.TryGetComponent<LabelComponent>(item, out var label) &&
|
||||
label.CurrentLabel is { } labelText
|
||||
? labelText
|
||||
: _entityManager.GetComponent<MetaDataComponent>(item).EntityName,
|
||||
CanSend = CanSend,
|
||||
};
|
||||
FaxList.AddChild(page);
|
||||
|
||||
page.ExaminePressed += () => ExaminePressed?.Invoke(item);
|
||||
page.ShredPressed += () => ShredPressed?.Invoke(item);
|
||||
page.DuplicatePressed += () => DuplicatePressed?.Invoke(item);
|
||||
page.SendPressed += () => OpenSendWindowPressed?.Invoke(item);
|
||||
}
|
||||
|
||||
if (container.ContainedEntities.Count == 0)
|
||||
{
|
||||
YesFaxes.Visible = false;
|
||||
NoFaxes.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
YesFaxes.Visible = true;
|
||||
NoFaxes.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateState(FaxUiState state)
|
||||
{
|
||||
CanSend = state.CanSendCooldown;
|
||||
}
|
||||
}
|
||||
@@ -108,70 +108,6 @@ public sealed partial class TraitCategory : BoxContainer
|
||||
{
|
||||
CategoryPointsLabel.Visible = false;
|
||||
}
|
||||
|
||||
// Lock unselected entries whenever the category cap is reached so the
|
||||
// player gets a clear visual cue instead of silently failing to equip.
|
||||
UpdateCategoryFullState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Propagates category-cap lock state to every entry.
|
||||
/// <para>
|
||||
/// Selected entries are never locked - they are the traits filling the cap
|
||||
/// and must stay interactive so the player can deselect them.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Unselected entries are locked when:
|
||||
/// <list type="bullet">
|
||||
/// <item><see cref="TraitCategoryPrototype.MaxTraits"/> is defined and already reached, OR</item>
|
||||
/// <item><see cref="TraitCategoryPrototype.MaxPoints"/> is defined and this specific
|
||||
/// trait's cost would push spending over the limit.</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private void UpdateCategoryFullState()
|
||||
{
|
||||
var traitCapReached = _category.MaxTraits.HasValue && SelectedCount >= _category.MaxTraits.Value;
|
||||
|
||||
foreach (var (_, entry) in _traitEntries)
|
||||
{
|
||||
if (entry.IsSelected)
|
||||
{
|
||||
// Selected traits are never locked by category state.
|
||||
entry.SetLockedByCategory(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var locked = traitCapReached;
|
||||
|
||||
// Even when the trait count cap hasn't been hit, lock this specific entry
|
||||
// if adding its cost would exceed the category's point budget.
|
||||
if (!locked && _category.MaxPoints.HasValue)
|
||||
locked = PointsSpent + entry.TraitCost > _category.MaxPoints.Value;
|
||||
|
||||
entry.SetLockedByCategory(locked);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="TraitsTab"/> whenever the player's global point budget changes.
|
||||
/// Locks any unselected entry whose cost the player can no longer afford.
|
||||
/// <para>
|
||||
/// Free (0-cost) and negative-cost traits are never locked - they cost nothing or
|
||||
/// actually give points back. Selected traits are also never locked here; they
|
||||
/// were affordable when picked and must stay interactive to be deselected.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public void UpdateGlobalPointsLock(int remainingPoints)
|
||||
{
|
||||
foreach (var (_, entry) in _traitEntries)
|
||||
{
|
||||
// A selected trait is always unlocked here - same reasoning as category cap:
|
||||
// it was paid for at selection time and must stay interactive.
|
||||
// Traits that cost nothing or give points back are never locked by budget.
|
||||
var shouldLock = !entry.IsSelected && entry.TraitCost > remainingPoints;
|
||||
entry.SetLockedByPoints(shouldLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTraitSelected(ProtoId<TraitPrototype> traitId, bool selected)
|
||||
@@ -235,11 +171,11 @@ public sealed partial class TraitCategory : BoxContainer
|
||||
/// Updates condition states for all trait entries based on current job/species.
|
||||
/// Traits that don't meet conditions are disabled but still visible.
|
||||
/// </summary>
|
||||
public void UpdateConditions(ProtoId<JobPrototype>? jobId, ProtoId<SpeciesPrototype>? speciesId, IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences, IReadOnlySet<ProtoId<TraitPrototype>>? selectedTraits)
|
||||
public void UpdateConditions(ProtoId<JobPrototype>? jobId, ProtoId<SpeciesPrototype>? speciesId, IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences)
|
||||
{
|
||||
foreach (var (_, entry) in _traitEntries)
|
||||
{
|
||||
entry.UpdateConditionsMet(jobId, speciesId, antagPreferences, selectedTraits);
|
||||
entry.UpdateConditionsMet(jobId, speciesId, antagPreferences);
|
||||
}
|
||||
|
||||
// Update stats since some traits may have been deselected
|
||||
|
||||
@@ -27,9 +27,6 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
private bool _isUpdating;
|
||||
private readonly List<string> _failedConditionTooltips = new();
|
||||
|
||||
private bool _isLockedByCategory;
|
||||
private bool _isLockedByPoints;
|
||||
|
||||
public TraitEntry(TraitPrototype trait)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -62,17 +59,9 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
|
||||
foreach (var condition in _trait.Conditions)
|
||||
{
|
||||
if (condition is TraitDependencyCondition depCond)
|
||||
{
|
||||
// Use GetTooltips() to get individual lines without duplication
|
||||
tooltips.AddRange(depCond.GetTooltips(_prototype, _loc));
|
||||
}
|
||||
else
|
||||
{
|
||||
var tooltip = condition.GetTooltip(_prototype, _loc);
|
||||
if (!string.IsNullOrEmpty(tooltip))
|
||||
tooltips.Add(tooltip);
|
||||
}
|
||||
var tooltip = condition.GetTooltip(_prototype, _loc);
|
||||
if (!string.IsNullOrEmpty(tooltip))
|
||||
tooltips.Add(tooltip);
|
||||
}
|
||||
|
||||
if (tooltips.Count > 0)
|
||||
@@ -102,92 +91,39 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
/// <summary>
|
||||
/// Updates whether conditions are met based on current job/species.
|
||||
/// </summary>
|
||||
public void UpdateConditionsMet(
|
||||
ProtoId<JobPrototype>? jobId,
|
||||
ProtoId<SpeciesPrototype>? speciesId,
|
||||
IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences,
|
||||
IReadOnlySet<ProtoId<TraitPrototype>>? selectedTraits)
|
||||
public void UpdateConditionsMet(ProtoId<JobPrototype>? jobId, ProtoId<SpeciesPrototype>? speciesId, IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences)
|
||||
{
|
||||
_failedConditionTooltips.Clear();
|
||||
MeetsConditions = true;
|
||||
|
||||
foreach (var condition in _trait.Conditions)
|
||||
{
|
||||
bool result;
|
||||
|
||||
if (condition is TraitDependencyCondition depCond)
|
||||
var result = condition switch
|
||||
{
|
||||
result = CheckDependencyCondition(depCond, selectedTraits);
|
||||
// CheckDependencyCondition adds its own tooltips directly
|
||||
}
|
||||
else
|
||||
{
|
||||
result = condition switch
|
||||
{
|
||||
IsSpeciesCondition speciesCond => CheckSpeciesCondition(speciesCond, speciesId),
|
||||
HasJobCondition jobCond => CheckJobCondition(jobCond, jobId),
|
||||
InDepartmentCondition deptCond => CheckDepartmentCondition(deptCond, jobId),
|
||||
HasCompCondition compCond => !compCond.Invert, // can't check in lobby
|
||||
IsAntagEligibleCondition antagEligibleCond => CheckAntagEligibleCondition(antagEligibleCond, antagPreferences),
|
||||
AnyOfCondition anyOfCond => CheckAnyOfCondition(anyOfCond, jobId, speciesId, antagPreferences, selectedTraits),
|
||||
_ => true,
|
||||
};
|
||||
IsSpeciesCondition speciesCond => CheckSpeciesCondition(speciesCond, speciesId),
|
||||
HasJobCondition jobCond => CheckJobCondition(jobCond, jobId),
|
||||
InDepartmentCondition deptCond => CheckDepartmentCondition(deptCond, jobId),
|
||||
HasCompCondition compCond => !compCond.Invert, // can't check in lobby but screws with the inversion logic
|
||||
IsAntagEligibleCondition antagEligibleCond => CheckAntagEligibleCondition(antagEligibleCond, antagPreferences),
|
||||
AnyOfCondition anyOfCond => CheckAnyOfCondition(anyOfCond, jobId, speciesId, antagPreferences),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// Apply inversion for non-dependency conditions
|
||||
result ^= condition.Invert;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
var tooltip = condition.GetTooltip(_prototype, _loc);
|
||||
if (!string.IsNullOrEmpty(tooltip))
|
||||
_failedConditionTooltips.Add(tooltip);
|
||||
}
|
||||
}
|
||||
// Apply inversion
|
||||
result ^= condition.Invert;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
MeetsConditions = false;
|
||||
var tooltip = condition.GetTooltip(_prototype, _loc);
|
||||
if (!string.IsNullOrEmpty(tooltip))
|
||||
_failedConditionTooltips.Add(tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateDisabledState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks a TraitDependencyCondition and adds failure tooltips directly.
|
||||
/// Returns true if the condition passes.
|
||||
/// </summary>
|
||||
private bool CheckDependencyCondition(TraitDependencyCondition condition, IReadOnlySet<ProtoId<TraitPrototype>>? selectedTraits)
|
||||
{
|
||||
var passed = true;
|
||||
|
||||
foreach (var conflict in condition.Conflicts)
|
||||
{
|
||||
if (selectedTraits == null || !selectedTraits.Contains(conflict))
|
||||
continue;
|
||||
|
||||
if (_prototype.TryIndex(conflict, out var conflictProto))
|
||||
{
|
||||
_failedConditionTooltips.Add(_loc.GetString("trait-condition-trait-conflict",
|
||||
("trait", _loc.GetString(conflictProto.Name))));
|
||||
}
|
||||
passed = false;
|
||||
}
|
||||
|
||||
foreach (var required in condition.Requires)
|
||||
{
|
||||
if (selectedTraits != null && selectedTraits.Contains(required))
|
||||
continue;
|
||||
|
||||
if (_prototype.TryIndex(required, out var requiredProto))
|
||||
{
|
||||
_failedConditionTooltips.Add(_loc.GetString("trait-condition-trait-required",
|
||||
("trait", _loc.GetString(requiredProto.Name))));
|
||||
}
|
||||
passed = false;
|
||||
}
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
private bool CheckSpeciesCondition(IsSpeciesCondition condition, ProtoId<SpeciesPrototype>? speciesId)
|
||||
{
|
||||
if (!_prototype.TryIndex(speciesId, out var species))
|
||||
@@ -223,12 +159,7 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
return antagPreferences.Contains(condition.Antag);
|
||||
}
|
||||
|
||||
private bool CheckAnyOfCondition(
|
||||
AnyOfCondition condition,
|
||||
ProtoId<JobPrototype>? jobId,
|
||||
ProtoId<SpeciesPrototype>? speciesId,
|
||||
IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences,
|
||||
IReadOnlySet<ProtoId<TraitPrototype>>? selectedTraits)
|
||||
private bool CheckAnyOfCondition(AnyOfCondition condition, ProtoId<JobPrototype>? jobId, ProtoId<SpeciesPrototype>? speciesId, IReadOnlySet<ProtoId<AntagPrototype>>? antagPreferences)
|
||||
{
|
||||
if (condition.Conditions.Count == 0)
|
||||
return false;
|
||||
@@ -236,27 +167,19 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
// Return true if ANY child condition evaluates to true
|
||||
foreach (var childCondition in condition.Conditions)
|
||||
{
|
||||
bool result;
|
||||
|
||||
if (childCondition is TraitDependencyCondition depCond)
|
||||
var result = childCondition switch
|
||||
{
|
||||
result = CheckDependencyCondition(depCond, selectedTraits);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = childCondition switch
|
||||
{
|
||||
IsSpeciesCondition speciesCond => CheckSpeciesCondition(speciesCond, speciesId),
|
||||
HasJobCondition jobCond => CheckJobCondition(jobCond, jobId),
|
||||
InDepartmentCondition deptCond => CheckDepartmentCondition(deptCond, jobId),
|
||||
HasCompCondition compCond => !compCond.Invert, // can't check in lobby
|
||||
IsAntagEligibleCondition antagEligibleCond => CheckAntagEligibleCondition(antagEligibleCond, antagPreferences),
|
||||
AnyOfCondition nestedAnyOf => CheckAnyOfCondition(nestedAnyOf, jobId, speciesId, antagPreferences, selectedTraits),
|
||||
_ => true,
|
||||
};
|
||||
IsSpeciesCondition speciesCond => CheckSpeciesCondition(speciesCond, speciesId),
|
||||
HasJobCondition jobCond => CheckJobCondition(jobCond, jobId),
|
||||
InDepartmentCondition deptCond => CheckDepartmentCondition(deptCond, jobId),
|
||||
HasCompCondition compCond => !compCond.Invert, // can't check in lobby
|
||||
AnyOfCondition nestedAnyOf => CheckAnyOfCondition(nestedAnyOf, jobId, speciesId, antagPreferences), // Recursive!
|
||||
IsAntagEligibleCondition antagEligibleCond => CheckAntagEligibleCondition(antagEligibleCond, antagPreferences),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
result ^= childCondition.Invert;
|
||||
}
|
||||
// Apply child's inversion
|
||||
result ^= childCondition.Invert;
|
||||
|
||||
// If any child passes, the AnyOf passes
|
||||
if (result)
|
||||
@@ -267,50 +190,16 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="TraitCategory"/> whenever the category's trait or
|
||||
/// points-cap state changes. Locking only applies to <em>unselected</em>
|
||||
/// entries - the selected traits are the ones filling the cap and must
|
||||
/// remain interactive so the player can deselect them.
|
||||
/// </summary>
|
||||
public void SetLockedByCategory(bool locked)
|
||||
{
|
||||
if (_isLockedByCategory == locked)
|
||||
return;
|
||||
|
||||
_isLockedByCategory = locked;
|
||||
UpdateDisabledState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="TraitCategory"/> whenever the player's global point budget
|
||||
/// changes. Locks unselected entries whose cost the player can no longer afford.
|
||||
/// Free (0-cost) and negative-cost traits are never locked by this.
|
||||
/// </summary>
|
||||
public void SetLockedByPoints(bool locked)
|
||||
{
|
||||
if (_isLockedByPoints == locked)
|
||||
return;
|
||||
|
||||
_isLockedByPoints = locked;
|
||||
UpdateDisabledState();
|
||||
}
|
||||
|
||||
private void UpdateDisabledState()
|
||||
{
|
||||
var isSelected = TraitCheckbox.Pressed;
|
||||
var conditionLocked = !MeetsConditions;
|
||||
var categoryLocked = _isLockedByCategory && !isSelected;
|
||||
var pointsLocked = _isLockedByPoints && !isSelected;
|
||||
var isDisabled = conditionLocked || categoryLocked || pointsLocked;
|
||||
|
||||
if (isDisabled)
|
||||
if (!MeetsConditions)
|
||||
{
|
||||
// Hide checkbox, show lock icon
|
||||
TraitCheckbox.Visible = false;
|
||||
LockIcon.Visible = true;
|
||||
|
||||
if (isSelected && conditionLocked)
|
||||
// Deselect if conditions no longer met
|
||||
if (TraitCheckbox.Pressed)
|
||||
{
|
||||
_isUpdating = true;
|
||||
TraitCheckbox.Pressed = false;
|
||||
@@ -322,24 +211,14 @@ public sealed partial class TraitEntry : PanelContainer
|
||||
// Add disabled styling
|
||||
AddStyleClass("TraitsEntryDisabled");
|
||||
|
||||
// Tooltip priority for conditions: condition failures > category full > insufficient points.
|
||||
if (conditionLocked && _failedConditionTooltips.Count > 0)
|
||||
// Update tooltip to show failed conditions
|
||||
if (_failedConditionTooltips.Count > 0)
|
||||
{
|
||||
var tooltipText = Loc.GetString("trait-conditions-not-met-tooltip",
|
||||
("requirements", string.Join("\n", _failedConditionTooltips)));
|
||||
|
||||
TooltipSupplier = _ => CreateMarkupTooltip(tooltipText);
|
||||
}
|
||||
else if (categoryLocked)
|
||||
{
|
||||
var tooltipText = Loc.GetString("trait-category-full-tooltip");
|
||||
TooltipSupplier = _ => CreateMarkupTooltip(tooltipText);
|
||||
}
|
||||
else if (pointsLocked)
|
||||
{
|
||||
var tooltipText = Loc.GetString("trait-insufficient-points-tooltip");
|
||||
TooltipSupplier = _ => CreateMarkupTooltip(tooltipText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -154,18 +154,14 @@ public sealed partial class TraitsTab : BoxContainer
|
||||
}
|
||||
}
|
||||
|
||||
// Check conflicts via TraitDependencyCondition
|
||||
var depCondition = trait.Conditions.OfType<Content.Shared._DV.Traits.Conditions.TraitDependencyCondition>().FirstOrDefault();
|
||||
if (depCondition != null)
|
||||
// Check conflicts
|
||||
foreach (var conflict in trait.Conflicts)
|
||||
{
|
||||
foreach (var conflict in depCondition.Conflicts)
|
||||
{
|
||||
if (!_selectedTraits.Contains(conflict))
|
||||
continue;
|
||||
if (!_selectedTraits.Contains(conflict))
|
||||
continue;
|
||||
|
||||
RevertTraitToggle(traitId);
|
||||
return;
|
||||
}
|
||||
RevertTraitToggle(traitId);
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedTraits.Add(traitId);
|
||||
@@ -180,7 +176,6 @@ public sealed partial class TraitsTab : BoxContainer
|
||||
}
|
||||
|
||||
UpdateGlobalStats();
|
||||
UpdateAllConditions();
|
||||
UpdateCategoryStats(trait.Category);
|
||||
OnTraitsChanged?.Invoke(_selectedTraits);
|
||||
}
|
||||
@@ -216,7 +211,7 @@ public sealed partial class TraitsTab : BoxContainer
|
||||
// If parent width is 0 (not laid out yet), defer until layout happens
|
||||
if (parentWidth > 0)
|
||||
{
|
||||
GlobalPointsBar.SetWidth = (int)((parentWidth - 2) * percentage);
|
||||
GlobalPointsBar.SetWidth = (int)((parentWidth - 2 ) * percentage);
|
||||
_awaitingLayoutUpdate = false;
|
||||
}
|
||||
else if (!_awaitingLayoutUpdate)
|
||||
@@ -240,11 +235,6 @@ public sealed partial class TraitsTab : BoxContainer
|
||||
> 0f => "TraitsProgressBarLow",
|
||||
_ => "TraitsProgressBarEmpty"
|
||||
});
|
||||
|
||||
foreach (var (_, categoryUi) in _categoryUis)
|
||||
{
|
||||
categoryUi.UpdateGlobalPointsLock(remainingPoints);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProgressBarParentResized()
|
||||
@@ -291,7 +281,7 @@ public sealed partial class TraitsTab : BoxContainer
|
||||
foreach (var (_, categoryUi) in _categoryUis)
|
||||
{
|
||||
// If some fork wants to use the top selected job as well, just add that to the UpdateConditions method in the editor
|
||||
categoryUi.UpdateConditions(null, _profile?.Species, _profile?.AntagPreferences, _selectedTraits);
|
||||
categoryUi.UpdateConditions(null, _profile?.Species, _profile?.AntagPreferences);
|
||||
}
|
||||
|
||||
RecalculateStats();
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<Button xmlns="https://spacestation14.io">
|
||||
<TextureRect Name="TextureRect"
|
||||
TextureScale="0.5 0.5"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Stretch="KeepCentered"/>
|
||||
</Button>
|
||||
@@ -1,17 +0,0 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._DV.UserInterfaces;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class IconButton : Button
|
||||
{
|
||||
public Texture? Icon { get => TextureRect.Texture; set => TextureRect.Texture = value; }
|
||||
|
||||
public IconButton()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public sealed class WizdenContentFreeze
|
||||
var protoMan = server.ProtoMan;
|
||||
|
||||
var recipesCount = protoMan.Count<FoodRecipePrototype>();
|
||||
var recipesLimit = 266; // DeltaV - was 218
|
||||
var recipesLimit = 269; // DeltaV - was 218
|
||||
|
||||
if (recipesCount > recipesLimit)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Player; // DeltaV
|
||||
|
||||
namespace Content.Server.AlertLevel;
|
||||
|
||||
@@ -192,8 +191,7 @@ public sealed class AlertLevelSystem : EntitySystem
|
||||
{
|
||||
if (detail.Sound != null)
|
||||
{
|
||||
//var filter = _stationSystem.GetInOwningStation(station); // DeltaV - Global Annoucements
|
||||
var filter = Filter.Empty().AddAllPlayers(); // DeltaV - Global Annoucements
|
||||
var filter = _stationSystem.GetInOwningStation(station);
|
||||
_audio.PlayGlobal(detail.Sound, filter, true, detail.Sound.Params);
|
||||
}
|
||||
else
|
||||
@@ -204,7 +202,7 @@ public sealed class AlertLevelSystem : EntitySystem
|
||||
|
||||
if (announce)
|
||||
{
|
||||
_chatSystem.DispatchGlobalAnnouncement(announcementFull, playSound: playDefault, // DeltaV - Global Annoucements
|
||||
_chatSystem.DispatchStationAnnouncement(station, announcementFull, playDefaultSound: playDefault,
|
||||
colorOverride: detail.Color, sender: stationName);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Audio;
|
||||
|
||||
public sealed partial class ServerGlobalSoundSystem : SharedGlobalSoundSystem // DeltaV - Made Partial
|
||||
public sealed class ServerGlobalSoundSystem : SharedGlobalSoundSystem
|
||||
{
|
||||
[Dependency] private readonly IConsoleHost _conHost = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
|
||||
@@ -184,11 +184,6 @@ public sealed class MetabolizerSystem : SharedMetabolizerSystem
|
||||
|
||||
var rate = entry.MetabolismRate * group.MetabolismRateModifier;
|
||||
|
||||
// BEGIN DeltaV - fix FixedPoint2 truncation flooring low rateModifiers to zero
|
||||
if (rate == FixedPoint2.Zero && entry.MetabolismRate > FixedPoint2.Zero && group.MetabolismRateModifier > 0f)
|
||||
rate = FixedPoint2.Epsilon;
|
||||
// END DeltaV
|
||||
|
||||
// Remove $rate, as long as there's enough reagent there to actually remove that much
|
||||
mostToRemove = FixedPoint2.Clamp(rate, 0, quantity);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Tools;
|
||||
using Content.Shared._DV.Fax; // DeltaV - fax
|
||||
using Content.Shared._DV.Pager; // DeltaV - pagers
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
@@ -91,10 +90,10 @@ public sealed class FaxSystem : EntitySystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<FaxMachineComponent>();
|
||||
while (query.MoveNext(out var uid, out var fax)) // DeltaV - faxes aren't necessarily powered
|
||||
var query = EntityQueryEnumerator<FaxMachineComponent, ApcPowerReceiverComponent>();
|
||||
while (query.MoveNext(out var uid, out var fax, out var receiver))
|
||||
{
|
||||
if (TryComp<ApcPowerReceiverComponent>(uid, out var receiver) && !receiver.Powered) // DeltaV - faxes aren't necessarily powered
|
||||
if (!receiver.Powered)
|
||||
continue;
|
||||
|
||||
ProcessPrintingAnimation(uid, frameTime, fax);
|
||||
@@ -393,7 +392,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
var canCopy = isPaperInserted &&
|
||||
component.SendTimeoutRemaining <= 0 &&
|
||||
component.InsertingTimeRemaining <= 0;
|
||||
var state = new FaxUiState(component.FaxName, component.KnownFaxes, canSend, canCopy, isPaperInserted, component.DestinationFaxAddress, component.SendTimeoutRemaining <= 0); // DeltaV - AI fax
|
||||
var state = new FaxUiState(component.FaxName, component.KnownFaxes, canSend, canCopy, isPaperInserted, component.DestinationFaxAddress);
|
||||
_userInterface.SetUiState(uid, FaxUiKey.Key, state);
|
||||
}
|
||||
|
||||
@@ -462,7 +461,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
/// Copies the paper in the fax. A timeout is set after copying,
|
||||
/// which is shared by the send button.
|
||||
/// </summary>
|
||||
public void Copy(EntityUid uid, FaxMachineComponent? component, BoundUserInterfaceMessage args, EntityUid? item = null) // DeltaV - station AI fax
|
||||
public void Copy(EntityUid uid, FaxMachineComponent? component, FaxCopyMessage args)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
@@ -470,7 +469,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
if (component.SendTimeoutRemaining > 0)
|
||||
return;
|
||||
|
||||
var sendEntity = item ?? component.PaperSlot.Item; // DeltaV - station AI fax
|
||||
var sendEntity = component.PaperSlot.Item;
|
||||
if (sendEntity == null)
|
||||
return;
|
||||
|
||||
@@ -512,7 +511,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
/// Sends message to addressee if paper is set and a known fax is selected
|
||||
/// A timeout is set after sending, which is shared by the copy button.
|
||||
/// </summary>
|
||||
public void Send(EntityUid uid, FaxMachineComponent? component, BoundUserInterfaceMessage args, EntityUid? item = null) // DeltaV - station AI fax
|
||||
public void Send(EntityUid uid, FaxMachineComponent? component, FaxSendMessage args)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
@@ -520,7 +519,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
if (component.SendTimeoutRemaining > 0)
|
||||
return;
|
||||
|
||||
var sendEntity = item ?? component.PaperSlot.Item; // DeltaV - station AI fax
|
||||
var sendEntity = component.PaperSlot.Item;
|
||||
if (sendEntity == null)
|
||||
return;
|
||||
|
||||
@@ -589,6 +588,15 @@ public sealed class FaxSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var faxName = Loc.GetString("fax-machine-popup-source-unknown");
|
||||
|
||||
// BEGIN DeltaV - Refresh Fax IDs before recieving
|
||||
// This will seem odd that we're doing the same if statement twice BUT if its not in the known fax machine list, the
|
||||
// sending fax might not have been online when the current fax machine was refreshed/init'd. So, if its already known,
|
||||
// we don't need to refresh. But if its not known, let's attempt to refresh first, then check the fromAddress in the KnownFaxes.
|
||||
if (fromAddress != null && !component.KnownFaxes.TryGetValue(fromAddress, out var _))
|
||||
Refresh(uid, component);
|
||||
// END DeltaV
|
||||
|
||||
if (fromAddress != null && component.KnownFaxes.TryGetValue(fromAddress, out var fax)) // If message received from unknown fax address
|
||||
faxName = fax;
|
||||
|
||||
@@ -636,10 +644,6 @@ public sealed class FaxSystem : EntitySystem
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"\"{component.FaxName}\" {ToPrettyString(uid):tool} printed {ToPrettyString(printed):subject}: {printout.Content}");
|
||||
// Begin DeltaV - notify on fax printing
|
||||
var evt = new FaxPrintedEvent(printed);
|
||||
RaiseLocalEvent(uid, ref evt);
|
||||
// End DeltaV - notify on fax printing
|
||||
}
|
||||
|
||||
private void NotifyAdmins(string faxName)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Server.RoundEnd; // DeltaV
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -26,29 +25,4 @@ public sealed partial class ZombieRuleComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ZombieShuttleCallPercentage = 0.7f;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The behavior of the round if all zombies are defeated.
|
||||
/// </summary>
|
||||
public RoundEndBehavior ZombieRoundEndBehavior = RoundEndBehavior.ShuttleCall;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The amount of time before the evac shuttle will arrive if the ZombieRoundEndBehavior is set to ShuttleCall.
|
||||
/// </summary>
|
||||
public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(5);
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement sender when calling the shuttle.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextSender = "comms-console-announcement-title-centcom";
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement text when calling a shuttle.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextShuttleCall = "zombie-no-more-threat-announcement-shuttle-call";
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement text when a shuttle is already called.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextAnnouncement = "zombie-no-more-threat-announcement";
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ using System.Linq;
|
||||
using Content.Shared.Station.Components;
|
||||
using Content.Shared.Store.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Cuffs.Components; // DeltaV
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
@@ -501,23 +500,12 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
||||
// Check if there are nuke operatives still alive on the same map as the shuttle,
|
||||
// or on the same map as the station.
|
||||
// If there are, the round can continue.
|
||||
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
// We need to use a EntityQueryEnumerator instead of a EntityQuery, because we need the uid to check for cuffs
|
||||
var operatives = new List<Entity<NukeOperativeComponent, MobStateComponent, TransformComponent>>();
|
||||
var operativesEnumerator = EntityQueryEnumerator<NukeOperativeComponent, MobStateComponent, TransformComponent>();
|
||||
while (operativesEnumerator.MoveNext(out var uid, out var nukeOp, out var mobState, out var transform))
|
||||
{
|
||||
operatives.Add((uid, nukeOp, mobState, transform));
|
||||
}
|
||||
|
||||
var operatives = EntityQuery<NukeOperativeComponent, MobStateComponent, TransformComponent>(true);
|
||||
var operativesAlive = operatives
|
||||
.Where(op =>
|
||||
op.Comp3.MapID == shuttleMapId
|
||||
|| op.Comp3.MapID == targetStationMap)
|
||||
.Any(op => op.Comp2.CurrentState == MobState.Alive && op.Comp1.Running &&
|
||||
!TryComp<CuffableComponent>(op, out _)); // in the case the crew keeps one alive
|
||||
// END DeltaV
|
||||
op.Item3.MapID == shuttleMapId
|
||||
|| op.Item3.MapID == targetStationMap)
|
||||
.Any(op => op.Item2.CurrentState == MobState.Alive && op.Item1.Running);
|
||||
|
||||
if (operativesAlive)
|
||||
return; // There are living operatives than can access the shuttle, or are still on the station's map.
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.RoundEnd; // DeltaV
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
@@ -114,31 +114,11 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
||||
/// </summary>
|
||||
private void CheckRoundEnd(ZombieRuleComponent zombieRuleComponent)
|
||||
{
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
// Zombies have failed, time to go home
|
||||
if (zombieRuleComponent.ZombieRoundEndBehavior == RoundEndBehavior.Nothing)
|
||||
return;
|
||||
// END DeltaV
|
||||
|
||||
var healthy = GetHealthyHumans();
|
||||
if (healthy.Count == 1) // Only one human left. spooky
|
||||
_popup.PopupEntity(Loc.GetString("zombie-alone"), healthy[0], healthy[0]);
|
||||
|
||||
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
var infectedPercent = GetInfectedFraction(false);
|
||||
if (Math.Round(infectedPercent, 0) == 0) // All zombies defeated
|
||||
{
|
||||
_roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior,
|
||||
zombieRuleComponent.EvacShuttleTime,
|
||||
zombieRuleComponent.RoundEndTextSender,
|
||||
zombieRuleComponent.RoundEndTextShuttleCall,
|
||||
zombieRuleComponent.RoundEndTextAnnouncement);
|
||||
zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future
|
||||
}
|
||||
// END DeltaV
|
||||
|
||||
if (infectedPercent > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested()) // DeltaV - Move GetInfectedFraction to var
|
||||
if (GetInfectedFraction(false) > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested())
|
||||
{
|
||||
foreach (var station in _station.GetStations())
|
||||
{
|
||||
|
||||
@@ -327,15 +327,15 @@ public sealed class NukeSystem : EntitySystem
|
||||
// should play
|
||||
if (nuke.RemainingTime <= _nukeSongLength + nuke.AlertSoundTime + NukeSongBuffer && !nuke.PlayedNukeSong && !ResolvedSoundSpecifier.IsNullOrEmpty(_selectedNukeSong))
|
||||
{
|
||||
_sound.DispatchGlobalEventMusic(_selectedNukeSong, StationEventMusicType.Nuke); // DeltaV - Global Nuke Music
|
||||
_sound.DispatchStationEventMusic(uid, _selectedNukeSong, StationEventMusicType.Nuke);
|
||||
nuke.PlayedNukeSong = true;
|
||||
}
|
||||
|
||||
// play alert sound if time is running out
|
||||
if (nuke.RemainingTime <= nuke.AlertSoundTime && !nuke.PlayedAlertSound)
|
||||
{
|
||||
_sound.PlayGlobal(_audio.ResolveSound(nuke.AlertSound), new AudioParams { Volume = -5f }); // DeltaV - Global Nuke SFX
|
||||
_sound.StopGlobalEventMusic(StationEventMusicType.Nuke); // DeltaV - Global Nuke Music
|
||||
_sound.PlayGlobalOnStation(uid, _audio.ResolveSound(nuke.AlertSound), new AudioParams{Volume = -5f});
|
||||
_sound.StopStationEventMusic(uid, StationEventMusicType.Nuke);
|
||||
nuke.PlayedAlertSound = true;
|
||||
UpdateAppearance(uid, nuke);
|
||||
}
|
||||
@@ -504,9 +504,9 @@ public sealed class NukeSystem : EntitySystem
|
||||
("time", (int) component.RemainingTime),
|
||||
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((uid, nukeXform)))));
|
||||
var sender = Loc.GetString("nuke-component-announcement-sender");
|
||||
_chatSystem.DispatchGlobalAnnouncement(announcement, sender, false, null, Color.Red); // DeltaV - Global Nuke Annoucement
|
||||
_chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red);
|
||||
|
||||
_sound.PlayGlobal(_audio.ResolveSound(component.ArmSound)); // DeltaV - Global Nuke Music
|
||||
_sound.PlayGlobalOnStation(uid, _audio.ResolveSound(component.ArmSound));
|
||||
_nukeSongLength = (float) _audio.GetAudioLength(_selectedNukeSong).TotalSeconds;
|
||||
|
||||
// turn on the spinny light
|
||||
@@ -544,11 +544,11 @@ public sealed class NukeSystem : EntitySystem
|
||||
// warn a crew
|
||||
var announcement = Loc.GetString("nuke-component-announcement-unarmed");
|
||||
var sender = Loc.GetString("nuke-component-announcement-sender");
|
||||
_chatSystem.DispatchGlobalAnnouncement(announcement, sender, false); // DeltaV - Global Nuke Announcement
|
||||
_chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false);
|
||||
|
||||
component.PlayedNukeSong = false;
|
||||
_sound.PlayGlobal(_audio.ResolveSound(component.DisarmSound)); // DeltaV - Global Nuke SFX
|
||||
_sound.StopGlobalEventMusic(StationEventMusicType.Nuke); // DeltaV - Global Nuke Music
|
||||
_sound.PlayGlobalOnStation(uid, _audio.ResolveSound(component.DisarmSound));
|
||||
_sound.StopStationEventMusic(uid, StationEventMusicType.Nuke);
|
||||
|
||||
// reset nuke remaining time to either itself or the minimum time, whichever is higher
|
||||
component.RemainingTime = Math.Max(component.RemainingTime, component.MinimumTime);
|
||||
@@ -610,7 +610,7 @@ public sealed class NukeSystem : EntitySystem
|
||||
OwningStation = transform.GridUid,
|
||||
});
|
||||
|
||||
_sound.StopGlobalEventMusic(StationEventMusicType.Nuke); // DeltaV - Global Nuke Music
|
||||
_sound.StopStationEventMusic(uid, StationEventMusicType.Nuke);
|
||||
Del(uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,8 +157,7 @@ public sealed class RadioSystem : EntitySystem
|
||||
message,
|
||||
wrappedMessage,
|
||||
NetEntity.Invalid,
|
||||
null,
|
||||
radioChannelProto: channel.ID); // DeltaV - Add RadioChannel for committing sins
|
||||
null);
|
||||
var chatMsg = new MsgChatMessage { Message = chat };
|
||||
var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg);
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ namespace Content.Server.RoundEnd
|
||||
else
|
||||
{
|
||||
RequestRoundEnd(time, null, false, textCall,
|
||||
Loc.GetString(sender), cantRecall: true);
|
||||
Loc.GetString(sender));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,41 +6,4 @@ namespace Content.Server.StationEvents.Components;
|
||||
[RegisterComponent]
|
||||
public sealed partial class IonStormRuleComponent : Component
|
||||
{
|
||||
// DV start - Synthetic tweaks
|
||||
/// <summary>
|
||||
/// The chance that a synth gets electrocuted by the ion storm.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float SynthElectrocutionChance = 0.6f;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum delay before a synth affected by the ion storm gets electrocuted. (in seconds)
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int SynthElectrocutionDelayMin = 3;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum delay before a synth affected by the ion storm gets electrocuted. (in seconds)
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int SynthElectrocutionDelayMax = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum damage dealt by the synth electrocution. (shock damage)
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int SynthElectrocutionDamageMin = 5;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum damage dealt by the synth electrocution. (shock damage)
|
||||
/// </summary>8
|
||||
[DataField]
|
||||
public int SynthElectrocutionDamageMax = 10;
|
||||
|
||||
/// <summary>
|
||||
/// How long the synth is stunned for by the electrocution. (in seconds)
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int SynthElectrocutionStunDuration = 3;
|
||||
// DV end - synthetic tweaks
|
||||
}
|
||||
|
||||
@@ -6,12 +6,9 @@ using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Station.Components;
|
||||
// CD - start synth trait
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Electrocution; // DV - added for synth trait
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared._ES.Sparks; // Delta-V change - added for synth trait (where they get affected by ion storms)
|
||||
using Timer = Robust.Shared.Timing.Timer; // DV - used for synth trait delayed damage
|
||||
// CD - end synth trait
|
||||
|
||||
namespace Content.Server.StationEvents.Events;
|
||||
@@ -20,8 +17,6 @@ public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly IonStormSystem _ionStorm = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!; // CD - Used for synth trait
|
||||
[Dependency] private readonly ElectrocutionSystem _electrocution = default!; // DV - used for synth trait
|
||||
[Dependency] private readonly ESSparksSystem _esSparks = default!; // DV - used for synth trait
|
||||
|
||||
protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
||||
{
|
||||
@@ -31,32 +26,18 @@ public sealed class IonStormRule : StationEventSystem<IonStormRuleComponent>
|
||||
return;
|
||||
|
||||
// CD - Go through everyone with the SynthComponent and inform them a storm is happening.
|
||||
// DV - buuuuuut only if IonStormAffected is present so that not all synthetics are affected by this
|
||||
// but they are still notified about incoming ion storms regardless.
|
||||
var synthQuery = EntityQueryEnumerator<SynthComponent>();
|
||||
while (synthQuery.MoveNext(out var ent, out var synthComp))
|
||||
{
|
||||
if (RobustRandom.Prob(synthComp.AlertChance))
|
||||
continue;
|
||||
|
||||
if (!TryComp<ActorComponent>(ent, out var actor))
|
||||
continue;
|
||||
|
||||
if (RobustRandom.Prob(synthComp.AlertChance))
|
||||
{
|
||||
var msg = Loc.GetString("station-event-ion-storm-synth");
|
||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
|
||||
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Yellow);
|
||||
}
|
||||
|
||||
// DV start - super duper fucked up thing for synths
|
||||
if (synthComp.IonStormAffected && RobustRandom.Prob(comp.SynthElectrocutionChance))
|
||||
{
|
||||
var delay = RobustRandom.Next(TimeSpan.FromSeconds(comp.SynthElectrocutionDelayMin), TimeSpan.FromSeconds(comp.SynthElectrocutionDelayMax)); // they'll never know when it'll hit them
|
||||
Timer.Spawn(delay, () =>
|
||||
{
|
||||
_electrocution.TryDoElectrocution(ent, null, RobustRandom.Next(comp.SynthElectrocutionDamageMin, comp.SynthElectrocutionDamageMax), TimeSpan.FromSeconds(comp.SynthElectrocutionStunDuration), true, ignoreInsulation: true);
|
||||
_esSparks.DoSparks(ent);
|
||||
});
|
||||
}
|
||||
// DV end
|
||||
var msg = Loc.GetString("station-event-ion-storm-synth");
|
||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
|
||||
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Yellow);
|
||||
}
|
||||
// CD - End of synth trait
|
||||
|
||||
|
||||
@@ -7,16 +7,7 @@ namespace Content.Server._CD.Traits;
|
||||
public sealed partial class SynthComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this synthetic is affected by ion storms (electrocution/sparks and
|
||||
/// alerts when one occurs). False by default. set true by the
|
||||
/// "Susceptible to Ion Storms" meta trait.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool IonStormAffected;
|
||||
|
||||
/// <summary>
|
||||
/// The chance that the synth is alerted of an ion storm. Only relevant if
|
||||
/// <see cref="IonStormAffected"/> is true.
|
||||
/// The chance that the synth is alerted of an ion storm
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float AlertChance = 0.3f;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Chat.TypingIndicator;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Speech.Components;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CD.Traits;
|
||||
@@ -15,13 +12,9 @@ public sealed class SynthSystem : EntitySystem
|
||||
// Begin DeltaV - make strings static readonly
|
||||
private static readonly ProtoId<TypingIndicatorPrototype> RobotTypingIndicator = "robot";
|
||||
private static readonly ProtoId<ReagentPrototype> SynthBloodReagent = "SynthBlood";
|
||||
private static readonly ProtoId<TagPrototype> SyntheticEmotesTag = "SyntheticEmotes";
|
||||
private static readonly ProtoId<EmoteSoundsPrototype> SyntheticEmoteSounds = "SyntheticEmoteSounds";
|
||||
// End DeltaV
|
||||
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -45,21 +38,5 @@ public sealed class SynthSystem : EntitySystem
|
||||
_bloodstream.ChangeBloodReagents((uid, bloodstream), new([new(SynthBloodReagent, bloodstream.BloodReferenceSolution.Volume)]));
|
||||
}
|
||||
// End DeltaV
|
||||
|
||||
// Begin DeltaV - Add SyntheticEmotes tag and merge synthetic emote sounds into species sounds
|
||||
_tag.AddTag(uid, SyntheticEmotesTag);
|
||||
|
||||
if (TryComp<VocalComponent>(uid, out var vocal)
|
||||
&& _proto.TryIndex(SyntheticEmoteSounds, out var synthSounds)
|
||||
&& vocal.EmoteSounds is { } currentSoundsId
|
||||
&& _proto.TryIndex(currentSoundsId, out var currentSounds))
|
||||
{
|
||||
foreach (var (emoteId, sound) in synthSounds.Sounds)
|
||||
{
|
||||
currentSounds.Sounds.TryAdd(emoteId, sound);
|
||||
}
|
||||
Dirty(uid, vocal);
|
||||
}
|
||||
// End DeltaV
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
using Content.Shared.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Audio;
|
||||
|
||||
/// <summary>
|
||||
/// Extends upstream's Content.Server/Audio/ServerGlobalSoundSystem.cs.
|
||||
/// </summary>
|
||||
public sealed partial class ServerGlobalSoundSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// DeltaV - Plays a sound globally for all players, no matter where they are.
|
||||
/// </summary>
|
||||
/// <param name="specifier"></param>
|
||||
/// <param name="audioParams"></param>
|
||||
public void PlayGlobal(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null)
|
||||
{
|
||||
var msg = new GameGlobalSoundEvent(specifier, audioParams);
|
||||
RaiseNetworkEvent(msg);
|
||||
}
|
||||
|
||||
public void StopGlobalEventMusic(StationEventMusicType type)
|
||||
{
|
||||
var msg = new StopStationEventMusic(type);
|
||||
RaiseNetworkEvent(msg);
|
||||
}
|
||||
|
||||
public void DispatchGlobalEventMusic(SoundSpecifier sound, StationEventMusicType type)
|
||||
{
|
||||
DispatchGlobalEventMusic(_audio.ResolveSound(sound), type);
|
||||
}
|
||||
|
||||
public void DispatchGlobalEventMusic(ResolvedSoundSpecifier specifier, StationEventMusicType type)
|
||||
{
|
||||
var audio = AudioParams.Default.WithVolume(-8);
|
||||
var msg = new StationEventMusicEvent(specifier, type, audio);
|
||||
RaiseNetworkEvent(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - Plays a sound globally for all players on a specified Map.
|
||||
/// </summary>
|
||||
/// <param name="specifier"></param>
|
||||
/// <param name="audioParams"></param>
|
||||
public void PlayGlobalOnMap(MapId map, ResolvedSoundSpecifier specifier, AudioParams? audioParams = null)
|
||||
{
|
||||
var msg = new GameGlobalSoundEvent(specifier, audioParams);
|
||||
var filter = Filter.Empty().AddInMap(map);
|
||||
RaiseNetworkEvent(msg, filter);
|
||||
}
|
||||
|
||||
public void StopMapEventMusic(MapId map, StationEventMusicType type)
|
||||
{
|
||||
var msg = new StopStationEventMusic(type);
|
||||
var filter = Filter.Empty().AddInMap(map);
|
||||
RaiseNetworkEvent(msg, filter);
|
||||
}
|
||||
|
||||
public void DispatchMapEventMusic(MapId map, SoundSpecifier sound, StationEventMusicType type)
|
||||
{
|
||||
DispatchMapEventMusic(map, _audio.ResolveSound(sound), type);
|
||||
}
|
||||
|
||||
public void DispatchMapEventMusic(MapId map, ResolvedSoundSpecifier specifier, StationEventMusicType type)
|
||||
{
|
||||
var audio = AudioParams.Default.WithVolume(-8);
|
||||
var msg = new StationEventMusicEvent(specifier, type, audio);
|
||||
var filter = Filter.Empty().AddInMap(map);
|
||||
RaiseNetworkEvent(msg, filter);
|
||||
}
|
||||
}
|
||||
@@ -61,39 +61,6 @@ public sealed partial class CosmicCultRuleComponent : Component
|
||||
[DataField]
|
||||
public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(5);
|
||||
|
||||
#region Progress Checking
|
||||
/// <summary>
|
||||
/// The next time the monument should check the progress of the cult.
|
||||
/// </summary>
|
||||
public TimeSpan NextProgressCheck = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time between progress checks.
|
||||
/// </summary>
|
||||
public TimeSpan TimeBetweenProgressChecks = TimeSpan.FromMinutes(15);
|
||||
|
||||
/// <summary>
|
||||
/// The progress value of the monument last time it was checked.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int LastProgress = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The number of times the the progress check as failed. Resets after some progress.
|
||||
/// </summary>
|
||||
public int ConsecutiveProgressFails = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The number of times the progress check has to fail for the round to start to end.
|
||||
/// </summary>
|
||||
public int ProgressFailureTolerance = 3;
|
||||
|
||||
public LocId ProgressFailTextShuttleCall = "cosmiccult-progress-fail-shuttle-call";
|
||||
|
||||
public LocId ProgressFailTextAnnouncement = "cosmiccult-progress-fail-announcement";
|
||||
|
||||
#endregion
|
||||
|
||||
[DataField]
|
||||
public HashSet<EntityUid> Cultists = [];
|
||||
|
||||
|
||||
@@ -62,15 +62,13 @@ using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Content.Shared.StatusIcon;
|
||||
using Content.Shared.SSDIndicator;
|
||||
|
||||
namespace Content.Server._DV.CosmicCult;
|
||||
|
||||
/// <summary>
|
||||
/// Where all the main stuff for Cosmic Cultists happens.
|
||||
/// </summary>
|
||||
public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponent>
|
||||
public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
@@ -174,28 +172,6 @@ public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRule
|
||||
component.StewardVoteTimer = null;
|
||||
StewardVote();
|
||||
}
|
||||
|
||||
// Progress check. Is the cult trying to progress at all?
|
||||
if (component.MonumentPlaced && _timing.CurTime > component.NextProgressCheck)
|
||||
{
|
||||
// We're going to assume one monument.
|
||||
var monument = EntityQuery<MonumentComponent>().First();
|
||||
if (component.LastProgress == monument.CurrentProgress)
|
||||
component.ConsecutiveProgressFails++;
|
||||
else
|
||||
component.ConsecutiveProgressFails = 0;
|
||||
|
||||
// They haven't progressed enough in X checks, end the round.
|
||||
if (component.ConsecutiveProgressFails >= component.ProgressFailureTolerance) {
|
||||
SetWinType((uid, component), WinType.CrewMinor);
|
||||
_roundEnd.DoRoundEndBehavior(component.RoundEndBehavior, component.EvacShuttleTime, component.RoundEndTextSender, component.ProgressFailTextShuttleCall, component.ProgressFailTextAnnouncement);
|
||||
component.RoundEndBehavior = RoundEndBehavior.Nothing;
|
||||
}
|
||||
|
||||
component.LastProgress = monument.CurrentProgress;
|
||||
component.NextProgressCheck = _timing.CurTime + component.TimeBetweenProgressChecks;
|
||||
}
|
||||
|
||||
if (component.ExtraRiftTimer is { } riftTimer && _timing.CurTime >= riftTimer && !component.RiftStop)
|
||||
{
|
||||
component.ExtraRiftTimer = _timing.CurTime + _rand.Next(TimeSpan.FromSeconds(230), TimeSpan.FromSeconds(360)); //3min50 to 6min between new rifts. Seconds instead of minutes for granularity.
|
||||
@@ -466,19 +442,17 @@ public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRule
|
||||
}
|
||||
}
|
||||
|
||||
private int GetCultistsAlive()
|
||||
private bool CultistsAlive()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CosmicCultComponent, MobStateComponent>();
|
||||
int cultistsAlive = 0;
|
||||
while (query.MoveNext(out var ent, out _, out var mobComp))
|
||||
{
|
||||
if (TryComp<CuffableComponent>(ent, out var cuffed) && cuffed.CuffedHandCount > 0) continue;
|
||||
if (TryComp<SSDIndicatorComponent>(ent, out var ssd) && ssd.IsSSD) continue; // TODO: Maybe check how long.
|
||||
if (mobComp.Running && mobComp.CurrentState != MobState.Dead)
|
||||
cultistsAlive++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return cultistsAlive;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(Entity<CosmicCultComponent> ent, ref MobStateChangedEvent args)
|
||||
@@ -493,19 +467,14 @@ public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRule
|
||||
|
||||
private void CheckForActiveCultists()
|
||||
{
|
||||
// A lone cultist can't do anything, so check for more than one.
|
||||
if (GetCultistsAlive() > 1)
|
||||
if (CultistsAlive())
|
||||
return;
|
||||
|
||||
var query = QueryActiveRules();
|
||||
List<Entity<CosmicCultRuleComponent>> cosCultRules = new();
|
||||
|
||||
// ConfirmWinState needs to be outside the query, because it might add an active rule
|
||||
while (query.MoveNext(out var ruleUid, out _, out var ruleComp, out _))
|
||||
{
|
||||
cosCultRules.Add((ruleUid, ruleComp));
|
||||
ConfirmWinState((ruleUid, ruleComp));
|
||||
}
|
||||
cosCultRules.ForEach(ConfirmWinState);
|
||||
}
|
||||
|
||||
private void ConfirmWinState(Entity<CosmicCultRuleComponent> ent)
|
||||
@@ -535,6 +504,8 @@ public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRule
|
||||
else
|
||||
SetWinType(ent, WinType.Neutral); //The monument wasn't completed, no cultists escaped to midpoint. Some cultists still remain on the station, though.
|
||||
|
||||
if (CultistsAlive()) return; //If there are no cultists alive, ignore all previous checks, crew alreay won.
|
||||
|
||||
if (tier <= 1) //Prevent the cult getting cooked by accident before anyone even knows there's a cult.
|
||||
{
|
||||
SetWinType(ent, WinType.CrewMinor); //If we somehow get here at the end of the round, we'll still count this as a crew minor.
|
||||
@@ -550,7 +521,7 @@ public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRule
|
||||
{
|
||||
finComp.CurrentState = FinaleState.Unavailable;
|
||||
_popup.PopupCoordinates(Loc.GetString("cosmiccult-monument-powerdown"), Transform(gameruleMonument).Coordinates, PopupType.Large);
|
||||
_sound.StopGlobalEventMusic(StationEventMusicType.CosmicCult);
|
||||
_sound.StopStationEventMusic(gameruleMonument, StationEventMusicType.CosmicCult);
|
||||
_monument.UpdateMonumentAppearance(gameruleMonument, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,9 +82,11 @@ public sealed partial class CosmicCultSystem : SharedCosmicCultSystem
|
||||
|
||||
_corrupting.SetCorruptionTime((uid, corruptingComp), TimeSpan.FromSeconds(1));
|
||||
_appearance.SetData(uid, MonumentVisuals.FinaleReached, 2);
|
||||
_sound.DispatchGlobalEventMusic(comp.SelectedSong, StationEventMusicType.CosmicCult);
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cosmiccult-finale-location", ("location", indicatedLocation)),
|
||||
null, false, null, Color.FromHex("#cae8e8"));
|
||||
_sound.DispatchStationEventMusic(uid, comp.SelectedSong, StationEventMusicType.CosmicCult);
|
||||
_chatSystem.DispatchStationAnnouncement(uid,
|
||||
Loc.GetString("cosmiccult-finale-location", ("location", indicatedLocation)),
|
||||
null, false, null,
|
||||
Color.FromHex("#cae8e8"));
|
||||
|
||||
var stationUid = _station.GetStationInMap(Transform(uid).MapID);
|
||||
if (stationUid != null)
|
||||
@@ -126,8 +128,8 @@ public sealed partial class CosmicCultSystem : SharedCosmicCultSystem
|
||||
if (stationUid != null)
|
||||
_alert.SetLevel(stationUid.Value, "green", true, true, true);
|
||||
|
||||
_sound.PlayGlobal(_audio.ResolveSound(comp.CancelEventSound));
|
||||
_sound.StopGlobalEventMusic(StationEventMusicType.CosmicCult);
|
||||
_sound.PlayGlobalOnStation(uid, _audio.ResolveSound(comp.CancelEventSound));
|
||||
_sound.StopStationEventMusic(uid, StationEventMusicType.CosmicCult);
|
||||
uid.Comp.CurrentState = FinaleState.ReadyFinale;
|
||||
|
||||
if (TryComp<CosmicCorruptingComponent>(uid, out var corruptingComp))
|
||||
|
||||
@@ -8,7 +8,6 @@ using Content.Shared.Mind;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -26,7 +25,6 @@ public sealed class CosmicChantrySystem : EntitySystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||
|
||||
/// <summary>
|
||||
@@ -81,11 +79,11 @@ public sealed class CosmicChantrySystem : EntitySystem
|
||||
comp.SpawnTimer = _timing.CurTime + comp.SpawningTime;
|
||||
comp.CountdownTimer = _timing.CurTime + comp.EventTime;
|
||||
|
||||
var targetMap = _transform.GetMapId(ent.Owner);
|
||||
_sound.PlayGlobalOnMap(targetMap, _audio.ResolveSound(comp.ChantryAlarm));
|
||||
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cosmiccult-chantry-location",
|
||||
("location", indicatedLocation)), null, false, null, Color.FromHex("#cae8e8"));
|
||||
_sound.PlayGlobalOnStation(ent, _audio.ResolveSound(comp.ChantryAlarm));
|
||||
_chatSystem.DispatchStationAnnouncement(ent,
|
||||
Loc.GetString("cosmiccult-chantry-location", ("location", indicatedLocation)),
|
||||
null, false, null,
|
||||
Color.FromHex("#cae8e8"));
|
||||
|
||||
if (_mind.TryGetMind(comp.InternalVictim, out _, out var mind))
|
||||
mind.PreventGhosting = true;
|
||||
|
||||
@@ -79,13 +79,13 @@ public sealed class MonumentSystem : SharedMonumentSystem
|
||||
{
|
||||
comp.SongTimer = null;
|
||||
if (comp.SelectedSong is { } song)
|
||||
_sound.DispatchGlobalEventMusic(song, StationEventMusicType.CosmicCult);
|
||||
_sound.DispatchStationEventMusic(uid, song, StationEventMusicType.CosmicCult);
|
||||
}
|
||||
|
||||
if (comp.CurrentState == FinaleState.ActiveFinale && comp.FinaleAnnounceCheck && comp.FinaleTimer - _timing.CurTime < comp.VisualsThreshold)
|
||||
{
|
||||
_appearance.SetData(uid, MonumentVisuals.FinaleReached, 3);
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cosmiccult-announce-finale-warning"), null, false, null, Color.FromHex("#cae8e8"));
|
||||
_chatSystem.DispatchStationAnnouncement(uid, Loc.GetString("cosmiccult-announce-finale-warning"), null, false, null, Color.FromHex("#cae8e8"));
|
||||
comp.FinaleAnnounceCheck = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,6 @@ public sealed class DeepFryerSystem : SharedDeepFryerSystem
|
||||
private void OnPowerChanged(Entity<DeepFryerComponent> ent, ref PowerChangedEvent args)
|
||||
{
|
||||
UpdateAppearance(ent);
|
||||
ResetCookingItemsStartTime(ent);
|
||||
}
|
||||
|
||||
private void OnThrowHitBy(Entity<DeepFryerComponent> ent, ref ThrowHitByEvent args)
|
||||
@@ -675,26 +674,4 @@ public sealed class DeepFryerSystem : SharedDeepFryerSystem
|
||||
// Add the split solution to the food
|
||||
Solution.AddSolution(foodSolutionEnt.Value, transferredSolution);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the starttime for cooking items (on power change)
|
||||
/// </summary>
|
||||
private void ResetCookingItemsStartTime(Entity<DeepFryerComponent> ent)
|
||||
{
|
||||
if (_power.IsPowered(ent.Owner) && !ent.Comp.WasPreviouslyPowered)
|
||||
{
|
||||
// Power just came back on - reset all cooking timers
|
||||
foreach (var itemUid in ent.Comp.CookingItems.Keys.ToList())
|
||||
{
|
||||
var cookingItem = ent.Comp.CookingItems[itemUid];
|
||||
cookingItem.TimeStarted = _timing.CurTime;
|
||||
ent.Comp.CookingItems[itemUid] = cookingItem;
|
||||
}
|
||||
ent.Comp.WasPreviouslyPowered = true;
|
||||
}
|
||||
else if (!_power.IsPowered(ent.Owner) && ent.Comp.WasPreviouslyPowered)
|
||||
{
|
||||
ent.Comp.WasPreviouslyPowered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
using Content.Server.Fax;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Fax;
|
||||
using Content.Shared.Fax.Components;
|
||||
|
||||
namespace Content.Server._DV.Silicons;
|
||||
|
||||
public sealed class StationAiFaxSystem : SharedStationAiFaxSystem
|
||||
{
|
||||
[Dependency] private readonly FaxSystem _fax = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Subs.BuiEvents<StationAiFaxComponent>(FaxUiKey.Key,
|
||||
subs =>
|
||||
{
|
||||
subs.Event<StationAiFaxSendMessage>(OnSend);
|
||||
subs.Event<StationAiFaxDuplicateMessage>(OnDuplicate);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnSend(Entity<StationAiFaxComponent> ent, ref StationAiFaxSendMessage args)
|
||||
{
|
||||
if (GetDocument(ent, args.Document) is not { } document)
|
||||
return;
|
||||
|
||||
_fax.Send(ent, Comp<FaxMachineComponent>(ent), args, document);
|
||||
}
|
||||
|
||||
private void OnDuplicate(Entity<StationAiFaxComponent> ent, ref StationAiFaxDuplicateMessage args)
|
||||
{
|
||||
if (GetDocument(ent, args.Document) is not { } document)
|
||||
return;
|
||||
|
||||
_fax.Copy(ent, Comp<FaxMachineComponent>(ent), args, document);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server._DV.StationEvents.Events;
|
||||
using Content.Server.StationEvents.Events;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._DV.StationEvents.Components;
|
||||
namespace Content.Server.StationEvents.Components;
|
||||
|
||||
/// <summary>
|
||||
/// When fired, turns off power on the station for a few seconds, playing <see cref="EpsilonEventRuleComponent.PowerOffSound"/>
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.StationEvents.Events;
|
||||
using Content.Server.StationEvents.Components;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Station.Components;
|
||||
using Content.Server.AlertLevel;
|
||||
using Content.Server.Audio;
|
||||
using Content.Server._DV.StationEvents.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
||||
namespace Content.Server._DV.StationEvents.Events;
|
||||
|
||||
namespace Content.Server.StationEvents.Events
|
||||
{
|
||||
public sealed class EpsilonEventRule : StationEventSystem<EpsilonEventRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly ApcSystem _apcSystem = default!;
|
||||
@@ -26,7 +25,7 @@ public sealed class EpsilonEventRule : StationEventSystem<EpsilonEventRuleCompon
|
||||
return;
|
||||
component.AffectedStation = chosenStation.Value;
|
||||
|
||||
// Plays the power off sound for those who are on the station.
|
||||
// Plays the power off sound to the station.
|
||||
_sound.PlayGlobalOnStation(component.AffectedStation, _audio.ResolveSound(component.PowerOffSound));
|
||||
|
||||
var query = AllEntityQuery<ApcComponent, TransformComponent>();
|
||||
@@ -71,3 +70,4 @@ public sealed class EpsilonEventRule : StationEventSystem<EpsilonEventRuleCompon
|
||||
_alertLevelSystem.SetLevel(component.AffectedStation, "epsilon", true, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,7 @@ public sealed class TraitSystem : EntitySystem
|
||||
JobId = jobId,
|
||||
SpeciesId = speciesId,
|
||||
Profile = profile,
|
||||
StatusEffects = _statusEffects,
|
||||
SelectedTraits = selectedTraits
|
||||
StatusEffects = _statusEffects
|
||||
};
|
||||
|
||||
foreach (var traitId in selectedTraits)
|
||||
|
||||
@@ -41,13 +41,7 @@ namespace Content.Shared.Chat
|
||||
[NonSerialized]
|
||||
public bool Read;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - If not null, contains the radio channel proto ID that the message was sent on.
|
||||
/// Used to replace the channel color client-side.
|
||||
/// </summary>
|
||||
public string? RadioChannelProtoId = null;
|
||||
|
||||
public ChatMessage(ChatChannel channel, string message, string wrappedMessage, NetEntity source, int? senderKey, bool hideChat = false, Color? colorOverride = null, string? audioPath = null, float audioVolume = 0, string? radioChannelProto = null) // DeltaV - added radioChannelProto
|
||||
public ChatMessage(ChatChannel channel, string message, string wrappedMessage, NetEntity source, int? senderKey, bool hideChat = false, Color? colorOverride = null, string? audioPath = null, float audioVolume = 0)
|
||||
{
|
||||
Channel = channel;
|
||||
Message = message;
|
||||
@@ -58,7 +52,6 @@ namespace Content.Shared.Chat
|
||||
MessageColorOverride = colorOverride;
|
||||
AudioPath = audioPath;
|
||||
AudioVolume = audioVolume;
|
||||
RadioChannelProtoId = radioChannelProto; // DeltaV
|
||||
}
|
||||
|
||||
public ChatMessage(ChatMessage copyFrom)
|
||||
@@ -73,7 +66,6 @@ namespace Content.Shared.Chat
|
||||
AudioPath = copyFrom.AudioPath;
|
||||
AudioVolume = copyFrom.AudioVolume;
|
||||
Read = copyFrom.Read;
|
||||
RadioChannelProtoId = copyFrom.RadioChannelProtoId; // DeltaV
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ using System.Linq;
|
||||
using Content.Shared.Eye.Blinding.Components;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory; // Harmony - for lanyards
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using JetBrains.Annotations;
|
||||
@@ -294,7 +293,7 @@ namespace Content.Shared.Examine
|
||||
/// If you're pushing multiple messages that should be grouped together (or ordered in some way),
|
||||
/// call <see cref="PushGroup"/> before pushing and <see cref="PopGroup"/> when finished.
|
||||
/// </summary>
|
||||
public sealed class ExaminedEvent : EntityEventArgs, IInventoryRelayEvent //Harmony InventoryRelayEvent for Lanyards
|
||||
public sealed class ExaminedEvent : EntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The message that will be displayed as the examine text.
|
||||
@@ -530,7 +529,6 @@ namespace Content.Shared.Examine
|
||||
}
|
||||
|
||||
private record ExamineMessagePart(FormattedMessage Message, int Priority, bool DoNewLine, string? Group);
|
||||
public SlotFlags TargetSlots { get; } = SlotFlags.NECK; // Harmony - For targeting lanyards.
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public sealed partial class FaxMachineComponent : Component
|
||||
/// Sound to play when fax printing new message
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier? PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg"); // DeltaV - nullable
|
||||
public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Sound to play when fax successfully send message
|
||||
|
||||
@@ -17,15 +17,13 @@ public sealed class FaxUiState : BoundUserInterfaceState
|
||||
public bool IsPaperInserted { get; }
|
||||
public bool CanSend { get; }
|
||||
public bool CanCopy { get; }
|
||||
public bool CanSendCooldown; // DeltaV - AI fax
|
||||
|
||||
public FaxUiState(string deviceName,
|
||||
Dictionary<string, string> peers,
|
||||
bool canSend,
|
||||
bool canCopy,
|
||||
bool isPaperInserted,
|
||||
string? destAddress,
|
||||
bool canSendCooldown) // DeltaV - AI fax
|
||||
string? destAddress)
|
||||
{
|
||||
DeviceName = deviceName;
|
||||
AvailablePeers = peers;
|
||||
@@ -33,7 +31,6 @@ public sealed class FaxUiState : BoundUserInterfaceState
|
||||
CanSend = canSend;
|
||||
CanCopy = canCopy;
|
||||
DestinationAddress = destAddress;
|
||||
CanSendCooldown = canSendCooldown; // DeltaV - AI fax
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ using Content.Shared.Verbs;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Content.Shared.Wieldable;
|
||||
using Content.Shared.Zombies;
|
||||
using Content.Shared.Examine; //Harmony
|
||||
|
||||
|
||||
namespace Content.Shared.Inventory;
|
||||
@@ -65,7 +64,6 @@ public partial class InventorySystem
|
||||
SubscribeLocalEvent<InventoryComponent, BeforeEmoteEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, StoodEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, DownedEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, ExaminedEvent>(RelayInventoryEvent); // Harmony - added for lanyards.
|
||||
|
||||
// by-ref events
|
||||
SubscribeLocalEvent<InventoryComponent, RefreshFrictionModifiersEvent>(RefRelayInventoryEvent);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement; //Harmony Lanyards
|
||||
using Content.Shared.Inventory; //Harmony Lanyards
|
||||
using Content.Shared.Labels.Components;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Paper;
|
||||
@@ -10,7 +8,6 @@ using Content.Shared.Tag; // DeltaV
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Prototypes; // DeltaV
|
||||
using Robust.Shared.Utility;
|
||||
using System.Linq; //Harmony Lanyards
|
||||
|
||||
namespace Content.Shared.Labels.EntitySystems;
|
||||
|
||||
@@ -37,11 +34,6 @@ public sealed partial class LabelSystem : EntitySystem
|
||||
SubscribeLocalEvent<PaperLabelComponent, EntInsertedIntoContainerMessage>(OnContainerModified);
|
||||
SubscribeLocalEvent<PaperLabelComponent, EntRemovedFromContainerMessage>(OnContainerModified);
|
||||
SubscribeLocalEvent<PaperLabelComponent, ExaminedEvent>(OnExamined);
|
||||
// Harmony - OnExamined can now be inventory relayed from the neck slot for lanyard implementation,
|
||||
// getting the entity's pronouns and changing the label inspection text to reflect it being from a lanyard.
|
||||
// This would cause any other neck slot item with the label component to be described as a lanyard on inspection,
|
||||
// but currently no others exist.
|
||||
SubscribeLocalEvent<PaperLabelComponent, InventoryRelayedEvent<ExaminedEvent>>((e, c, ev) => OnExaminedInInventory(e, c, ev.Args));
|
||||
}
|
||||
|
||||
private void OnLabelCompMapInit(Entity<LabelComponent> ent, ref MapInitEvent args)
|
||||
@@ -131,65 +123,9 @@ public sealed partial class LabelSystem : EntitySystem
|
||||
args.PushMarkup(Loc.GetString("comp-paper-label-has-label"));
|
||||
var text = paper.Content;
|
||||
args.PushMarkup(text.TrimEnd());
|
||||
// Harmony addition begins - shows which stamps have been applied to a label when inspected. Copied from PaperSystem.
|
||||
if (paper.StampedBy.Count > 0)
|
||||
{
|
||||
var commaSeparated =
|
||||
string.Join(", ", paper.StampedBy.Select(s => Loc.GetString(s.StampedName)));
|
||||
args.PushMarkup(
|
||||
Loc.GetString(
|
||||
"comp-label-examine-detail-stamped-by",
|
||||
("stamps", commaSeparated))
|
||||
);
|
||||
}
|
||||
// Harmony addition ends
|
||||
}
|
||||
}
|
||||
|
||||
// Harmony addition begins - version of OnExamined for when the event is inventory relayed. Used when reading from a worn lanyard.
|
||||
private void OnExaminedInInventory(EntityUid uid, PaperLabelComponent comp, ExaminedEvent args)
|
||||
{
|
||||
if (comp.LabelSlot.Item is not { Valid: true } item)
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(PaperLabelComponent)))
|
||||
{
|
||||
// UID's parent is saved to be used for localisation grammar when the label is from a lanyard, since the text is changed.
|
||||
var user = Comp<TransformComponent>(uid).ParentUid;
|
||||
if (!args.IsInDetailsRange)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("comp-lanyard-has-lanyard-cant-read", ("user", Identity.Entity(user, EntityManager))));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp(item, out PaperComponent? paper))
|
||||
// Assuming yaml has the correct entity whitelist, this should not happen.
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(paper.Content))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("comp-lanyard-has-lanyard-blank", ("user", Identity.Entity(user, EntityManager))));
|
||||
return;
|
||||
}
|
||||
|
||||
args.PushMarkup(Loc.GetString("comp-lanyard-has-lanyard", ("user", Identity.Entity(user, EntityManager))));
|
||||
var text = paper.Content;
|
||||
args.PushMarkup(text.TrimEnd());
|
||||
// Harmony - shows which stamps have been applied to a lanyard's label when inspected. Copied from PaperSystem.
|
||||
if (paper.StampedBy.Count > 0)
|
||||
{
|
||||
var commaSeparated =
|
||||
string.Join(", ", paper.StampedBy.Select(s => Loc.GetString(s.StampedName)));
|
||||
args.PushMarkup(
|
||||
Loc.GetString(
|
||||
"comp-lanyard-examine-detail-stamped-by",
|
||||
("stamps", commaSeparated))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Harmony Addition Ends
|
||||
|
||||
// Not ref-sub due to being used for multiple subscriptions.
|
||||
private void OnContainerModified(EntityUid uid, PaperLabelComponent label, ContainerModifiedMessage args)
|
||||
{
|
||||
|
||||
@@ -68,11 +68,6 @@ public abstract class SharedSuitSensorSystem : EntitySystem
|
||||
/// <returns>True if the sensor is assigned to a station or assigning it was successful. False otherwise.</returns>
|
||||
public bool CheckSensorAssignedStation(Entity<SuitSensorComponent> sensor)
|
||||
{
|
||||
// Begin DeltaV - fallback
|
||||
if (sensor.Comp.StationId.HasValue && _stationSystem.GetOwningStation(sensor.Owner) is null)
|
||||
return true;
|
||||
// End DeltaV - fallback
|
||||
|
||||
if (!sensor.Comp.StationId.HasValue && Transform(sensor.Owner).GridUid == null)
|
||||
return false;
|
||||
|
||||
@@ -353,7 +348,7 @@ public abstract class SharedSuitSensorSystem : EntitySystem
|
||||
var transform = ent.Comp2;
|
||||
|
||||
// check if sensor is enabled and worn by user
|
||||
if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null || !HasComp<MobStateComponent>(sensor.User)) // DeltaV - don't block on grids here
|
||||
if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null || !HasComp<MobStateComponent>(sensor.User) || transform.GridUid == null)
|
||||
return null;
|
||||
|
||||
// try to get mobs id from ID slot
|
||||
|
||||
@@ -276,7 +276,7 @@ public sealed class PaperSystem : EntitySystem
|
||||
_appearance.SetData(entity, PaperVisuals.Status, status, appearance);
|
||||
}
|
||||
|
||||
public void UpdateUserInterface(Entity<PaperComponent> entity) // DeltaV - station AI
|
||||
private void UpdateUserInterface(Entity<PaperComponent> entity)
|
||||
{
|
||||
_uiSystem.SetUiState(entity.Owner, PaperUiKey.Key, new PaperBoundUserInterfaceState(entity.Comp.Content, entity.Comp.StampedBy, entity.Comp.Mode));
|
||||
}
|
||||
|
||||
@@ -120,23 +120,10 @@ public abstract partial class SharedBatterySystem : EntitySystem
|
||||
var rechargerQuery = EntityQueryEnumerator<BatterySelfRechargerComponent, BatteryComponent>();
|
||||
while (rechargerQuery.MoveNext(out var uid, out var recharger, out var battery))
|
||||
{
|
||||
|
||||
// BEGIN DeltaV - Battery Drain
|
||||
// Currently, NextAutoRecharge is only set when there's an explicit power draw from
|
||||
// the battery, and it doesn't count a negative charge rate as battery charge being used
|
||||
// so, this is to patch that in the case that the drain exceeds the recharge.
|
||||
if (recharger.AutoRechargePauseTime > TimeSpan.Zero && battery.ChargeRate < 0)
|
||||
{
|
||||
TrySetChargeCooldown((uid, recharger));
|
||||
continue;
|
||||
}
|
||||
// END DeltaV
|
||||
|
||||
if (recharger.NextAutoRecharge == null || curTime < recharger.NextAutoRecharge)
|
||||
continue;
|
||||
|
||||
recharger.NextAutoRecharge = null; // Don't refresh every tick.
|
||||
|
||||
Dirty(uid, recharger);
|
||||
RefreshChargeRate((uid, battery)); // Cooldown is over, apply the new recharge rate.
|
||||
}
|
||||
|
||||
@@ -32,10 +32,4 @@ public sealed partial class PowerCellDrawComponent : Component
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float UseCharge;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - If the battery's recharge should be paused while power draw is active.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool PauseRecharging;
|
||||
}
|
||||
|
||||
@@ -17,14 +17,8 @@ public sealed partial class PowerCellSystem
|
||||
ent.Comp.Enabled = enabled;
|
||||
Dirty(ent, ent.Comp);
|
||||
|
||||
// BEGIN DeltaV - Allow PowerDraw to prevent recharge
|
||||
if (TryGetBatteryFromSlot(ent.Owner, out var battery) && battery is { } existingBattery)
|
||||
{
|
||||
_battery.RefreshChargeRate(existingBattery.AsNullable());
|
||||
|
||||
if (ent.Comp.PauseRecharging) _battery.TrySetChargeCooldown(existingBattery.Owner);
|
||||
}
|
||||
// END DeltaV
|
||||
if (TryGetBatteryFromSlot(ent.Owner, out var battery))
|
||||
_battery.RefreshChargeRate(battery.Value.AsNullable());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed partial class RadioChannelPrototype : IPrototype
|
||||
public int Frequency { get; private set; } = 0;
|
||||
|
||||
[DataField("color")]
|
||||
public Color Color { get; set; } = Color.Lime; // DeltaV - Client-side radio channel colors, no longer private set
|
||||
public Color Color { get; private set; } = Color.Lime;
|
||||
|
||||
[IdDataField, ViewVariables]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared._DV.CCVars;
|
||||
|
||||
public sealed partial class DCCVars
|
||||
{
|
||||
public static readonly CVarDef<string> RadioColorCommon =
|
||||
CVarDef.Create("deltav.options.radio.common_color",
|
||||
"#2cdb2c",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Common radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorCommand =
|
||||
CVarDef.Create("deltav.options.radio.command_color",
|
||||
"#fcdf03",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Command radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorSecurity =
|
||||
CVarDef.Create("deltav.options.radio.security_color",
|
||||
"#8c93f5",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Security radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorMedical =
|
||||
CVarDef.Create("deltav.options.radio.medical_color",
|
||||
"#57b8f0",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Medical radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorEngineering =
|
||||
CVarDef.Create("deltav.options.radio.engineering_color",
|
||||
"#ff733c",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Engineering radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorScience =
|
||||
CVarDef.Create("deltav.options.radio.science_color",
|
||||
"#cd7ccd",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Science radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorCargo =
|
||||
CVarDef.Create("deltav.options.radio.cargo_color",
|
||||
"#b48b57",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Cargo radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorService =
|
||||
CVarDef.Create("deltav.options.radio.service_color",
|
||||
"#539c00",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Service radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorBinary =
|
||||
CVarDef.Create("deltav.options.radio.binary_color",
|
||||
"#5ed7aa",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Binary radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorJustice =
|
||||
CVarDef.Create("deltav.options.radio.justice_color",
|
||||
"#c70667",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Justice radio channel.");
|
||||
|
||||
public static readonly CVarDef<string> RadioColorPrison =
|
||||
CVarDef.Create("deltav.options.radio.prison_color",
|
||||
"#FFA500",
|
||||
CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"The color of the Prison radio channel.");
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace Content.Shared._DV.Fax;
|
||||
|
||||
[ByRefEvent]
|
||||
public readonly record struct FaxPrintedEvent(EntityUid Fax);
|
||||
@@ -137,12 +137,6 @@ public sealed partial class DeepFryerComponent : Component
|
||||
/// <seealso cref="ProfessionalChefComponent"/>
|
||||
[DataField]
|
||||
public float MissChance = 0.25f;
|
||||
|
||||
/// <summary>
|
||||
/// Check for whether the cooking timer needs to be reset after powering down
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool WasPreviouslyPowered = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.CartridgeLoader;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.DeviceNetwork.Events;
|
||||
using Content.Shared.DeviceNetwork.Systems;
|
||||
@@ -55,11 +54,5 @@ public sealed class PageSenderSystem : EntitySystem
|
||||
{ PagerConstants.DataBody, body },
|
||||
};
|
||||
_deviceNetwork.QueuePacket(ent, null, payload);
|
||||
|
||||
if (HasComp<PagerComponent>(ent))
|
||||
{
|
||||
var evt = new CartridgeLoaderNotificationSentEvent(Loc.GetString("pager-self-notification"), body);
|
||||
RaiseLocalEvent(ent, ref evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
using Content.Shared._DV.Fax;
|
||||
using Content.Shared.Fax;
|
||||
using Content.Shared.Paper;
|
||||
using Content.Shared.Silicons.StationAi;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Shared._DV.Silicons;
|
||||
|
||||
public abstract class SharedStationAiFaxSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly PaperSystem _paper = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StationAiFaxComponent, EntInsertedIntoContainerMessage>(OnInserted);
|
||||
SubscribeLocalEvent<StationAiFaxComponent, FaxPrintedEvent>(OnFaxPrinted);
|
||||
Subs.BuiEvents<StationAiFaxComponent>(FaxUiKey.Key,
|
||||
subs =>
|
||||
{
|
||||
subs.Event<StationAiFaxExamineMessage>(OnExamine);
|
||||
subs.Event<StationAiFaxShredMessage>(OnShred);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void OnInserted(Entity<StationAiFaxComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (HasComp<PaperComponent>(args.Entity))
|
||||
EnsureComp<StationAiWhitelistComponent>(args.Entity);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<StationAiFaxComponent> ent, ref StationAiFaxExamineMessage args)
|
||||
{
|
||||
if (GetDocument(ent, args.Document) is not { } document)
|
||||
return;
|
||||
|
||||
if (TryComp<PaperComponent>(document, out var paper))
|
||||
{
|
||||
paper.Mode = paper.EditingDisabled || paper.StampedBy.Count != 0
|
||||
? PaperComponent.PaperAction.Read
|
||||
: PaperComponent.PaperAction.Write;
|
||||
|
||||
_paper.UpdateUserInterface((document, paper));
|
||||
}
|
||||
|
||||
_userInterface.OpenUi(document, PaperComponent.PaperUiKey.Key, args.Actor);
|
||||
}
|
||||
|
||||
private void OnShred(Entity<StationAiFaxComponent> ent, ref StationAiFaxShredMessage args)
|
||||
{
|
||||
if (GetDocument(ent, args.Document) is { } document)
|
||||
{
|
||||
PredictedQueueDel(document);
|
||||
}
|
||||
}
|
||||
|
||||
protected EntityUid? GetDocument(Entity<StationAiFaxComponent> ent, NetEntity netEntity)
|
||||
{
|
||||
if (GetEntity(netEntity) is not { Valid: true } entity)
|
||||
return null;
|
||||
|
||||
if (!_container.TryGetContainingContainer(entity, out var container))
|
||||
return null;
|
||||
|
||||
if (container.Owner != ent.Owner)
|
||||
return null;
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void OnFaxPrinted(Entity<StationAiFaxComponent> ent, ref FaxPrintedEvent args)
|
||||
{
|
||||
var container = _container.EnsureContainer<Container>(ent, StationAiFaxComponent.Container);
|
||||
if (!_container.Insert(args.Fax, container, force: true))
|
||||
{
|
||||
PredictedQueueDel(args.Fax);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Content.Shared._DV.Fax;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.Silicons;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedStationAiFaxSystem))]
|
||||
public sealed partial class StationAiFaxComponent : Component
|
||||
{
|
||||
public const string Container = "PaperLibrary";
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public abstract partial class StationAiFaxFileMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly NetEntity Document;
|
||||
|
||||
public StationAiFaxFileMessage(NetEntity document)
|
||||
{
|
||||
Document = document;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class StationAiFaxSendMessage(NetEntity document) : StationAiFaxFileMessage(document);
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class StationAiFaxExamineMessage(NetEntity document) : StationAiFaxFileMessage(document);
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class StationAiFaxDuplicateMessage(NetEntity document) : StationAiFaxFileMessage(document);
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class StationAiFaxShredMessage(NetEntity document) : StationAiFaxFileMessage(document);
|
||||
@@ -65,10 +65,4 @@ public sealed class TraitConditionContext
|
||||
/// The <see cref="HumanoidCharacterProfile"/> of the player, if available.
|
||||
/// </summary>
|
||||
public HumanoidCharacterProfile? Profile { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of trait IDs currently selected by the player, if available.
|
||||
/// Used by <see cref="TraitDependencyCondition"/> to check conflicts and requirements.
|
||||
/// </summary>
|
||||
public IReadOnlySet<ProtoId<TraitPrototype>>? SelectedTraits { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._DV.Traits.Conditions;
|
||||
|
||||
/// <summary>
|
||||
/// Condition that checks trait conflicts and requirements.
|
||||
/// - Conflicts: if any listed trait is selected, this condition fails.
|
||||
/// - Requires: all listed traits must be selected for this condition to pass.
|
||||
/// Tooltips are generated per-entry by the UI rather than via GetTooltip,
|
||||
/// so GetTooltip returns empty to avoid duplication.
|
||||
/// </summary>
|
||||
public sealed partial class TraitDependencyCondition : BaseTraitCondition
|
||||
{
|
||||
/// <summary>
|
||||
/// Traits that are mutually exclusive with this one.
|
||||
/// If any of these are selected, this condition fails.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<TraitPrototype>> Conflicts = new();
|
||||
|
||||
/// <summary>
|
||||
/// Traits that must already be selected for this condition to pass.
|
||||
/// All listed traits must be present.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<TraitPrototype>> Requires = new();
|
||||
|
||||
protected override bool EvaluateImplementation(TraitConditionContext ctx)
|
||||
{
|
||||
if (ctx.SelectedTraits is { } selectedTraits)
|
||||
{
|
||||
foreach (var conflict in Conflicts)
|
||||
{
|
||||
if (selectedTraits.Contains(conflict))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Requires.Count > 0)
|
||||
{
|
||||
if (ctx.SelectedTraits is not { } selected)
|
||||
return false;
|
||||
|
||||
foreach (var required in Requires)
|
||||
{
|
||||
if (!selected.Contains(required))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns empty. the UI generates conflict/require tooltips directly via
|
||||
/// <see cref="GetTooltips"/> to avoid duplicating lines across the two tooltip paths.
|
||||
/// </summary>
|
||||
public override string GetTooltip(IPrototypeManager proto, ILocalizationManager loc) => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Returns individual tooltip lines for each conflict and requirement.
|
||||
/// Used by the UI to build both the requirements preview and the failed-conditions tooltip.
|
||||
/// </summary>
|
||||
public IEnumerable<string> GetTooltips(IPrototypeManager proto, ILocalizationManager loc)
|
||||
{
|
||||
foreach (var conflict in Conflicts)
|
||||
{
|
||||
if (!proto.TryIndex(conflict, out var traitProto))
|
||||
continue;
|
||||
yield return loc.GetString("trait-condition-trait-conflict", ("trait", loc.GetString(traitProto.Name)));
|
||||
}
|
||||
|
||||
foreach (var required in Requires)
|
||||
{
|
||||
if (!proto.TryIndex(required, out var traitProto))
|
||||
continue;
|
||||
yield return loc.GetString("trait-condition-trait-required", ("trait", loc.GetString(traitProto.Name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,4 +1,181 @@
|
||||
Entries:
|
||||
- author: snowywinters
|
||||
changes:
|
||||
- message: Station AI can now use traffic comms. Your secrets are no longer safe.
|
||||
type: Add
|
||||
- message: Station AI can now see silicon health, just like diagnostic HUDs.
|
||||
type: Add
|
||||
id: 1941
|
||||
time: '2025-12-09T17:56:16.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4905
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Syndicat ghost role description doesn't mention microbomb implant.
|
||||
type: Fix
|
||||
id: 1942
|
||||
time: '2025-12-09T18:31:07.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4889
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Added more festive headwear, an elf costume, and holiday red dress to
|
||||
the AutoDrobe!
|
||||
type: Add
|
||||
id: 1943
|
||||
time: '2025-12-10T08:05:33.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4909
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Entropic Degen should no longer last forever.
|
||||
type: Fix
|
||||
id: 1944
|
||||
time: '2025-12-10T08:12:42.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4931
|
||||
- author: SirWarock
|
||||
changes:
|
||||
- message: Fixed Rollerbeds getting annihilated by mouse traps!
|
||||
type: Fix
|
||||
id: 1945
|
||||
time: '2025-12-10T14:57:38.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4933
|
||||
- author: verybigman311
|
||||
changes:
|
||||
- message: Mowed Astro-Snow can now be crafted and utilized
|
||||
type: Add
|
||||
id: 1946
|
||||
time: '2025-12-10T14:59:27.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4921
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: New caw sounds for harpies!
|
||||
type: Add
|
||||
- message: Harpy emotes are now gender specific.
|
||||
type: Tweak
|
||||
id: 1947
|
||||
time: '2025-12-10T15:25:50.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4915
|
||||
- author: verybigman311
|
||||
changes:
|
||||
- message: Saws are now a little more lethal
|
||||
type: Tweak
|
||||
id: 1948
|
||||
time: '2025-12-10T21:59:39.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4886
|
||||
- author: Eternally-Confused
|
||||
changes:
|
||||
- message: The Crime Assist PDA app has been updated to match Space Law.
|
||||
type: Fix
|
||||
id: 1949
|
||||
time: '2025-12-11T14:58:57.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4937
|
||||
- author: SirWarock
|
||||
changes:
|
||||
- message: Truncheons can now be selected instead of a firearm in Security Loadouts!
|
||||
type: Tweak
|
||||
id: 1950
|
||||
time: '2025-12-11T22:05:22.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4838
|
||||
- author: AeraAuling
|
||||
changes:
|
||||
- message: Adds purifying salt to allow for healing of metaphysical damage
|
||||
type: Add
|
||||
id: 1951
|
||||
time: '2025-12-11T22:39:23.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4682
|
||||
- author: Halo3moth
|
||||
changes:
|
||||
- message: Lawyers now spawn with a forensic scanner.
|
||||
type: Add
|
||||
- message: Minor detective goodies added to the lawdrobe.
|
||||
type: Add
|
||||
id: 1952
|
||||
time: '2025-12-12T10:54:37.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4879
|
||||
- author: IRSMsoso
|
||||
changes:
|
||||
- message: Harpy flight no longer causes silent errors
|
||||
type: Fix
|
||||
id: 1953
|
||||
time: '2025-12-12T11:05:00.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4952
|
||||
- author: EmberAstra
|
||||
changes:
|
||||
- message: forensic pads used to scan gloves now also show the fiber's ID.
|
||||
type: Tweak
|
||||
id: 1954
|
||||
time: '2025-12-12T19:21:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4932
|
||||
- author: TheShuEd, Spielern
|
||||
changes:
|
||||
- message: The Christmas Anomaly is back in rotation!
|
||||
type: Add
|
||||
id: 1955
|
||||
time: '2025-12-12T22:23:47.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4957
|
||||
- author: AirlineFood001
|
||||
changes:
|
||||
- message: Adjusted the armor values on the Advanced Plate Carrier to make it all
|
||||
around stronger.
|
||||
type: Tweak
|
||||
id: 1956
|
||||
time: '2025-12-12T22:40:34.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4942
|
||||
- author: Velcroboy
|
||||
changes:
|
||||
- message: Reconfigurated the TEG tentacles
|
||||
type: Tweak
|
||||
id: 1957
|
||||
time: '2025-12-13T19:18:53.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4965
|
||||
- author: kotobdev
|
||||
changes:
|
||||
- message: The Redshirt trait has been added, which causes you to immediately die
|
||||
instead of going crit.
|
||||
type: Add
|
||||
id: 1958
|
||||
time: '2025-12-16T01:34:03.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4974
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Courier, Boxer, Gladiator, and Prisoner have the option to choose glasses
|
||||
in their loadout.
|
||||
type: Tweak
|
||||
- message: Surgeons get medical eyewear options in loadout.
|
||||
type: Tweak
|
||||
id: 1959
|
||||
time: '2025-12-16T05:04:42.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4977
|
||||
- author: Proxysseia
|
||||
changes:
|
||||
- message: replaced vestigial entity mentions with employee mentions. You can no
|
||||
longer harass vent spiders.
|
||||
type: Tweak
|
||||
id: 1960
|
||||
time: '2025-12-16T13:07:37.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4947
|
||||
- author: MantasDab360
|
||||
changes:
|
||||
- message: Revenant's crayon is now infinite once again.
|
||||
type: Fix
|
||||
id: 1961
|
||||
time: '2025-12-16T13:15:10.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4987
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Corpsman's inventory on spawn has been cleaned up. Most medical gear
|
||||
has been moved to the corpsman. locker.
|
||||
type: Tweak
|
||||
- message: Corpsman uniforms are now available in the SecDrobe.
|
||||
type: Tweak
|
||||
id: 1962
|
||||
time: '2025-12-16T13:24:57.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4979
|
||||
- author: marigauge
|
||||
changes:
|
||||
- message: IPCs now leave behind steel fibers when touching stuff.
|
||||
type: Tweak
|
||||
id: 1963
|
||||
time: '2025-12-16T13:41:33.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4968
|
||||
- author: marigauge
|
||||
changes:
|
||||
- message: Cybernetic eyes are no longer edible.
|
||||
@@ -4217,204 +4394,4 @@
|
||||
id: 2441
|
||||
time: '2026-06-20T17:14:12.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6049
|
||||
- author: Velcroboy
|
||||
changes:
|
||||
- message: 'The Hive: Epistemics now has a public thoroughfare through the center
|
||||
where a new chapel and robotics lab are located. Also security is blue.'
|
||||
type: Tweak
|
||||
id: 2442
|
||||
time: '2026-06-21T13:48:13.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6018
|
||||
- author: Halo3moth
|
||||
changes:
|
||||
- message: Pitbulls now spawn from vents less often
|
||||
type: Tweak
|
||||
id: 2443
|
||||
time: '2026-06-22T04:23:12.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6081
|
||||
- author: wesk
|
||||
changes:
|
||||
- message: Fixed **8 O'Clock Ghosts** from being stereo, instead of mono. This will
|
||||
no longer make the music play "loud" especially when the jukebox is behind a
|
||||
wall.
|
||||
type: Fix
|
||||
id: 2444
|
||||
time: '2026-06-22T08:46:38.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6084
|
||||
- author: wesk
|
||||
changes:
|
||||
- message: The Traits UI now shows a visual indicator when you have selected the
|
||||
max amount of traits in a category.
|
||||
type: Tweak
|
||||
- message: The Traits UI now indicates if you do not have enough points for a trait.
|
||||
type: Tweak
|
||||
- message: The Traits UI now indicates if a trait is conflicting with another trait,
|
||||
or is requiring another trait in order to be used/equipped by your character.
|
||||
type: Tweak
|
||||
id: 2445
|
||||
time: '2026-06-22T11:11:35.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6082
|
||||
- author: Proxysseia
|
||||
changes:
|
||||
- message: Shields are now not allowed to be carried on code Green (again)
|
||||
type: Tweak
|
||||
id: 2446
|
||||
time: '2026-06-22T11:36:51.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6070
|
||||
- author: rebe83
|
||||
changes:
|
||||
- message: Slugs are made out of lead and do 100 structural.
|
||||
type: Tweak
|
||||
id: 2447
|
||||
time: '2026-06-22T16:48:31.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6068
|
||||
- author: A111Vojta
|
||||
changes:
|
||||
- message: Ported lanyards from Harmony
|
||||
type: Add
|
||||
id: 2448
|
||||
time: '2026-06-22T18:05:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6035
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Nuke and Cosmic Cult finale music and SFX will always play, even if you're
|
||||
jetpacking around the station.
|
||||
type: Tweak
|
||||
- message: If a cultist converts a borg off-station, it will properly announce that
|
||||
it is happening.
|
||||
type: Fix
|
||||
id: 2449
|
||||
time: '2026-06-23T10:40:17.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5918
|
||||
- author: wesk
|
||||
changes:
|
||||
- message: Fixed required traits from not being detected by the Trait System, causing
|
||||
a false positive of traits not being met, even if you have them equipped already.
|
||||
type: Fix
|
||||
id: 2450
|
||||
time: '2026-06-23T12:49:52.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6097
|
||||
- author: rebe83
|
||||
changes:
|
||||
- message: Broken glass bottles can cut and slice things. Yay?
|
||||
type: Tweak
|
||||
id: 2451
|
||||
time: '2026-06-23T15:27:08.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6092
|
||||
- author: RoboBozu, SalDragonsNOA
|
||||
changes:
|
||||
- message: NanoTrasen corporate has decided to celebrate the increased productivity
|
||||
of the Delta Sector with ice cream! Recipes for various frozen treats have been
|
||||
added to Bartenders' handbooks to facilitate the celebration!
|
||||
type: Add
|
||||
id: 2452
|
||||
time: '2026-06-20T15:02:14.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5943
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Sleeper and NT sleeper agents no longer raise the alert level to blue
|
||||
and no longer display a 'communications intercepted' message.
|
||||
type: Tweak
|
||||
id: 2453
|
||||
time: '2026-06-23T22:34:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6066
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Station-specific jobs in the job preferences can now be found under their
|
||||
proper categories.
|
||||
type: Tweak
|
||||
- message: The station-specific jobs category will no longer appear on the crew
|
||||
monitor.
|
||||
type: Tweak
|
||||
- message: The corpsman job will now properly appear as a member of security on
|
||||
the crew monitor.
|
||||
type: Fix
|
||||
id: 2454
|
||||
time: '2026-06-23T22:34:44.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6078
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: AAC tablet buttons have colors again!
|
||||
type: Tweak
|
||||
id: 2455
|
||||
time: '2026-06-24T13:08:20.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5567
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Stealth borg modules are now working as intended and no longer provide
|
||||
infinite duration cloaking.
|
||||
type: Fix
|
||||
id: 2456
|
||||
time: '2026-06-24T13:15:02.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6085
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: You can now change common radio channel colors to the colors of your
|
||||
choice in the Radio tab in the Options menu!
|
||||
type: Add
|
||||
id: 2457
|
||||
time: '2026-06-24T22:02:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6101
|
||||
- author: ManuDemoen
|
||||
changes:
|
||||
- message: Fixed certain entities from not metabolizing alcohol
|
||||
type: Fix
|
||||
id: 2458
|
||||
time: '2026-06-25T02:28:27.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6104
|
||||
- author: Tmanzxd
|
||||
changes:
|
||||
- message: Removed the Surgeon time requirement for Chief Medical Officer, since
|
||||
surgery is once again a week away.
|
||||
type: Remove
|
||||
id: 2459
|
||||
time: '2026-06-25T13:10:38.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6112
|
||||
- author: rebe83
|
||||
changes:
|
||||
- message: Washing machines now can fit larger items inside, such as felinids, rodentia,
|
||||
or even a china lake. (China Lake not included)
|
||||
type: Tweak
|
||||
id: 2460
|
||||
time: '2026-06-25T14:07:13.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6086
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: The station AI can now send and receive faxes.
|
||||
type: Add
|
||||
id: 2461
|
||||
time: '2026-06-25T15:27:50.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6064
|
||||
- author: ManuDemoen
|
||||
changes:
|
||||
- message: The nachos recipe has changed! Cut them from taco shells and then add
|
||||
chili or cheese for variants.
|
||||
type: Tweak
|
||||
id: 2462
|
||||
time: '2026-06-25T15:37:34.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6099
|
||||
- author: wesk
|
||||
changes:
|
||||
- message: Synthetics can now use borg emotes!
|
||||
type: Add
|
||||
- message: Synthetics now has an option of being susceptible to Ion Storms.
|
||||
type: Add
|
||||
- message: Synthetics can now be purely mechanical! (cosmetical function only; you
|
||||
spark when damaged.)
|
||||
type: Add
|
||||
id: 2463
|
||||
time: '2026-06-25T16:17:27.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6090
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: Suit sensors now report their location, even while in space
|
||||
type: Add
|
||||
- message: Crew monitoring computers now have a radar UI when you're off-station
|
||||
type: Add
|
||||
- message: Due to suit sensors now working in space, salvage no longer needs deathrattles
|
||||
for recovery, hence, they have been removed.
|
||||
type: Remove
|
||||
id: 2464
|
||||
time: '2026-06-25T17:59:50.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6054
|
||||
Order: 1
|
||||
|
||||
@@ -62,11 +62,9 @@ cosmiccult-summary-crewminor = The Monument did not reach full power.
|
||||
cosmiccult-summary-crewmajor = All cosmic cultists were eliminated.
|
||||
cosmiccult-summary-crewcomplete = All cosmic cultists were deconverted!
|
||||
|
||||
cosmiccult-elimination-shuttle-call = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle has been automatically called to the station for decontamination and debriefing procedures. ETA: {$time} {$units}.
|
||||
cosmiccult-elimination-announcement = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle is already inbound. Return to Midpoint safely for decontamination and debriefing procedures.
|
||||
cosmiccult-elimination-shuttle-call = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle has been automatically called to the station for decontamination and debriefing procedures. ETA: {$time} {$units}. Please note, if the psychological impact of the anomaly is negligible, you may recall the shuttle to extend the shift.
|
||||
cosmiccult-elimination-announcement = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle is already inbound. Return to CentComm safely for decontamination and debriefing procedures.
|
||||
|
||||
cosmiccult-progress-fail-shuttle-call = Due to sustained Λ-CDM activity on you station, an emergency shuttle has been automatically called so that the station may be decontaminated as soon as possible. We thank you for your cooperation.
|
||||
cosmiccult-progress-fail-announcement = Due to sustained Λ-CDM activity on you station, an emergency shuttle is already inbound. Please ensure as much of the station is ready and accessible for the decontamination team. We thank you for your cooperation.
|
||||
|
||||
## BRIEFINGS
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
ui-options-tab-radio = Radio
|
||||
ui-options-tab-radio-description = Customize common in-game radio channel colors.
|
||||
|
||||
# Upstream Departments
|
||||
ui-options-radio-header-binary = Binary
|
||||
ui-options-radio-header-cargo = Logistics
|
||||
ui-options-radio-header-command = Command
|
||||
ui-options-radio-header-common = Common
|
||||
ui-options-radio-header-engineering = Engineering
|
||||
ui-options-radio-header-medical = Medical
|
||||
ui-options-radio-header-science = Epistemics
|
||||
ui-options-radio-header-security = Security
|
||||
ui-options-radio-header-service = Service
|
||||
|
||||
ui-options-radio-example-binary = [Binary] Freefall (AI-752) states, "Someone is breaking into my core."
|
||||
ui-options-radio-example-cargo = [Logistics] Seren says, "Salvage, are you alive?"
|
||||
ui-options-radio-example-command = [Command] Alexis asks, "Uh... Where is the nuke disk?"
|
||||
ui-options-radio-example-common = [Common] Maya says, "I love slacking off."
|
||||
ui-options-radio-example-engineering = [Engineering] Abigail asks, "Has anyone checked on the Tesla lately?"
|
||||
ui-options-radio-example-medical = [Medical] Aurora asks, "Did anyone set up cryo?"
|
||||
ui-options-radio-example-science = [Epistemics] Isaiah says, "That's the next thing we'll research."
|
||||
ui-options-radio-example-security = [Security] Simon says, "Littering? That's ten minutes in the brig."
|
||||
ui-options-radio-example-service = [Service] Preston says, "I gave medical almost 2000u of omnizine."
|
||||
|
||||
ui-options-radio-reset-binary = Reset Binary channel color
|
||||
ui-options-radio-reset-cargo = Reset Cargo channel color
|
||||
ui-options-radio-reset-command = Reset Command channel color
|
||||
ui-options-radio-reset-common = Reset Common channel color
|
||||
ui-options-radio-reset-engineering = Reset Engineering channel color
|
||||
ui-options-radio-reset-medical = Reset Medical channel color
|
||||
ui-options-radio-reset-science = Reset Science channel color
|
||||
ui-options-radio-reset-security = Reset Security channel color
|
||||
ui-options-radio-reset-service = Reset Service channel color
|
||||
|
||||
# DeltaV-Specific Departments
|
||||
ui-options-radio-header-justice = Justice
|
||||
ui-options-radio-header-prison = Prison
|
||||
|
||||
ui-options-radio-example-justice = [Justice] Mila exclaims, "My client did no such thing!"
|
||||
ui-options-radio-example-prison = [Prison] Pepper asks, "Is anyone getting that scarf for me?"
|
||||
|
||||
ui-options-radio-reset-justice = Reset Justice channel color
|
||||
ui-options-radio-reset-prison = Reset Prison channel color
|
||||
@@ -1,8 +0,0 @@
|
||||
fax-machine-ui-no-faxes =
|
||||
You have no documents.
|
||||
Add some, and they'll show up here.
|
||||
|
||||
fax-machine-ui-add-blank-file = Add blank document
|
||||
fax-machine-ui-upload-file = Upload document…
|
||||
fax-machine-ui-page-window = Send Document
|
||||
fax-machine-ui-sending = Sending:
|
||||
@@ -1,4 +1,3 @@
|
||||
department-Epistemics-description = Research artifacts and anomalies to invent new equipment for the station, while trying to keep glimmer tame.
|
||||
department-Logistics-description = Complete bounties, earn Spesos and deliver useful supplies to the crew.
|
||||
department-Justice-description = Uphold justice on the station.
|
||||
department-Incarcerated-description = Serving your sentence for past mistakes.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
department-Epistemics = Epistemics
|
||||
department-Logistics = Logistics
|
||||
department-Justice = Justice
|
||||
department-Incarcerated = Incarcerated
|
||||
|
||||
@@ -2,4 +2,3 @@ pager-error-different-networks = { THE($sender) } is on a different network from
|
||||
pager-connection-added = { THE($receiver) } will now receive pages from { THE($sender) }.
|
||||
pager-connection-removed = { THE($receiver) } will no longer receive pages from { THE($sender) }.
|
||||
pager-notification = Page from { $sender }
|
||||
pager-self-notification = Page received
|
||||
|
||||
@@ -81,22 +81,22 @@ phrase-number7 = 7
|
||||
phrase-number8 = 8
|
||||
phrase-number9 = 9
|
||||
phrase-number0 = 0
|
||||
phrase-ten = Ten
|
||||
phrase-hundred = Hundred
|
||||
phrase-thousand = Thousand
|
||||
phrase-million = Million
|
||||
phrase-billion = Billion
|
||||
phrase-stack = Stack
|
||||
phrase-hour = Hour
|
||||
phrase-minute = Minute
|
||||
phrase-second = Second
|
||||
phrase-ten = ten
|
||||
phrase-hundred = hundred
|
||||
phrase-thousand = thousand
|
||||
phrase-million = million
|
||||
phrase-billion = billion
|
||||
phrase-stack = stack
|
||||
phrase-hour = hour
|
||||
phrase-minute = minute
|
||||
phrase-second = second
|
||||
phrase-i-am = I am
|
||||
phrase-you-are = You are
|
||||
phrase-mine = Mine
|
||||
phrase-yours = Yours
|
||||
phrase-on = On
|
||||
phrase-off = Off
|
||||
phrase-day = Day
|
||||
phrase-day = day
|
||||
phrase-which = Which
|
||||
phrase-not = Not
|
||||
phrase-call = Call
|
||||
|
||||
@@ -7,17 +7,17 @@ phrase-location-shuttle = Shuttle
|
||||
phrase-location-maintenance = Maintenance
|
||||
|
||||
# relative
|
||||
phrase-location-near = Near
|
||||
phrase-location-far = Far
|
||||
phrase-location-inside = Inside
|
||||
phrase-location-outside = Outside
|
||||
phrase-location-near = near
|
||||
phrase-location-far = far
|
||||
phrase-location-inside = inside
|
||||
phrase-location-outside = outside
|
||||
|
||||
## compass
|
||||
phrase-location-north = North
|
||||
phrase-location-east = East
|
||||
phrase-location-south = South
|
||||
phrase-location-west = West
|
||||
phrase-location-northeast = Northeast
|
||||
phrase-location-southeast = Southeast
|
||||
phrase-location-southwest = Southwest
|
||||
phrase-location-northwest = Northwest
|
||||
phrase-location-north = north
|
||||
phrase-location-east = east
|
||||
phrase-location-south = south
|
||||
phrase-location-west = west
|
||||
phrase-location-northeast = northeast
|
||||
phrase-location-southeast = southeast
|
||||
phrase-location-southwest = southwest
|
||||
phrase-location-northwest = northwest
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
phrase-species-dog = Dog
|
||||
phrase-species-cat = Cat
|
||||
phrase-species-opossum = Opossum
|
||||
phrase-species-lizard = Lizard
|
||||
phrase-species-bat = Sloth
|
||||
phrase-species-slime = Slime
|
||||
phrase-species-mouse = Mouse
|
||||
phrase-species-mothroach = Mothroach
|
||||
phrase-species-cockroach = Cockroach
|
||||
phrase-species-spider = Spider
|
||||
phrase-species-bird = Bird
|
||||
phrase-species-parrot = Parrot
|
||||
phrase-species-snake = Snake
|
||||
phrase-species-pig = Pig
|
||||
phrase-species-monkey = Monkey
|
||||
phrase-species-kobold = Kobold
|
||||
phrase-species-ferret = Ferret
|
||||
phrase-species-carp = Carp
|
||||
phrase-species-xeno = Xeno
|
||||
phrase-species-hamster = Hamster
|
||||
phrase-species-ifrit = Ifrit
|
||||
phrase-species-raccoon = Raccoon
|
||||
phrase-species-rouny = Rouny
|
||||
phrase-species-fox = Fox
|
||||
phrase-species-crab = Crab
|
||||
phrase-species-kangaroo = Kangaroo
|
||||
phrase-species-cow = Cow
|
||||
phrase-species-duck = Duck
|
||||
phrase-species-bear = Bear
|
||||
phrase-species-penguin = Penguin
|
||||
phrase-species-goat = Goat
|
||||
phrase-species-person = Person
|
||||
phrase-species-animal = Animal
|
||||
phrase-species-corpse = Corpse
|
||||
phrase-species-robot = Robot
|
||||
phrase-species-alien = Alien
|
||||
phrase-species-monster = Monster
|
||||
phrase-species-ghost = Ghost
|
||||
phrase-species-pest = Pest
|
||||
phrase-species-insect = Insect
|
||||
phrase-species-pet = Pet
|
||||
phrase-species-chicken = Chicken
|
||||
phrase-species-fish = Fish
|
||||
phrase-species-dog = dog
|
||||
phrase-species-cat = cat
|
||||
phrase-species-opossum = opossum
|
||||
phrase-species-lizard = lizard
|
||||
phrase-species-bat = sloth
|
||||
phrase-species-slime = slime
|
||||
phrase-species-mouse = mouse
|
||||
phrase-species-mothroach = mothroach
|
||||
phrase-species-cockroach = cockroach
|
||||
phrase-species-spider = spider
|
||||
phrase-species-bird = bird
|
||||
phrase-species-parrot = parrot
|
||||
phrase-species-snake = snake
|
||||
phrase-species-pig = pig
|
||||
phrase-species-monkey = monkey
|
||||
phrase-species-kobold = kobold
|
||||
phrase-species-ferret = ferret
|
||||
phrase-species-carp = carp
|
||||
phrase-species-xeno = xeno
|
||||
phrase-species-hamster = hamster
|
||||
phrase-species-ifrit = ifrit
|
||||
phrase-species-raccoon = raccoon
|
||||
phrase-species-rouny = rouny
|
||||
phrase-species-fox = fox
|
||||
phrase-species-crab = crab
|
||||
phrase-species-kangaroo = kangaroo
|
||||
phrase-species-cow = cow
|
||||
phrase-species-duck = duck
|
||||
phrase-species-bear = bear
|
||||
phrase-species-penguin = penguin
|
||||
phrase-species-goat = goat
|
||||
phrase-species-person = person
|
||||
phrase-species-animal = animal
|
||||
phrase-species-corpse = corpse
|
||||
phrase-species-robot = robot
|
||||
phrase-species-alien = alien
|
||||
phrase-species-monster = monster
|
||||
phrase-species-ghost = ghost
|
||||
phrase-species-pest = pest
|
||||
phrase-species-insect = insect
|
||||
phrase-species-pet = pet
|
||||
phrase-species-chicken = chicken
|
||||
phrase-species-fish = fish
|
||||
|
||||
@@ -1,249 +1,249 @@
|
||||
phrase-pen = Pen
|
||||
phrase-paper = Paper
|
||||
phrase-wrench = Wrench
|
||||
phrase-crowbar = Crowbar
|
||||
phrase-screwdriver = Screwdriver
|
||||
phrase-wirecutter = Wirecutter
|
||||
phrase-welding-tool = Welding tool
|
||||
phrase-welding-mask = Welding mask
|
||||
phrase-toolbox = Toolbox
|
||||
phrase-beaker = Beaker
|
||||
phrase-radio = Radio
|
||||
phrase-uniform = Uniform
|
||||
phrase-suit-sensors = Suit sensors
|
||||
phrase-internals = Internals
|
||||
phrase-gas-tank = Gas tank
|
||||
phrase-multitool = Multitool
|
||||
phrase-lathe = Lathe
|
||||
phrase-computer = Computer
|
||||
phrase-door = Door
|
||||
phrase-firelock = Firelock
|
||||
phrase-space = Space
|
||||
phrase-tool = Tool
|
||||
phrase-weapon = Weapon
|
||||
phrase-armor = Armor
|
||||
phrase-brain = Brain
|
||||
phrase-drink = Drink
|
||||
phrase-food = Food
|
||||
phrase-water = Water
|
||||
phrase-signature = Signature
|
||||
phrase-belt = Belt
|
||||
phrase-hardsuit = Hardsuit
|
||||
phrase-light = Light
|
||||
phrase-bag = Bag
|
||||
phrase-steel = Steel
|
||||
phrase-plastic = Plastic
|
||||
phrase-plasteel = Plasteel
|
||||
phrase-plasma = Plasma
|
||||
phrase-uranium = Uranium
|
||||
phrase-bananium = Bananium
|
||||
phrase-wood = Wood
|
||||
phrase-cloth = Cloth
|
||||
phrase-cardboard = Cardboard
|
||||
phrase-gold = Gold
|
||||
phrase-glass = Glass
|
||||
phrase-silver = Silver
|
||||
phrase-bluespace = Bluespace
|
||||
phrase-access = Access
|
||||
phrase-encryption-key = Encryption key
|
||||
phrase-pen = pen
|
||||
phrase-paper = paper
|
||||
phrase-wrench = wrench
|
||||
phrase-crowbar = crowbar
|
||||
phrase-screwdriver = screwdriver
|
||||
phrase-wirecutter = wirecutter
|
||||
phrase-welding-tool = welding tool
|
||||
phrase-welding-mask = welding mask
|
||||
phrase-toolbox = toolbox
|
||||
phrase-beaker = beaker
|
||||
phrase-radio = radio
|
||||
phrase-uniform = uniform
|
||||
phrase-suit-sensors = suit sensors
|
||||
phrase-internals = internals
|
||||
phrase-gas-tank = gas tank
|
||||
phrase-multitool = multitool
|
||||
phrase-lathe = lathe
|
||||
phrase-computer = computer
|
||||
phrase-door = door
|
||||
phrase-firelock = firelock
|
||||
phrase-space = space
|
||||
phrase-tool = tool
|
||||
phrase-weapon = weapon
|
||||
phrase-armor = armor
|
||||
phrase-brain = brain
|
||||
phrase-drink = drink
|
||||
phrase-food = food
|
||||
phrase-water = water
|
||||
phrase-signature = signature
|
||||
phrase-belt = belt
|
||||
phrase-hardsuit = hardsuit
|
||||
phrase-light = light
|
||||
phrase-bag = bag
|
||||
phrase-steel = steel
|
||||
phrase-plastic = plastic
|
||||
phrase-plasteel = plasteel
|
||||
phrase-plasma = plasma
|
||||
phrase-uranium = uranium
|
||||
phrase-bananium = bananium
|
||||
phrase-wood = wood
|
||||
phrase-cloth = cloth
|
||||
phrase-cardboard = cardboard
|
||||
phrase-gold = gold
|
||||
phrase-glass = glass
|
||||
phrase-silver = silver
|
||||
phrase-bluespace = bluespace
|
||||
phrase-access = access
|
||||
phrase-encryption-key = encryption key
|
||||
phrase-id-card = ID card
|
||||
phrase-pda = Pda
|
||||
phrase-stamp = Stamp
|
||||
phrase-implant = Implant
|
||||
phrase-pda = pda
|
||||
phrase-stamp = stamp
|
||||
phrase-implant = implant
|
||||
phrase-ame = AME
|
||||
phrase-apc = APC
|
||||
phrase-canister = Canister
|
||||
phrase-compressed-matter = Compressed matter
|
||||
phrase-frezon = Frezon
|
||||
phrase-gravity = Gravity
|
||||
phrase-canister = canister
|
||||
phrase-compressed-matter = compressed matter
|
||||
phrase-frezon = frezon
|
||||
phrase-gravity = gravity
|
||||
phrase-hvwire = HV cable
|
||||
phrase-lvwire = LV cable
|
||||
phrase-mvwire = MV cable
|
||||
phrase-network-configurator = Network configurator
|
||||
phrase-nitrogen = Nitrogen
|
||||
phrase-oxygen = Oxygen
|
||||
phrase-network-configurator = network configurator
|
||||
phrase-nitrogen = nitrogen
|
||||
phrase-oxygen = oxygen
|
||||
phrase-rcd = RCD
|
||||
phrase-rtg = RTG
|
||||
phrase-scrubber = Scrubber
|
||||
phrase-singulo = Singularity
|
||||
phrase-scrubber = scrubber
|
||||
phrase-singulo = singularity
|
||||
phrase-smes = SMES
|
||||
phrase-substation = Substation
|
||||
phrase-tray-scanner = T-ray scanner
|
||||
phrase-substation = substation
|
||||
phrase-tray-scanner = t-ray scanner
|
||||
phrase-teg = TEG
|
||||
phrase-tesla = Tesla
|
||||
phrase-tritium = Tritium
|
||||
phrase-magboots = Magboots
|
||||
phrase-holofan = Holofan
|
||||
phrase-anomaly = Anomaly
|
||||
phrase-tesla = tesla
|
||||
phrase-tritium = tritium
|
||||
phrase-magboots = magboots
|
||||
phrase-holofan = holofan
|
||||
phrase-anomaly = anomaly
|
||||
phrase-ape = A.P.E.
|
||||
phrase-anomaly-vessel = Anomaly vessel
|
||||
phrase-artifact = Artifact
|
||||
phrase-artifact-container = Artifact container
|
||||
phrase-robotics = Robotics
|
||||
phrase-circuit-board = Circuit board
|
||||
phrase-research = Research
|
||||
phrase-anomaly-vessel = anomaly vessel
|
||||
phrase-artifact = artifact
|
||||
phrase-artifact-container = artifact container
|
||||
phrase-robotics = robotics
|
||||
phrase-circuit-board = circuit board
|
||||
phrase-research = research
|
||||
phrase-research-console = R&D computer
|
||||
phrase-oracle = Oracle
|
||||
phrase-sophie = Sophie
|
||||
phrase-glimmer = Glimmer
|
||||
phrase-psionic = Psionic
|
||||
phrase-lotophagol-oil = Lotophagol oil
|
||||
phrase-mindbreak-phase = Mindbreak
|
||||
phrase-protolathe = Protolathe
|
||||
phrase-circuit-imprinter = Circuit imprinter
|
||||
phrase-bounty = Bounty
|
||||
phrase-cargo-shuttle = Cargo shuttle
|
||||
phrase-crate = Crate
|
||||
phrase-mail = Mail
|
||||
phrase-order = Order
|
||||
phrase-ore-processor = Ore processor
|
||||
phrase-request = Request
|
||||
phrase-spesos = Spesos
|
||||
phrase-restock = Restock
|
||||
phrase-fulton = Fulton
|
||||
phrase-jetpack = Jetpack
|
||||
phrase-crusher = Crusher
|
||||
phrase-pka = Proto-kinetic accelerator
|
||||
phrase-pickaxe = Pickaxe
|
||||
phrase-drill = Drill
|
||||
phrase-ore-bag = Ore bag
|
||||
phrase-salv-magnet = Salvage magnet
|
||||
phrase-expedition = Expedition
|
||||
phrase-topical = Topical
|
||||
phrase-topical-brute-pack = Brute pack
|
||||
phrase-topical-gauze = Gauze
|
||||
phrase-topical-bloodpack = Bloodpack
|
||||
phrase-defibrillator = Defibrillator
|
||||
phrase-cryopod = Cryopod
|
||||
phrase-stasis-bed = Stasis bed
|
||||
phrase-first-aid-kit = First-aid kit
|
||||
phrase-clone = Clone
|
||||
phrase-cloning-pod = Cloning pod
|
||||
phrase-biomass = Biomass
|
||||
phrase-syringe = Syringe
|
||||
phrase-pill = Pill
|
||||
phrase-alive = Alive
|
||||
phrase-crit = Critical
|
||||
phrase-dead = Dead
|
||||
phrase-healthy = Healthy
|
||||
phrase-handcuffs = Handcuffs
|
||||
phrase-stun-baton = Stun baton
|
||||
phrase-disabler = Disabler
|
||||
phrase-flash = Flash
|
||||
phrase-flashbang = Flashbang
|
||||
phrase-arrest = Arrest
|
||||
phrase-warrant = Warrant
|
||||
phrase-wanted = Wanted
|
||||
phrase-search = Search
|
||||
phrase-detain = Detain
|
||||
phrase-suspect = Suspect
|
||||
phrase-forensic-scanner = Forensic scanner
|
||||
phrase-forensic-pad = Forensic pad
|
||||
phrase-glimmer = glimmer
|
||||
phrase-psionic = psionic
|
||||
phrase-lotophagol-oil = lotophagol oil
|
||||
phrase-mindbreak-phase = mindbreak
|
||||
phrase-protolathe = protolathe
|
||||
phrase-circuit-imprinter = circuit imprinter
|
||||
phrase-bounty = bounty
|
||||
phrase-cargo-shuttle = cargo shuttle
|
||||
phrase-crate = crate
|
||||
phrase-mail = mail
|
||||
phrase-order = order
|
||||
phrase-ore-processor = ore processor
|
||||
phrase-request = request
|
||||
phrase-spesos = spesos
|
||||
phrase-restock = restock
|
||||
phrase-fulton = fulton
|
||||
phrase-jetpack = jetpack
|
||||
phrase-crusher = crusher
|
||||
phrase-pka = proto-kinetic accelerator
|
||||
phrase-pickaxe = pickaxe
|
||||
phrase-drill = drill
|
||||
phrase-ore-bag = ore bag
|
||||
phrase-salv-magnet = salvage magnet
|
||||
phrase-expedition = expedition
|
||||
phrase-topical = topical
|
||||
phrase-topical-brute-pack = brute pack
|
||||
phrase-topical-gauze = gauze
|
||||
phrase-topical-bloodpack = bloodpack
|
||||
phrase-defibrillator = defibrillator
|
||||
phrase-cryopod = cryopod
|
||||
phrase-stasis-bed = stasis bed
|
||||
phrase-first-aid-kit = first-aid kit
|
||||
phrase-clone = clone
|
||||
phrase-cloning-pod = cloning pod
|
||||
phrase-biomass = biomass
|
||||
phrase-syringe = syringe
|
||||
phrase-pill = pill
|
||||
phrase-alive = alive
|
||||
phrase-crit = critical
|
||||
phrase-dead = dead
|
||||
phrase-healthy = healthy
|
||||
phrase-handcuffs = handcuffs
|
||||
phrase-stun-baton = stun baton
|
||||
phrase-disabler = disabler
|
||||
phrase-flash = flash
|
||||
phrase-flashbang = flashbang
|
||||
phrase-arrest = arrest
|
||||
phrase-warrant = warrant
|
||||
phrase-wanted = wanted
|
||||
phrase-search = search
|
||||
phrase-detain = detain
|
||||
phrase-suspect = suspect
|
||||
phrase-forensic-scanner = forensic scanner
|
||||
phrase-forensic-pad = forensic pad
|
||||
phrase-log-probe = LogProbe
|
||||
phrase-meat = Meat
|
||||
phrase-flour = Flour
|
||||
phrase-rice = Rice
|
||||
phrase-dough = Dough
|
||||
phrase-bread = Bread
|
||||
phrase-milk = Milk
|
||||
phrase-egg = Egg
|
||||
phrase-wheat = Wheat
|
||||
phrase-vegetable = Vegetable
|
||||
phrase-fruit = Fruit
|
||||
phrase-sugar = Sugar
|
||||
phrase-alcohol = Alcohol
|
||||
phrase-non-alcoholic = Non-alcoholic
|
||||
phrase-juice = Juice
|
||||
phrase-mop = Mop
|
||||
phrase-bucket = Bucket
|
||||
phrase-space-cleaner = Space cleaner
|
||||
phrase-soap = Soap
|
||||
phrase-trash = Trash
|
||||
phrase-stage = Stage
|
||||
phrase-seed = Seed
|
||||
phrase-plant = Plant
|
||||
phrase-mutagen = Mutagen
|
||||
phrase-robust = Robust harvest
|
||||
phrase-weed = Weed
|
||||
phrase-knife = Knife
|
||||
phrase-witness = Witness
|
||||
phrase-evidence = Evidence
|
||||
phrase-case = Case
|
||||
phrase-sue = Sue
|
||||
phrase-courtroom-timer = Courtroom timer
|
||||
phrase-bailiff = Bailiff
|
||||
phrase-sentence = Sentence
|
||||
phrase-defendant = Defendant
|
||||
phrase-plaintiff = Plaintiff
|
||||
phrase-victim = Victim
|
||||
phrase-defense = Defense
|
||||
phrase-prosecution = Prosecution
|
||||
phrase-statement = Statement
|
||||
phrase-gavel = Gavel
|
||||
phrase-charge = Charge
|
||||
phrase-guilty = Guilty
|
||||
phrase-not-guilty = Not guilty
|
||||
phrase-meat = meat
|
||||
phrase-flour = flour
|
||||
phrase-rice = rice
|
||||
phrase-dough = dough
|
||||
phrase-bread = bread
|
||||
phrase-milk = milk
|
||||
phrase-egg = egg
|
||||
phrase-wheat = wheat
|
||||
phrase-vegetable = vegetable
|
||||
phrase-fruit = fruit
|
||||
phrase-sugar = sugar
|
||||
phrase-alcohol = alcohol
|
||||
phrase-non-alcoholic = non-alcoholic
|
||||
phrase-juice = juice
|
||||
phrase-mop = mop
|
||||
phrase-bucket = bucket
|
||||
phrase-space-cleaner = space cleaner
|
||||
phrase-soap = soap
|
||||
phrase-trash = trash
|
||||
phrase-stage = stage
|
||||
phrase-seed = seed
|
||||
phrase-plant = plant
|
||||
phrase-mutagen = mutagen
|
||||
phrase-robust = robust harvest
|
||||
phrase-weed = weed
|
||||
phrase-knife = knife
|
||||
phrase-witness = witness
|
||||
phrase-evidence = evidence
|
||||
phrase-case = case
|
||||
phrase-sue = sue
|
||||
phrase-courtroom-timer = courtroom timer
|
||||
phrase-bailiff = bailiff
|
||||
phrase-sentence = sentence
|
||||
phrase-defendant = defendant
|
||||
phrase-plaintiff = plaintiff
|
||||
phrase-victim = victim
|
||||
phrase-defense = defense
|
||||
phrase-prosecution = prosecution
|
||||
phrase-statement = statement
|
||||
phrase-gavel = gavel
|
||||
phrase-charge = charge
|
||||
phrase-guilty = guilty
|
||||
phrase-not-guilty = not guilty
|
||||
phrase-objection = Objection
|
||||
phrase-request-time = I need more time
|
||||
phrase-your-honor = Your Honor
|
||||
phrase-microwave = Microwave
|
||||
phrase-grill = Grill
|
||||
phrase-iron = Iron
|
||||
phrase-coal = Coal
|
||||
phrase-quartz = Quartz
|
||||
phrase-salt = Salt
|
||||
phrase-artifact-fragment = Artifact fragment
|
||||
phrase-bluespace-crystal = Bluespace
|
||||
phrase-diamond = Diamond
|
||||
phrase-chemicals = Chemicals
|
||||
phrase-box = Box
|
||||
phrase-locker = Locker
|
||||
phrase-machine = Machine
|
||||
phrase-blood = Blood
|
||||
phrase-nukedisk = Nuclear disk
|
||||
phrase-pinpointer = Pinpointer
|
||||
phrase-law = Law
|
||||
phrase-chassis = Chassis
|
||||
phrase-engi-on = On
|
||||
phrase-engi-off = Off
|
||||
phrase-gas-analyzer = Gas analyzer
|
||||
phrase-planetside = Planetside
|
||||
phrase-holopad = Holopad
|
||||
phrase-upgrade = Upgrade
|
||||
phrase-gloves = Gloves
|
||||
phrase-shoes = Shoes
|
||||
phrase-limbs = Limbs
|
||||
phrase-release = Release
|
||||
phrase-parole = Parole
|
||||
phrase-microwave = microwave
|
||||
phrase-grill = grill
|
||||
phrase-iron = iron
|
||||
phrase-coal = coal
|
||||
phrase-quartz = quartz
|
||||
phrase-salt = salt
|
||||
phrase-artifact-fragment = artifact fragment
|
||||
phrase-bluespace-crystal = bluespace
|
||||
phrase-diamond = diamond
|
||||
phrase-chemicals = chemicals
|
||||
phrase-box = box
|
||||
phrase-locker = locker
|
||||
phrase-machine = machine
|
||||
phrase-blood = blood
|
||||
phrase-nukedisk = nuclear disk
|
||||
phrase-pinpointer = pinpointer
|
||||
phrase-law = law
|
||||
phrase-chassis = chassis
|
||||
phrase-engi-on = on
|
||||
phrase-engi-off = off
|
||||
phrase-gas-analyzer = gas analyzer
|
||||
phrase-planetside = planetside
|
||||
phrase-holopad = holopad
|
||||
phrase-upgrade = upgrade
|
||||
phrase-gloves = gloves
|
||||
phrase-shoes = shoes
|
||||
phrase-limbs = limbs
|
||||
phrase-release = release
|
||||
phrase-parole = parole
|
||||
|
||||
# colors
|
||||
phrase-color-red = Red
|
||||
phrase-color-orange = Orange
|
||||
phrase-color-yellow = Yellow
|
||||
phrase-color-green = Green
|
||||
phrase-color-blue = Blue
|
||||
phrase-color-purple = Purple
|
||||
phrase-color-pink = Pink
|
||||
phrase-color-black = Black
|
||||
phrase-color-white = White
|
||||
phrase-color-bright = Bright
|
||||
phrase-color-light = Light
|
||||
phrase-color-dark = Dark
|
||||
phrase-color-rainbow = Rainbow
|
||||
phrase-color-brown = Brown
|
||||
phrase-color-gray = Gray
|
||||
phrase-color-red = red
|
||||
phrase-color-orange = orange
|
||||
phrase-color-yellow = yellow
|
||||
phrase-color-green = green
|
||||
phrase-color-blue = blue
|
||||
phrase-color-purple = purple
|
||||
phrase-color-pink = pink
|
||||
phrase-color-black = black
|
||||
phrase-color-white = white
|
||||
phrase-color-bright = bright
|
||||
phrase-color-light = light
|
||||
phrase-color-dark = dark
|
||||
phrase-color-rainbow = rainbow
|
||||
phrase-color-brown = brown
|
||||
phrase-color-gray = gray
|
||||
|
||||
# flavors
|
||||
phrase-sweet = Sweet
|
||||
phrase-sour = Sour
|
||||
phrase-spicy = Spicy
|
||||
phrase-savory = Savory
|
||||
phrase-bitter = Bitter
|
||||
phrase-sweet = sweet
|
||||
phrase-sour = sour
|
||||
phrase-spicy = spicy
|
||||
phrase-savory = savory
|
||||
phrase-bitter = bitter
|
||||
|
||||
# plants
|
||||
phrase-tomato = Tomato
|
||||
phrase-potato = Potato
|
||||
phrase-onion = Onion
|
||||
phrase-aloe = Aloe
|
||||
phrase-poppy = Poppy
|
||||
phrase-galaxythistle = Galaxythistle
|
||||
phrase-tomato = tomato
|
||||
phrase-potato = potato
|
||||
phrase-onion = onion
|
||||
phrase-aloe = aloe
|
||||
phrase-poppy = poppy
|
||||
phrase-galaxythistle = galaxythistle
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
phrase-hazard-space = Spaced
|
||||
phrase-hazard-low-presure = Low pressure
|
||||
phrase-hazard-high-presure = High pressure
|
||||
phrase-hazard-heat = Overheating
|
||||
phrase-hazard-cold = Cold
|
||||
phrase-hazard-gas-leak = Gas leak
|
||||
phrase-hazard-explosion = Explosion
|
||||
phrase-hazard-radiation = Radiation
|
||||
phrase-hazard-structure-damage = Structural damage
|
||||
phrase-hazard-chemical-spill = Chemical spill
|
||||
phrase-hazard-shock = Shock hazard
|
||||
phrase-hazard = Hazard
|
||||
phrase-hazard-meteors = Meteor
|
||||
phrase-hazard-poison = Poison
|
||||
phrase-hazard-fire = Fire
|
||||
phrase-hazard-power-outage = Power outage
|
||||
phrase-hazard-low = Low power
|
||||
phrase-hazard-infection = Infection
|
||||
phrase-hazard-viral-threat = Viral threat
|
||||
phrase-hazard-broken-equipment = Broken equipment
|
||||
phrase-hostile-enemy = Enemy
|
||||
phrase-hostile = Hostile
|
||||
phrase-hostile-attacker = Attacker
|
||||
phrase-hostile-lifeform = Dangerous lifeform
|
||||
phrase-hostile-entity = Entity
|
||||
phrase-hostile-bomb = Bomb
|
||||
phrase-hostile-criminal = Criminal
|
||||
phrase-hostile-intruder = Intruder
|
||||
phrase-hostile-infiltrator = Infiltrator
|
||||
phrase-hostile-fugitive = Fugitive
|
||||
phrase-hostile-weapon = Weapon
|
||||
phrase-hostile-gun = Gun
|
||||
phrase-safety-safe = Safe
|
||||
phrase-safety-in-danger = In danger
|
||||
phrase-safety-injured = Injured
|
||||
phrase-safety-dying = Dying
|
||||
phrase-safety-critical = Critical
|
||||
phrase-safety-bleeding = Bleeding
|
||||
phrase-safety-dead = Dead
|
||||
phrase-safety-alive = Alive
|
||||
phrase-safety-trustworthy = Trustworthy
|
||||
phrase-safety-escape = Escape
|
||||
phrase-safety-leaving = Leaving
|
||||
phrase-safety-need = Need
|
||||
phrase-safety-rescue = Rescue
|
||||
phrase-safety-dangerous = Dangerous
|
||||
phrase-safety-hazardous = Hazardous
|
||||
phrase-hazard-space = spaced
|
||||
phrase-hazard-low-presure = low pressure
|
||||
phrase-hazard-high-presure = high pressure
|
||||
phrase-hazard-heat = overheating
|
||||
phrase-hazard-cold = cold
|
||||
phrase-hazard-gas-leak = gas leak
|
||||
phrase-hazard-explosion = explosion
|
||||
phrase-hazard-radiation = radiation
|
||||
phrase-hazard-structure-damage = structural damage
|
||||
phrase-hazard-chemical-spill = chemical spill
|
||||
phrase-hazard-shock = shock hazard
|
||||
phrase-hazard = hazard
|
||||
phrase-hazard-meteors = meteor
|
||||
phrase-hazard-poison = poison
|
||||
phrase-hazard-fire = fire
|
||||
phrase-hazard-power-outage = power outage
|
||||
phrase-hazard-low = low power
|
||||
phrase-hazard-infection = infection
|
||||
phrase-hazard-viral-threat = viral threat
|
||||
phrase-hazard-broken-equipment = broken equipment
|
||||
phrase-hostile-enemy = enemy
|
||||
phrase-hostile = hostile
|
||||
phrase-hostile-attacker = attacker
|
||||
phrase-hostile-lifeform = dangerous lifeform
|
||||
phrase-hostile-entity = entity
|
||||
phrase-hostile-bomb = bomb
|
||||
phrase-hostile-criminal = criminal
|
||||
phrase-hostile-intruder = intruder
|
||||
phrase-hostile-infiltrator = infiltrator
|
||||
phrase-hostile-fugitive = fugitive
|
||||
phrase-hostile-weapon = weapon
|
||||
phrase-hostile-gun = gun
|
||||
phrase-safety-safe = safe
|
||||
phrase-safety-in-danger = in danger
|
||||
phrase-safety-injured = injured
|
||||
phrase-safety-dying = dying
|
||||
phrase-safety-critical = critical
|
||||
phrase-safety-bleeding = bleeding
|
||||
phrase-safety-dead = dead
|
||||
phrase-safety-alive = alive
|
||||
phrase-safety-trustworthy = trustworthy
|
||||
phrase-safety-escape = escape
|
||||
phrase-safety-leaving = leaving
|
||||
phrase-safety-need = need
|
||||
phrase-safety-rescue = rescue
|
||||
phrase-safety-dangerous = dangerous
|
||||
phrase-safety-hazardous = hazardous
|
||||
phrase-safety-here-to-help = Here to help
|
||||
phrase-safety-how-to-help = How can I help?
|
||||
phrase-safety-evac = Let's evacuate
|
||||
phrase-safety-not = Not
|
||||
phrase-safety-lost = Lost
|
||||
phrase-hazard-hot = Hot
|
||||
phrase-hazard-freezing = Freezing
|
||||
phrase-hazard-burning = Burning
|
||||
phrase-hazard-bad-temperature = Bad temperature
|
||||
phrase-hazard-darkness = Darkness
|
||||
phrase-safety-not = not
|
||||
phrase-safety-lost = lost
|
||||
phrase-hazard-hot = hot
|
||||
phrase-hazard-freezing = freezing
|
||||
phrase-hazard-burning = burning
|
||||
phrase-hazard-bad-temperature = bad temperature
|
||||
phrase-hazard-darkness = darkness
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
id-card-access-level-emergency-command = Emergency Command
|
||||
|
||||
id-card-access-level-orders = Orders
|
||||
id-card-access-level-mantis = Psionic Mantis
|
||||
id-card-access-level-chief-justice = Chief Justice
|
||||
|
||||
@@ -32,11 +32,6 @@ trait-conditions-tooltip = [bold]Requirements:[/bold]
|
||||
trait-conditions-not-met-tooltip = Requirements not met:
|
||||
{$requirements}
|
||||
|
||||
trait-category-full-tooltip = You have reached the maximum amount of traits that you can have in this category.
|
||||
trait-insufficient-points-tooltip = You do not have enough points to equip this trait.
|
||||
trait-condition-trait-conflict = You must not have the [color=yellow]{ $trait }[/color] trait.
|
||||
trait-condition-trait-required = You must have the [color=yellow]{ $trait }[/color] trait.
|
||||
|
||||
## Composite conditions
|
||||
trait-condition-any-of = Any of the following must be true:
|
||||
• {$requirements}
|
||||
@@ -54,8 +49,8 @@ trait-condition-department-is = You must be in the [color={$color}]{$department}
|
||||
trait-condition-department-not = You must not be in the [color={$color}]{$department}[/color] department.
|
||||
|
||||
## HasComp borg conditions
|
||||
trait-condition-borg-not = You must not be a [color=yellow]Silicon[/color].
|
||||
trait-condition-borg-not = You must not be a [color=yellow]borg[/color].
|
||||
|
||||
## Antag conditions
|
||||
# Antag conditions
|
||||
trait-condition-antag-is = Must be eligible for [color=red]{$antag}[/color] antag role.
|
||||
trait-condition-antag-not = Must not be eligible for [color=red]{$antag}[/color] antag role.
|
||||
|
||||
@@ -73,9 +73,3 @@ trait-slavic-desc = You kome from ze East, and speak vith strong Slavic accent!
|
||||
|
||||
trait-no-paradox-clone-name = No Paradox Clone
|
||||
trait-no-paradox-clone-desc = For whatever reason, the universe will only ever have one of you. You won't be able to have a paradox clone.
|
||||
|
||||
trait-ion-storm-susceptible-name = Susceptible to Ion Storms
|
||||
trait-ion-storm-susceptible-desc = Your synthetic body lacks protection against ion storms. You have a high chance of being shocked in an event of an ion storm.
|
||||
|
||||
trait-mechanical-synthetic-name = Mechanical Synthetic
|
||||
trait-mechanical-synthetic-desc = Your synthetic body is fully mechanical rather than biomechanical.
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
zombie-no-more-threat-announcement-shuttle-call = Long-range sensors indicate that you station has dealt with a biohazardous threat involving Romerol. Station decontamination required. The emergency shuttle has been called. ETA: {$time} {$units}.
|
||||
zombie-no-more-threat-announcement = Long-range sensors indicate that you station has dealt with a biohazardous threat involving Romerol. Station decontamination required. The emergency shuttle is already en route.
|
||||
@@ -1,6 +0,0 @@
|
||||
comp-lanyard-has-lanyard = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } wearing a lanyard, it reads:
|
||||
comp-lanyard-has-lanyard-blank = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } wearing a lanyard, but it's blank.
|
||||
comp-lanyard-has-lanyard-cant-read = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } wearing a lanyard, but you can't read it from this distance.
|
||||
# For listing stamps on all labels, not just lanyards
|
||||
comp-label-examine-detail-stamped-by = The label has been stamped by: {$stamps}.
|
||||
comp-lanyard-examine-detail-stamped-by = The lanyard has been stamped by: {$stamps}.
|
||||
@@ -1,2 +1,2 @@
|
||||
nuke-ops-no-more-threat-announcement-shuttle-call = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle has been called. ETA: {$time} {$units}.
|
||||
nuke-ops-no-more-threat-announcement-shuttle-call = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle has been called. ETA: {$time} {$units}. You may recall the shuttle to extend the shift.
|
||||
nuke-ops-no-more-threat-announcement = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle is already en route.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user