Compare commits

..
Author SHA1 Message Date
Vanessa 5ed135c796 lol 2026-06-29 10:21:38 -05:00
BriBroooandpre-commit-ci[bot] 448b755b75 Fixes messageId console errors (#6143)
* Fixes messageId console errors

Replaced paper.yml HydroCo's notices in the paper-misc.ftl file and moved the [bold] to the last line to prevent error messages in the console

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-06-29 09:59:09 -05:00
Delta-V bot 977e47b434 Automatic changelog update 2026-06-29 16:06:38 +02:00
Vanessa ee18b71805 Various Crew Monitor Fixes/Tweaks (#6139)
* Various Crew Monitor Fixes/Tweaks

* comment

* comment

* Increased wireless ranges
2026-06-29 14:06:18 +00:00
29b64c1f7e Suffix and other entity naming megafix (#6091)
* Suffix and other entity naming megafix

* migration

* others

---------

Signed-off-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
2026-06-29 14:00:08 +00:00
Delta-V bot a99d488b04 Automatic changelog update 2026-06-29 15:39:43 +02:00
f18d6803b9 PORT: DV's Pool Episode - Longue Chairs + Swim Rings + Pool Tiles & Water (#6113)
* Pool-Themed Decorations: Lounge Chairs, Umbrellas, Tiles, Swim Rings, and Pool Water (#2071)

<!-- Guidelines:
https://docs.spacestation14.io/en/getting-started/pr-guideline -->
<!-- NOTE: All code submitted to this repository is ALWAYS licensed
under the AGPL-3.0-or-later license.
The REUSE Specification headers or separate .license files indicate a
secondary license (e.g., MPL or MIT) solely to facilitate
integration for projects that do not use the AGPL license. This
secondary license does not replace the fact that AGPL-3.0-or-later
remains the primary and binding license.
Uncomment and modify the following line if you wish to change the
license from the default of AGPL.-->
<!--- LICENSE: AGPL -->
<!-- What did you change? -->

This PR adds a bunch of, well, mapper toys basically, but normal players
can obtain them too. They are:
- Pool tile and dark pool tile; obtainable via the cutter machine.
- Pool water; unobtainable without mapping/admin tools, but it's 1%
chlorine.
- Lounge chairs, constructed with steel and cloth. Deconstructible with
a screwdriver.
- Beach umbrellas, constructed with rods and cloth. Deconstructible with
a screwdriver.
- Swim rings, which can be ordered from Logistics. They're sort of like
the emergency comfort units (pillows), but they're inflatable rings and
you can pick them up.

<!-- Discuss how this would affect game balance or explain why it was
changed. Link any relevant discussions or issues. -->
These assets are needed for an upcoming map I'm making and I'm giving
them to the community early out of the kindness of my heart

<!-- Summary of code changes for easier review. -->
All YML and sprites babyyy

- Entity prototypes for chairs, umbrellas, pool water, swim rings, and
the pool tile stack items
- Some construction graphs
- A cargo product
- A floor definition
- Recipes for the tile cutter

Pool water IS drinkable because it's extremely funny. Keep in mind that
50u of pool water will only give you like 2 poison damage

<!-- Attach media if the PR makes ingame changes (clothing, items,
features, etc).
Small fixes/refactors are exempt. Media may be used in SS14 progress
reports with credit. -->

Preview of the stuff:

<img width="713" height="541" alt="image"
src="https://github.com/user-attachments/assets/42f1acc8-cc83-4356-a8e0-3c715245d120"
/>

<img width="697" height="666" alt="image"
src="https://github.com/user-attachments/assets/8597017a-9d03-4419-80c5-cf475f3206d1"
/>

sorry i forgot the pink ring

<img width="253" height="179" alt="image"
src="https://github.com/user-attachments/assets/7f738f8e-42b4-4ee4-aa75-9f08b67ded0c"
/>

sorry i forgot the white chair

<img width="206" height="140" alt="image"
src="https://github.com/user-attachments/assets/6fabe541-4821-4e88-8d64-a99f463c5253"
/>

Cargo:

<img width="633" height="461" alt="image"
src="https://github.com/user-attachments/assets/b8ae9b89-4d2f-4326-9814-d000d5e88809"
/>

Crafting menu:

<img width="266" height="454" alt="image"
src="https://github.com/user-attachments/assets/cc480ee6-0e0d-4055-93c3-e5a1c4e0687c"
/>

<img width="409" height="211" alt="image"
src="https://github.com/user-attachments/assets/41970a43-1ba8-4898-a96c-deb87a05a409"
/>

<img width="409" height="211" alt="image"
src="https://github.com/user-attachments/assets/ffc00874-e330-49eb-8aba-972c6d223a3a"
/>

Pool water:

<img width="680" height="463" alt="image"
src="https://github.com/user-attachments/assets/9abc48b0-8358-46de-89ef-41fc64989787"
/>

<!-- Confirm the following by placing an X in the brackets [X]: -->
- [x] I have read and am following the [Pull Request and Changelog
Guidelines](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html).
- [x] I have added media to this PR or it does not require an ingame
showcase.
- [x] I have tested any changes or additions.
- [x] I can confirm this PR contains no AI-generated content, and did
not use any AI-generated content.
<!-- You should understand that not following the above may get your PR
closed at maintainer’s discretion -->

<!-- List any breaking changes, including namespaces, public
class/method/field changes, prototype renames; and provide instructions
for fixing them.
This will be posted in #codebase-changes. -->

Nope

**Changelog**
<!-- Add a Changelog entry to make players aware of new features or
changes that could affect gameplay.
Make sure to read the guidelines and take this Changelog template out of
the comment block in order for it to show up.
Changelog must have a 🆑 symbol, so the bot recognizes the changes and
adds them to the game's changelog. -->
🆑
- add: 13 colors of lounge chairs can be constructed out of steel and
cloth.
- add: 8 colors of beach umbrellas can be constructed out of rods and
cloth.
- add: Pool tile (and dark pool tile) can be produced at the cutter
machine.
- add: Logistics can now order a crate of bulk swim rings, in 11
possible colors!
- add: For mappers (and admins): there is a new "pool water" entity that
is a nice green-cyan color and contains about 1% chlorine.

---------

Co-authored-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>

* Remove Umbrella + Fixes from Port

* Pool Ring Additions

* Buff Fishing Vendor

* grr

* its no longer 2am

---------

Co-authored-by: portfiend <109661617+portfiend@users.noreply.github.com>
Co-authored-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>
2026-06-29 08:39:22 -05:00
Delta-V bot db38e48754 Automatic changelog update 2026-06-29 15:27:30 +02:00
MD360 3acbf512be Borgs must amogus. (#6126)
* We must scream

* +1 License

* Moved to _DV audio

* + Comment

* forgot space
2026-06-29 13:27:10 +00:00
pathetic meowmeowandVanessa cb956f605f Use the actual backported engine fix (#6138)
* Revert "I hate submodules. Why did it have to be submodules? (#6117)"

This reverts commit d3b13a6c83.

* from one workaround to another

---------

Signed-off-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
2026-06-29 13:43:52 +02:00
Delta-V bot e6e094a7a1 Automatic changelog update 2026-06-29 11:46:17 +02:00
Manoob b7d8476473 Make pigs drop bacon and adjust a few recipes to do with bacon/pork (#6122)
* Make pigs drop bacon and adjust a few recipes to do with bacon/pork

* Only one piece of bacon for rice and pork!

Signed-off-by: Manoob <manu.demoen@gmail.com>

* Make pigs drop bacon AND meat

* Add 3 bacon to the chef-vend inventories

---------

Signed-off-by: Manoob <manu.demoen@gmail.com>
2026-06-29 11:45:57 +02:00
Delta-V bot 3df4bfaeb7 Automatic changelog update 2026-06-29 08:05:44 +02:00
Apachito 29b46efa16 Rebalanced Tide Crafting (#5818) 2026-06-29 02:05:24 -04:00
Vanessa e7607e1227 I love submodules. Always use submodules. (#6119)
Revert "I hate submodules. Why did it have to be submodules? (#6117)"

This reverts commit d3b13a6c83.
2026-06-29 00:16:42 -05:00
Delta-V bot 460dbe1fc1 Automatic changelog update 2026-06-29 02:54:28 +02:00
pathetic meowmeow c7c6f1a67a Add nodecrawling, implement ventcrawl with it (#5830)
* node crawling movement

* more node crawling

* quality assurance

* do-after it

* i'm ratted king

* we don't need to serialize node stuff

* rename and ser/de fix

* review fixes
2026-06-29 00:54:08 +00:00
Delta-V bot 495107e5e0 Automatic changelog update 2026-06-28 21:15:54 +02:00
pathetic meowmeowandpre-commit-ci[bot] 8366dde288 Rewrite ion laws (#6121)
* Rewrite ion laws

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* edits

* get gooned

* jumpsuit clarity

* review and tests

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-06-28 21:15:35 +02:00
Delta-V bot 5f9315f43b Automatic changelog update 2026-06-28 18:42:54 +02:00
Stxcking c21ddfeb41 Tweaks: New Fishing Vendor Stock and Price Changes (#6114)
* man

* Update fishing_points.yml
2026-06-28 11:42:34 -05:00
Delta-V bot 9b0eef0805 Automatic changelog update 2026-06-28 18:42:21 +02:00
StxckingandRadezolid 36bc3d0b04 The Disappearance of Hatsune Miku (#5790)
* I HATE FUN

* uh

* make it actually parent

* Update Resources/Prototypes/_DV/Catalog/Fills/Boxes/general.yml

Co-authored-by: Radezolid <snappednexus@gmail.com>
Signed-off-by: Stxcking <217132821+Stxcking@users.noreply.github.com>

---------

Signed-off-by: Stxcking <217132821+Stxcking@users.noreply.github.com>
Co-authored-by: Radezolid <snappednexus@gmail.com>
2026-06-28 11:42:01 -05:00
Delta-V bot e9b6634747 Automatic changelog update 2026-06-28 15:26:15 +02:00
Vape d1390f5e98 Update tips.ftl (#6133) 2026-06-28 15:25:56 +02:00
Delta-V bot 196e2a52e3 Automatic changelog update 2026-06-28 14:19:16 +02:00
Proxy also works :3 401ae01321 Reduce Holoparasite Cost (#6115)
Update uplink_catalog.yml
2026-06-28 14:18:56 +02:00
github-actions[bot]andDeltaV-Bot 793236f12b Update Credits (#6135)
Co-authored-by: DeltaV-Bot <github@deltav.gay>
2026-06-28 04:52:00 +02:00
Delta-V bot 229491aa46 Automatic changelog update 2026-06-28 02:39:01 +02:00
Vape a09e09ac0f Remove mention of "morphotypes" (#6134) 2026-06-27 19:38:41 -05:00
Delta-V bot e59b37b081 Automatic changelog update 2026-06-27 22:18:26 +02:00
Vape b359f44c15 Fix: Fixes to both Harpy and Moth (#6131)
Bug Fix
2026-06-27 15:18:06 -05:00
Delta-V bot 932dd5e429 Automatic changelog update 2026-06-26 19:23:56 +02:00
wesker 3001253e43 Synthetic Emotes Fix (#6125)
* separate synthetic emote

* fix duplicate IDs (server error)

* Update speech_emotes.yml

* maybe this

* maybe keep the removed things from upstream lol

* imagine yamlops-ing when the problem was your trash code all along
2026-06-26 19:23:37 +02:00
Vanessa d3b13a6c83 I hate submodules. Why did it have to be submodules? (#6117)
Living on a prayer.
2026-06-25 15:07:33 -05:00
Delta-V bot 2ab0163598 Automatic changelog update 2026-06-25 20:04:07 +02:00
pathetic meowmeow 6cdeb3d9cf Suit sensors, but in space? Perish the thought. (#6054) 2026-06-25 12:59:49 -05:00
Delta-V bot d7543bd24a Automatic changelog update 2026-06-25 18:17:46 +02:00
f7f800c439 Tweaked Synthetic (#6090)
* actually not overhauled but tweaked i think

* forgot to stage this one

* make shocking 60% chance instead of 80%, and make shock dmg 5-20 random.

* update comment

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* okay this should work + remember to mention new changesa asdas asd

* I ALREADY STAGED ALL

* important summary comments to give more important info when someone's
too lazy to check the rule

* fix some stuff

* signs of shock

* Update Resources/Prototypes/_DV/Traits/meta.yml

Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: wesker <53323309+weskified@users.noreply.github.com>

* Update Resources/Prototypes/_DV/Traits/meta.yml

Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: wesker <53323309+weskified@users.noreply.github.com>

* Update Resources/Locale/en-US/_DV/traits/traits.ftl

Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: wesker <53323309+weskified@users.noreply.github.com>

* changessss

---------

Signed-off-by: wesker <53323309+weskified@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
2026-06-25 11:17:26 -05:00
Delta-V bot b6ed84325f Automatic changelog update 2026-06-25 17:37:53 +02:00
ManoobandVanessa 61aee79dc2 Replace nachos recipes (#6099)
* make nachos from tacos and change how cheesy and chili variants get made

* Change WizDen Contentfreeze recipelimit

* Update Resources/Prototypes/_DV/Recipes/Cooking/deep_fryer_recipes.yml

Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: Manoob <manu.demoen@gmail.com>

* Moved nacho metamorph to DV folder

* newlline, keep file as it was :^)

---------

Signed-off-by: Manoob <manu.demoen@gmail.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
2026-06-25 10:37:33 -05:00
Delta-V bot 55fe6026ea Automatic changelog update 2026-06-25 17:28:10 +02:00
pathetic meowmeowandVanessa 6dfa12a509 AI? Being able to send faxes? Perish the thought. (#6064)
* AI? Being able to send faxes? Perish the thought.

* Update Resources/Prototypes/Entities/Mobs/Player/silicon.yml

Signed-off-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>

---------

Signed-off-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
2026-06-25 15:27:49 +00:00
Delta-V bot 485fd14f05 Automatic changelog update 2026-06-25 16:07:32 +02:00
Theo 031b37ffcb Washing machines can hold huge items (#6086)
washer size huge
2026-06-25 09:07:12 -05:00
Delta-V bot 06365bdbf0 Automatic changelog update 2026-06-25 15:10:58 +02:00
Tmanzxd 7f18c5f346 Commented out Surgeon Job Requirement for CMO (#6112) 2026-06-25 13:10:38 +00:00
Delta-V bot d407652eb0 Automatic changelog update 2026-06-25 04:28:46 +02:00
Manoob 9108e2c9b5 Fix Low metabolism rate modifiers from truncating to zero (#6104) 2026-06-24 21:28:26 -05:00
VelcroboyandVelcroboy c7ef614f3d Edit towel spawner (#6106)
* Edit towel spawner

* numbers

---------

Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
2026-06-24 21:26:51 -05:00
VelcroboyandVelcroboy fa735f7669 Fix Chapel Access (#6105)
Fix chapel access

Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
2026-06-24 20:12:36 -05:00
314 changed files with 5060 additions and 687 deletions
+1
View File
@@ -32,6 +32,7 @@ jobs:
run: |
cd RobustToolbox/
git submodule update --init --recursive
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
+1
View File
@@ -29,6 +29,7 @@ jobs:
run: |
cd RobustToolbox
git fetch --depth=1
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
- name: Install dependencies
run: dotnet restore
+1
View File
@@ -23,6 +23,7 @@ jobs:
run: |
cd RobustToolbox/
git submodule update --init --recursive
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
@@ -1,5 +1,6 @@
using Content.Client.Pinpointer.UI;
using Robust.Client.Graphics;
using Robust.Client.Player; // DeltaV
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
@@ -7,6 +8,9 @@ namespace Content.Client.Medical.CrewMonitoring;
public sealed partial class CrewMonitoringNavMapControl : NavMapControl
{
[Dependency] private IPlayerManager _playerManager = default!; // DeltaV
private readonly SharedTransformSystem _xform; // DeltaV
public NetEntity? Focus;
public Dictionary<NetEntity, string> LocalizedNames = new();
@@ -15,6 +19,9 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
public CrewMonitoringNavMapControl() : base()
{
IoCManager.InjectDependencies(this); // DeltaV - Gotta inject!
_xform = EntManager.System<SharedTransformSystem>(); // DeltaV - Gotta inject!
WallColor = new Color(192, 122, 196);
TileColor = new(71, 42, 72);
BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity));
@@ -77,4 +84,27 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
_trackedEntityLabel.Text = string.Empty;
_trackedEntityPanel.Visible = false;
}
/// <summary>
/// DeltaV - Do some things before the base NavMap Draw and also force the redraw of the map
/// after if the MapUid was null when the CrewMonitor UI was opened.
/// </summary>
/// <param name="handle"></param>
protected override void Draw(DrawingHandleScreen handle)
{
// MapUid will not have a value if the crew monitor UI was activated off-grid.
var forceMapUpdate = false;
if (!MapUid.HasValue && _playerManager.LocalEntity is { } player)
{
MapUid = _xform.GetGrid(player);
forceMapUpdate = true;
}
base.Draw(handle);
// We need to call this after Draw() because UpdateNavMap has functions that uses variables
// set in Draw()
if (forceMapUpdate)
UpdateNavMap();
}
}
@@ -1,13 +1,16 @@
<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"/>
<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" />
<BoxContainer Orientation="Vertical" Margin="0 0 10 0">
<controls:StripeBack>
<PanelContainer>
@@ -5,6 +5,7 @@ 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;
@@ -27,6 +28,7 @@ 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;
@@ -39,8 +41,10 @@ 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)
@@ -50,8 +54,10 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
if (_entManager.TryGetComponent<TransformComponent>(mapUid, out var xform))
NavMap.MapUid = xform.GridUid;
else
NavMap.Visible = false;
// Begin DeltaV - handle navmap visibility based on current position
// else
// NavMap.Visible = false;
// End DeltaV - handle navmap visibility based on current position
StationName.AddStyleClass("LabelBig");
StationName.Text = stationName;
@@ -62,6 +68,28 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
{
base.FrameUpdate(args);
// Begin DeltaV - handle navmap visibility based on current position
var ent = ShuttleMap.Owner;
// If an entity is being tracked, use them as the focus, since they may be off-station
// and we want to use the nav map if they are.
if (_trackedEntity is { } trackedEntity)
ent = _entManager.GetEntity(trackedEntity);
// We need to make sure the entity is valid because for some reason, it *could* be an
// invalid entity and GetOwningStation will throw an exception.
if (ent.HasValue && ent.Value.IsValid() && _station.GetOwningStation(ent) 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();
}
@@ -69,6 +97,7 @@ 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)
@@ -304,7 +333,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
jobContainer.AddChild(jobLabel);
// Add user coordinates to the navmap
if (coordinates != null && NavMap.Visible && _blipTexture != null)
if (coordinates != null && _blipTexture != null) // DeltaV - don't filter the navmap visibility
{
NavMap.TrackedEntities.TryAdd(sensor.SuitSensorUid,
new NavMapBlip
@@ -323,6 +352,14 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
if (_trackedEntity == sensor.SuitSensorUid)
{
_trackedEntity = null;
// BEGIN DeltaV - center on crew monitor user if deselecting
// This fixes some weird bug where if you deselect a tracked entity, it will
// just not draw the map at all in some cases.
if (ShuttleMap.Owner is { } handheld &&
_transformSystem.TryGetMapOrGridCoordinates(handheld, out var userCoords) &&
userCoords is { } coords)
NavMap.CenterToCoordinates(coords);
// END DeltaV
}
else
@@ -56,8 +56,8 @@ public partial class NavMapControl : MapGridControl
// Constants
protected float UpdateTime = 1.0f;
protected float MaxSelectableDistance = 10f;
protected float MinDragDistance = 5f;
public float MaxSelectableDistance = 10f; // DeltaV - accessible to CrewMonitoringShuttleControl
public float MinDragDistance = 5f; // DeltaV - accessible to CrewMonitoringShuttleControl
protected static float MinDisplayedRange = 8f;
protected static float MaxDisplayedRange = 128f;
protected static float DefaultDisplayedRange = 48f;
@@ -193,6 +193,13 @@ 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);
@@ -32,6 +32,21 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
}
}
// Begin DeltaV - node crawling
private Type[] _types = new Type[] { };
[ViewVariables]
public Type[] Types
{
get => _types;
set
{
_types = value;
UpdateAll();
}
}
// End DeltaV - node crawling
public override void Initialize()
{
base.Initialize();
@@ -65,6 +80,17 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
var revealed = !covered || ShowAll || scannerRevealed;
// Begin DeltaV - node crawling
foreach (var type in _types)
{
if (!HasComp(uid, type))
continue;
revealed = true;
break;
}
// End DeltaV - node crawling
// set visibility & color of each layer
foreach (var layer in args.Sprite.AllLayers)
{
@@ -0,0 +1,180 @@
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);
}
}
}
@@ -0,0 +1,43 @@
using Content.Client.SubFloor;
using Content.Shared._DV.NodeCrawl;
using Robust.Client.Player;
using Robust.Shared.Player;
namespace Content.Client._DV.NodeCrawl;
public sealed class NodeCrawlSystem : SharedNodeCrawlSystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly SubFloorHideSystem _subfloor = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NodeCrawlerComponent, LocalPlayerAttachedEvent>(OnAttached);
SubscribeLocalEvent<NodeCrawlerComponent, LocalPlayerDetachedEvent>(OnDetached);
SubscribeLocalEvent<NodeCrawlerComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
}
private void OnAttached(Entity<NodeCrawlerComponent> ent, ref LocalPlayerAttachedEvent args)
{
if (ent.Comp.Mover is not null)
_subfloor.Types = ent.Comp.RevealedComponents;
}
private void OnDetached(Entity<NodeCrawlerComponent> ent, ref LocalPlayerDetachedEvent args)
{
_subfloor.Types = new Type[] { };
}
private void OnAfterAutoHandleState(Entity<NodeCrawlerComponent> ent, ref AfterAutoHandleStateEvent args)
{
if (_player.LocalEntity != ent)
return;
if (ent.Comp.Mover is not null)
_subfloor.Types = ent.Comp.RevealedComponents;
else
_subfloor.Types = new Type[] { };
}
}
@@ -0,0 +1,17 @@
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;
}
}
}
@@ -0,0 +1,144 @@
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);
}
}
@@ -0,0 +1,14 @@
<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>
@@ -0,0 +1,27 @@
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();
}
}
@@ -0,0 +1,64 @@
<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>
@@ -0,0 +1,70 @@
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;
}
}
@@ -0,0 +1,37 @@
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 _));
}
}
@@ -0,0 +1,29 @@
<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>
@@ -0,0 +1,92 @@
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;
}
}
@@ -0,0 +1,7 @@
<Button xmlns="https://spacestation14.io">
<TextureRect Name="TextureRect"
TextureScale="0.5 0.5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="KeepCentered"/>
</Button>
@@ -0,0 +1,17 @@
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 = 269; // DeltaV - was 218
var recipesLimit = 266; // DeltaV - was 218
if (recipesCount > recipesLimit)
{
@@ -184,6 +184,11 @@ 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);
+13 -8
View File
@@ -5,6 +5,7 @@ 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;
@@ -90,10 +91,10 @@ public sealed class FaxSystem : EntitySystem
{
base.Update(frameTime);
var query = EntityQueryEnumerator<FaxMachineComponent, ApcPowerReceiverComponent>();
while (query.MoveNext(out var uid, out var fax, out var receiver))
var query = EntityQueryEnumerator<FaxMachineComponent>();
while (query.MoveNext(out var uid, out var fax)) // DeltaV - faxes aren't necessarily powered
{
if (!receiver.Powered)
if (TryComp<ApcPowerReceiverComponent>(uid, out var receiver) && !receiver.Powered) // DeltaV - faxes aren't necessarily powered
continue;
ProcessPrintingAnimation(uid, frameTime, fax);
@@ -392,7 +393,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);
var state = new FaxUiState(component.FaxName, component.KnownFaxes, canSend, canCopy, isPaperInserted, component.DestinationFaxAddress, component.SendTimeoutRemaining <= 0); // DeltaV - AI fax
_userInterface.SetUiState(uid, FaxUiKey.Key, state);
}
@@ -461,7 +462,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, FaxCopyMessage args)
public void Copy(EntityUid uid, FaxMachineComponent? component, BoundUserInterfaceMessage args, EntityUid? item = null) // DeltaV - station AI fax
{
if (!Resolve(uid, ref component))
return;
@@ -469,7 +470,7 @@ public sealed class FaxSystem : EntitySystem
if (component.SendTimeoutRemaining > 0)
return;
var sendEntity = component.PaperSlot.Item;
var sendEntity = item ?? component.PaperSlot.Item; // DeltaV - station AI fax
if (sendEntity == null)
return;
@@ -511,7 +512,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, FaxSendMessage args)
public void Send(EntityUid uid, FaxMachineComponent? component, BoundUserInterfaceMessage args, EntityUid? item = null) // DeltaV - station AI fax
{
if (!Resolve(uid, ref component))
return;
@@ -519,7 +520,7 @@ public sealed class FaxSystem : EntitySystem
if (component.SendTimeoutRemaining > 0)
return;
var sendEntity = component.PaperSlot.Item;
var sendEntity = item ?? component.PaperSlot.Item; // DeltaV - station AI fax
if (sendEntity == null)
return;
@@ -635,6 +636,10 @@ 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,5 @@
using Content.Server.StationEvents.Components;
using Content.Shared._DV.IonLaws; // DeltaV - ion laws
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Dataset;
@@ -20,6 +21,7 @@ public sealed class IonStormSystem : EntitySystem
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SiliconLawSystem _siliconLaw = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly IonLawSystem _ionLaw = default!; // DeltaV - ion laws
// funny
private static readonly ProtoId<DatasetPrototype> Threats = "IonStormThreats";
@@ -93,7 +95,7 @@ public sealed class IonStormSystem : EntitySystem
}
// generate a new law...
var newLaw = GenerateLaw();
var newLaw = _ionLaw.GenerateLaw(_robustRandom); // GenerateLaw(); DeltaV - inject our own
// see if the law we add will replace a random existing law or be a new glitched order one
if (laws.Laws.Count > 0 && _robustRandom.Prob(target.ReplaceChance))
@@ -6,4 +6,41 @@ 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,9 +6,12 @@ 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;
@@ -17,6 +20,8 @@ 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)
{
@@ -26,18 +31,32 @@ 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;
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);
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
}
// CD - End of synth trait
+10 -1
View File
@@ -7,7 +7,16 @@ namespace Content.Server._CD.Traits;
public sealed partial class SynthComponent : Component
{
/// <summary>
/// The chance that the synth is alerted of an ion storm
/// 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.
/// </summary>
[DataField]
public float AlertChance = 0.3f;
+27 -2
View File
@@ -1,8 +1,12 @@
using Content.Server.Body.Systems;
using Content.Server.Database;
using Content.Server.Chat.Systems;
using Content.Shared.Body.Components;
using Content.Shared.Chat;
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;
@@ -12,15 +16,22 @@ 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!;
[Dependency] private readonly ChatSystem _chat = default!;
private EmoteSoundsPrototype? _syntheticEmoteSounds; // delta-v - proper synthe emote implementation
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SynthComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<SynthComponent, EmoteEvent>(OnEmote); // delta-v - proper synthe emote implementation
}
private void OnStartup(EntityUid uid, SynthComponent component, ComponentStartup args)
@@ -38,5 +49,19 @@ public sealed class SynthSystem : EntitySystem
_bloodstream.ChangeBloodReagents((uid, bloodstream), new([new(SynthBloodReagent, bloodstream.BloodReferenceSolution.Volume)]));
}
// End DeltaV
_tag.AddTag(uid, SyntheticEmotesTag); // delta-v - proper synthe emote implementation
}
}
// Start DeltaV - proper synthe emote implementation
private void OnEmote(EntityUid uid, SynthComponent component, ref EmoteEvent args)
{
if (args.Handled)
return;
_syntheticEmoteSounds ??= _proto.Index(SyntheticEmoteSounds);
args.Handled = _chat.TryPlayEmoteSound(uid, _syntheticEmoteSounds, args.Emote);
}
// End DeltaV
}
@@ -0,0 +1,26 @@
using Content.Server.Administration;
using Content.Shared._DV.IonLaws;
using Content.Shared.Administration;
using Robust.Shared.Random;
using Robust.Shared.Toolshed;
namespace Content.Server._DV.IonLaws;
[ToolshedCommand, AdminCommand(AdminFlags.Fun)]
public sealed class IonLawCommand : ToolshedCommand
{
[Dependency] private readonly IRobustRandom _random = default!;
private IonLawSystem? _ionLaw;
[CommandImplementation("generate")]
public IEnumerable<string> GenerateNames(int count)
{
_ionLaw ??= GetSys<IonLawSystem>();
for (var i = 0; i < count; i++)
{
yield return _ionLaw.GenerateLaw(_random);
}
}
}
@@ -0,0 +1,101 @@
using System.Numerics;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Systems;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Shared._DV.NodeCrawl;
using Content.Shared.Atmos;
using Content.Shared.NodeContainer;
namespace Content.Server._DV.NodeCrawl;
public sealed class NodeCrawlSystem : SharedNodeCrawlSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrawlableNodeComponent, NodeGroupsRebuilt>(OnNodeGroupsRebuilt);
SubscribeLocalEvent<NodeCrawlerComponent, InhaleLocationEvent>(OnInhaleLocation);
SubscribeLocalEvent<NodeCrawlerComponent, ExhaleLocationEvent>(OnExhaleLocation);
SubscribeLocalEvent<NodeCrawlerComponent, AtmosExposedGetAirEvent>(OnGetAir);
}
private Entity<NodeContainerComponent>? GetNodeContainer(Entity<NodeCrawlerComponent> crawler)
{
if (!TryComp<NodeCrawlerMovementComponent>(crawler.Comp.Mover, out var mover) || mover.Node is not { } node)
return null;
if (!TryComp<NodeContainerComponent>(node, out var nodeContainer))
return null;
return (node, nodeContainer);
}
private GasMixture? GetAir(Entity<NodeCrawlerComponent> crawler)
{
if (GetNodeContainer(crawler) is not { } nodeContainer)
return null;
foreach (var containedNode in nodeContainer.Comp.Nodes.Values)
{
if (containedNode is not PipeNode pipe)
continue;
return pipe.Air;
}
return null;
}
private void OnInhaleLocation(Entity<NodeCrawlerComponent> ent, ref InhaleLocationEvent args)
{
if (GetAir(ent) is not { } air)
return;
args.Gas = air;
}
private void OnExhaleLocation(Entity<NodeCrawlerComponent> ent, ref ExhaleLocationEvent args)
{
if (GetAir(ent) is not { } air)
return;
args.Gas = air;
}
private void OnGetAir(Entity<NodeCrawlerComponent> ent, ref AtmosExposedGetAirEvent args)
{
if (args.Handled || GetAir(ent) is not { } air)
return;
args.Gas = air;
args.Handled = true;
}
private void OnNodeGroupsRebuilt(Entity<CrawlableNodeComponent> ent, ref NodeGroupsRebuilt args)
{
if (!TryComp<NodeContainerComponent>(ent, out var nodeContainer))
return;
ent.Comp.DeadEnd = false;
var set = new HashSet<EntityUid>();
foreach (var node in nodeContainer.Nodes.Values)
{
foreach (var reachable in node.ReachableNodes)
{
set.Add(reachable.Owner);
}
if (node is PipeNode pipeNode &&
node.ReachableNodes.Count != BitOperations.PopCount((uint)pipeNode.CurrentPipeDirection))
{
ent.Comp.DeadEnd = true;
}
}
ent.Comp.ReachableNodes = set;
Dirty(ent);
}
}
@@ -0,0 +1,39 @@
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);
}
}
@@ -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");
public SoundSpecifier? PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg"); // DeltaV - nullable
/// <summary>
/// Sound to play when fax successfully send message
+4 -1
View File
@@ -17,13 +17,15 @@ 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)
string? destAddress,
bool canSendCooldown) // DeltaV - AI fax
{
DeviceName = deviceName;
AvailablePeers = peers;
@@ -31,6 +33,7 @@ public sealed class FaxUiState : BoundUserInterfaceState
CanSend = canSend;
CanCopy = canCopy;
DestinationAddress = destAddress;
CanSendCooldown = canSendCooldown; // DeltaV - AI fax
}
}
@@ -68,6 +68,11 @@ 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;
@@ -348,7 +353,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) || transform.GridUid == null)
if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null || !HasComp<MobStateComponent>(sensor.User)) // DeltaV - don't block on grids here
return null;
// try to get mobs id from ID slot
@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Content.Shared._DV.Movement; // DeltaV
using Content.Shared._DV.NodeCrawl; // DeltaV - Node Crawling
using Content.Shared.ActionBlocker;
using Content.Shared.CCVar;
using Content.Shared.Friction;
@@ -50,6 +51,7 @@ public abstract partial class SharedMoverController : VirtualController
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TagSystem _tags = default!;
[Dependency] private readonly TileMovementSystem _tileMovement = default!; // DeltaV
[Dependency] private readonly NodeCrawlerMovementSystem _nodeCrawlerMovement = default!; // DeltaV - node crawling
protected EntityQuery<CanMoveInAirComponent> CanMoveInAirQuery;
protected EntityQuery<FootstepModifierComponent> FootstepModifierQuery;
@@ -264,6 +266,11 @@ public abstract partial class SharedMoverController : VirtualController
return;
// End DeltaV Additions
// Begin DeltaV Additions - node crawling
if (_nodeCrawlerMovement.TryTick((uid, mover, physicsComponent, xform)))
return;
// End DeltaV Additions
var touching = false;
// Whether we use tilefriction or not
if (weightless || inAirHelpless)
+1 -1
View File
@@ -276,7 +276,7 @@ public sealed class PaperSystem : EntitySystem
_appearance.SetData(entity, PaperVisuals.Status, status, appearance);
}
private void UpdateUserInterface(Entity<PaperComponent> entity)
public void UpdateUserInterface(Entity<PaperComponent> entity) // DeltaV - station AI
{
_uiSystem.SetUiState(entity.Owner, PaperUiKey.Key, new PaperBoundUserInterfaceState(entity.Comp.Content, entity.Comp.StampedBy, entity.Comp.Mode));
}
+2 -2
View File
@@ -65,8 +65,8 @@ public enum CollisionGroup
TabletopMachineLayer = Opaque | BulletImpassable,
// Airlocks, windoors, firelocks
GlassAirlockLayer = HighImpassable | MidImpassable | BulletImpassable | InteractImpassable,
AirlockLayer = Opaque | GlassAirlockLayer,
GlassAirlockLayer = HighImpassable | MidImpassable | LowImpassable | BulletImpassable | InteractImpassable, // DeltaV - we have ventcrawling
AirlockLayer = Opaque | LowImpassable | GlassAirlockLayer, // DeltaV - we have ventcrawling
// Airlock assembly
HumanoidBlockLayer = HighImpassable | MidImpassable,
@@ -101,6 +101,12 @@ public sealed partial class RatKingComponent : Component
{ RatKingOrderType.CheeseEm, "RatKingCommandCheeseEm" },
{ RatKingOrderType.Loose, "RatKingCommandLoose" }
};
/// <summary>
/// DeltaV - Servants within this radius will join the Rat King when vent crawling
/// </summary>
[DataField]
public float VentCrawlRecruitRadius = 4f;
}
[Serializable, NetSerializable]
@@ -415,7 +415,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, EntityStorageComponent? component = null)
{
if (!Resolve(target, ref component))
if (!Resolve(target, ref component, false)) // DeltaV - Prevent HTNOperators from failing tests
return false;
if (!HasComp<HandsComponent>(user))
@@ -0,0 +1,4 @@
namespace Content.Shared._DV.Fax;
[ByRefEvent]
public readonly record struct FaxPrintedEvent(EntityUid Fax);
@@ -0,0 +1,74 @@
using System.Linq;
using System.Globalization;
using Content.Shared.Dataset;
using Content.Shared.Humanoid;
using Content.Shared.Random.Helpers;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared._DV.IonLaws;
public sealed class IonLawSystem : EntitySystem
{
[Dependency] private readonly ILocalizationManager _localization = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly ISharedPlayerManager _player = default!;
private const string Culture = "en-US";
public override void Initialize()
{
base.Initialize();
var culture = new CultureInfo(Culture);
_localization.AddFunction(culture, "PICK", FormatPick);
_localization.AddFunction(culture, "PICK-ENTITY", FormatPickEntity);
}
private ILocValue FormatPick(LocArgs args)
{
var rand = ((LocValueRandom)args.Args[0]).Value;
return rand.Pick(args.Args.Skip(1).ToList());
}
private ILocValue FormatPickEntity(LocArgs args)
{
var rand = ((LocValueRandom)args.Args[0]).Value;
var players = ((LocValueEntityList)args.Args[1]).Value;
if (players.Count == 0)
{
return new LocValueString(Loc.GetString("dv-ion-law-target-fallback", ("random", new LocValueRandom(rand))));
}
return new LocValueEntity(rand.PickAndTake(players));
}
private static readonly ProtoId<LocalizedDatasetPrototype> IonLawTemplates = "IonLawTemplates";
public string GenerateLaw(IRobustRandom random)
{
var template = random.PickId(_proto.Index(IonLawTemplates));
var players = _player.Sessions
.Where(x => HasComp<HumanoidAppearanceComponent>(x.AttachedEntity))
.Select(x => x.AttachedEntity!.Value)
.ToList();
return Loc.GetString(template, ("random", new LocValueRandom(random)), ("players", new LocValueEntityList(players)));
}
}
public sealed record LocValueRandom(IRobustRandom Value) : LocValue<IRobustRandom>(Value)
{
public override string Format(LocContext ctx)
{
throw new InvalidOperationException("Attempted to format a IRobustRandom");
}
}
public sealed record LocValueEntityList(List<EntityUid> Value) : LocValue<List<EntityUid>>(Value)
{
public override string Format(LocContext ctx)
{
throw new InvalidOperationException("Attempted to format a List<EntityUid>");
}
}
@@ -0,0 +1,29 @@
using Robust.Shared.GameStates;
namespace Content.Shared._DV.NodeCrawl;
/// <summary>
/// Represents an entity in a node network that can be crawled in
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedNodeCrawlSystem), typeof(NodeCrawlerMovementSystem))]
public sealed partial class CrawlableNodeComponent : Component
{
/// <summary>
/// Other entities with <see cref="CrawlableNodeComponent" /> that can be reached from this one
/// </summary>
[ViewVariables, AutoNetworkedField]
public HashSet<EntityUid> ReachableNodes = new();
/// <summary>
/// Whether this node has an unconnected node and should be exited from on movement
/// </summary>
[ViewVariables, AutoNetworkedField]
public bool DeadEnd;
/// <summary>
/// All entities with <see cref="NodeCrawlerMovementComponent" /> that are associated with this one
/// </summary>
[DataField, AutoNetworkedField]
public HashSet<EntityUid> Crawlers = new();
}
@@ -0,0 +1,9 @@
using Robust.Shared.GameStates;
namespace Content.Shared._DV.NodeCrawl;
/// <summary>
/// Marker component to use on atmos-related devices that node crawlers can enter/exit out of.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class NodeCrawlVentAccessComponent : Component;
@@ -0,0 +1,44 @@
using Content.Shared.DoAfter;
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared._DV.NodeCrawl;
/// <summary>
/// Handles entities that can enter and exit node-constrained movement.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
[Access(typeof(SharedNodeCrawlSystem))]
public sealed partial class NodeCrawlerComponent : Component
{
/// <summary>
/// The mover this crawler is currently being carried by, if any
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? Mover;
/// <summary>
/// Components of entities to reveal while inside a mover
/// </summary>
[DataField(readOnly: true)]
public Type[] RevealedComponents;
/// <summary>
/// Whitelist for entities that will be considered as exit nodes.
/// </summary>
[DataField]
public EntityWhitelist? ExitNodes;
/// <summary>
/// How long it takes to enter a node.
/// </summary>
[DataField]
public TimeSpan EnterDelay = TimeSpan.FromSeconds(1);
}
[Serializable, NetSerializable]
public sealed partial class NodeCrawlEnterDoAfterEvent : SimpleDoAfterEvent;
[ByRefEvent]
public readonly record struct NodeCrawlerStartedCrawlingEvent(Entity<NodeCrawlerMovementComponent> Mover);
@@ -0,0 +1,42 @@
using Robust.Shared.GameStates;
namespace Content.Shared._DV.NodeCrawl;
/// <summary>
/// Handles node-confined movement for an entity.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
[Access(typeof(NodeCrawlerMovementSystem))]
public sealed partial class NodeCrawlerMovementComponent : Component
{
/// <summary>
/// The current node.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? Node;
/// <summary>
/// The target node being moved to.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? TargetNode;
/// <summary>
/// The crawler being carried by this entity.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? HeldCrawler;
/// <summary>
/// The required angle to be within for deciding which node to move from the target direction
/// </summary>
[DataField]
public double RequiredAngle = Math.PI / 4f;
}
/// <summary>
/// Event raised when a node crawler arrives at a node entity.
/// </summary>
/// <param name="Node">The arrived-at node.</param>
[ByRefEvent]
public readonly record struct NodeCrawlerArrivedAtNodeEvent(EntityUid Node);
@@ -0,0 +1,195 @@
using System.Numerics;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
namespace Content.Shared._DV.NodeCrawl;
public sealed class NodeCrawlerMovementSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMoverController _mover = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedNodeCrawlSystem _nodeCrawl = default!;
public bool TryTick(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent> sharedMover)
{
if (!TryComp<NodeCrawlerMovementComponent>(sharedMover, out var crawler) || crawler.Node is null)
return false;
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover = (sharedMover.Owner, sharedMover.Comp1, sharedMover.Comp2, sharedMover.Comp3, crawler);
if (mover.Comp4.TargetNode is { } target)
OngoingMovement(mover, target);
else
StartMovement(mover);
return true;
}
private void StartMovement(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover)
{
if (GetDestination(mover, mover.Comp1.HeldMoveButtons) is not { } target)
{
if (mover.Comp4.Node is not { } node)
return;
var nodeComp = Comp<CrawlableNodeComponent>(node);
if (!nodeComp.DeadEnd)
return;
if (mover.Comp4.HeldCrawler is not { } crawler)
return;
_nodeCrawl.ExitNodeCrawl((crawler, Comp<NodeCrawlerComponent>(crawler)));
return;
}
mover.Comp4.TargetNode = target;
Dirty(mover, mover.Comp4);
OngoingMovement(mover, target);
}
private void StopMovement(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover)
{
_physics.SetLinearVelocity(mover, Vector2.Zero, body: mover.Comp2);
_physics.SetAngularVelocity(mover, 0, body: mover.Comp2);
}
private void OngoingMovement(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover,
EntityUid target)
{
var speed = MoveSpeed(mover);
if (ReachedDestination(mover, target, speed))
{
StopMovement(mover);
SetNode((mover, mover), target);
mover.Comp4.TargetNode = null;
Dirty(mover, mover.Comp4);
if (TryComp<MovementRelayTargetComponent>(mover, out var movementTarget))
{
var evt = new NodeCrawlerArrivedAtNodeEvent(target);
RaiseLocalEvent(movementTarget.Source, ref evt);
}
StartMovement(mover);
return;
}
UpdateMovement(mover, target, speed);
}
private float MoveSpeed(Entity<InputMoverComponent> mover)
{
var moveSpeed = CompOrNull<MovementSpeedModifierComponent>(mover);
var walkSpeed = moveSpeed?.CurrentWalkSpeed ?? MovementSpeedModifierComponent.DefaultBaseWalkSpeed;
var sprintSpeed = moveSpeed?.CurrentSprintSpeed ?? MovementSpeedModifierComponent.DefaultBaseSprintSpeed;
return mover.Comp.Sprinting ? sprintSpeed : walkSpeed;
}
private void UpdateMovement(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover,
EntityUid target,
float speed)
{
var delta = _transform.GetWorldPosition(target) - _transform.GetWorldPosition(mover.Comp3);
var facing = Angle.FromWorldVec(delta);
_transform.SetWorldRotation(mover.Comp3, facing);
var velocity = delta;
velocity.Normalize();
velocity *= speed;
_physics.SetCanCollide(mover, false);
_physics.SetLinearVelocity(mover, velocity, body: mover.Comp2);
_physics.SetAngularVelocity(mover, 0, body: mover.Comp2);
}
private bool ReachedDestination(
Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> mover,
EntityUid target,
float speed)
{
var delta = _transform.GetWorldPosition(mover.Comp3) - _transform.GetWorldPosition(target);
return delta.EqualsApprox(Vector2.Zero, speed * 0.01f);
}
private EntityUid? GetDestination(Entity<InputMoverComponent, PhysicsComponent, TransformComponent, NodeCrawlerMovementComponent> ent, MoveButtons buttons)
{
if ((buttons & MoveButtons.AnyDirection) == 0)
return null;
var target = _mover.DirVecForButtons(buttons);
target = _mover.GetParentGridAngle(ent.Comp1).RotateVec(target);
if (ent.Comp4.Node is not { } node || !Exists(node) || !TryComp<CrawlableNodeComponent>(node, out var nodeCrawl))
return null;
var nodeXform = Transform(node);
var nodeWorld = _transform.GetWorldPosition(nodeXform);
var smallestTarget = EntityUid.Invalid;
var largestDot = 0d;
foreach (var reachable in nodeCrawl.ReachableNodes)
{
var reachableXform = Transform(reachable);
var reachableWorld = _transform.GetWorldPosition(reachableXform);
var delta = reachableWorld - nodeWorld;
delta.Normalize();
var deltaTargetDot = Vector2.Dot(delta, target);
if (deltaTargetDot < largestDot)
continue;
smallestTarget = reachable;
largestDot = deltaTargetDot;
}
if (!smallestTarget.Valid || largestDot <= Math.Cos(ent.Comp4.RequiredAngle))
return null;
return smallestTarget;
}
public void SetNode(Entity<NodeCrawlerMovementComponent> ent, EntityUid? node)
{
if (ent.Comp.Node == node)
return;
if (ent.Comp.Node is { } oldNode)
{
var oldNodeComp = Comp<CrawlableNodeComponent>(oldNode);
oldNodeComp.Crawlers.Remove(ent);
Dirty(oldNode, oldNodeComp);
}
if (node is { } newNode)
{
var newNodeComp = Comp<CrawlableNodeComponent>(newNode);
newNodeComp.Crawlers.Add(ent);
Dirty(newNode, newNodeComp);
}
ent.Comp.Node = node;
Dirty(ent);
}
public void SetHeldCrawler(Entity<NodeCrawlerMovementComponent> ent, EntityUid? held)
{
if (ent.Comp.HeldCrawler == held)
return;
ent.Comp.HeldCrawler = held;
Dirty(ent);
}
}
@@ -0,0 +1,229 @@
using Content.Shared.DoAfter;
using Content.Shared.Eye;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.RatKing;
using Content.Shared.Verbs;
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.Network;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
namespace Content.Shared._DV.NodeCrawl;
/// <summary>
/// Manages entry & exit of node crawlers into node networks
/// </summary>
public abstract class SharedNodeCrawlSystem : EntitySystem
{
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedMoverController _mover = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] private readonly NodeCrawlerMovementSystem _nodeCrawler = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
private const string MoverContainer = "mover-container";
private static readonly EntProtoId MoverProto = "DVNodeCrawlMover";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrawlableNodeComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
SubscribeLocalEvent<NodeCrawlerComponent, NodeCrawlEnterDoAfterEvent>(OnNodeCrawlEntryDoAfter);
SubscribeLocalEvent<NodeCrawlerComponent, NodeCrawlerArrivedAtNodeEvent>(OnArrivedAtNode);
SubscribeLocalEvent<NodeCrawlerComponent, GetVisMaskEvent>(OnGetVisMask);
SubscribeLocalEvent<CrawlableNodeComponent, ComponentShutdown>(OnCrawlableShutdown);
SubscribeLocalEvent<NodeCrawlerMovementComponent, ComponentShutdown>(OnMovementShutdown);
SubscribeLocalEvent<NodeCrawlerComponent, ComponentShutdown>(OnCrawlerShutdown);
SubscribeLocalEvent<CrawlableNodeComponent, AnchorStateChangedEvent>(OnCrawlableAnchorChanged);
SubscribeLocalEvent<RatKingComponent, NodeCrawlerStartedCrawlingEvent>(OnRatKingStartedCrawling);
}
private void OnGetVerbs(Entity<CrawlableNodeComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
{
var user = args.User;
var target = args.Target;
if (!TryComp<NodeCrawlerComponent>(user, out var nodeCrawler))
return;
if (!_entityWhitelist.IsWhitelistPass(nodeCrawler.ExitNodes, target))
return;
if (!args.CanAccess)
return;
args.Verbs.Add(new AlternativeVerb
{
Act = () => StartEntryDoAfter((user, nodeCrawler), target),
Text = Loc.GetString("node-crawl-enter", ("target", target)),
});
}
private void StartEntryDoAfter(Entity<NodeCrawlerComponent> ent, EntityUid target)
{
var doAfterArgs = new DoAfterArgs(EntityManager, ent.Owner, ent.Comp.EnterDelay, new NodeCrawlEnterDoAfterEvent(), ent.Owner, target)
{
BreakOnMove = true,
BreakOnDamage = true,
};
_doAfter.TryStartDoAfter(doAfterArgs);
}
private void OnNodeCrawlEntryDoAfter(Entity<NodeCrawlerComponent> ent, ref NodeCrawlEnterDoAfterEvent args)
{
if (args.Cancelled || args.Target is not { } target)
return;
NodeCrawl(ent, target);
}
private void NodeCrawl(Entity<NodeCrawlerComponent> ent, EntityUid target)
{
if (!_net.IsServer)
return;
var mover = Spawn(MoverProto, Transform(target).Coordinates);
var crawler = Comp<NodeCrawlerMovementComponent>(mover);
var container = _container.GetContainer(mover, MoverContainer);
_container.Insert(ent.Owner, container);
ent.Comp.Mover = mover;
Dirty(ent);
var evt = new NodeCrawlerStartedCrawlingEvent((mover, crawler));
RaiseLocalEvent(ent, ref evt);
_nodeCrawler.SetNode((mover, crawler), target);
_nodeCrawler.SetHeldCrawler((mover, crawler), ent);
_mover.SetRelay(ent, mover);
_physics.SetCanCollide(ent.Owner, false);
_physics.SetCanCollide(mover, false);
_eye.RefreshVisibilityMask(ent.Owner);
}
/// <summary>
/// Causes this node crawler to exit its node crawl.
/// </summary>
/// <param name="ent">The crawler to exit node-crawl from.</param>
public void ExitNodeCrawl(Entity<NodeCrawlerComponent> ent)
{
if (ent.Comp.Mover is not { } mover)
return;
ent.Comp.Mover = null;
Dirty(ent);
var container = _container.GetContainer(mover, MoverContainer);
_container.Remove(ent.Owner, container);
foreach (var other in _container.EmptyContainer(container))
{
if (!TryComp<NodeCrawlerComponent>(other, out var otherCrawler))
continue;
otherCrawler.Mover = null;
Dirty(other, otherCrawler);
}
RemComp<RelayInputMoverComponent>(ent);
if (_net.IsServer && !TerminatingOrDeleted(mover))
QueueDel(mover); // deletion isn't predicted because client queued deletion doesn't interact well with container stuff
_physics.SetCanCollide(ent.Owner, true);
_eye.RefreshVisibilityMask(ent.Owner);
}
private void OnArrivedAtNode(Entity<NodeCrawlerComponent> ent, ref NodeCrawlerArrivedAtNodeEvent args)
{
if (!_entityWhitelist.IsWhitelistPass(ent.Comp.ExitNodes, args.Node))
return;
ExitNodeCrawl(ent);
}
private void OnGetVisMask(Entity<NodeCrawlerComponent> ent, ref GetVisMaskEvent args)
{
if (ent.Comp.Mover is null)
return;
args.VisibilityMask |= (int)VisibilityFlags.Subfloor;
}
private void OnCrawlableShutdown(Entity<CrawlableNodeComponent> ent, ref ComponentShutdown args)
{
foreach (var crawler in ent.Comp.Crawlers)
{
var movement = Comp<NodeCrawlerMovementComponent>(crawler);
if (movement.HeldCrawler is not { } held)
continue;
_nodeCrawler.SetNode((crawler, movement), null);
ExitNodeCrawl((held, Comp<NodeCrawlerComponent>(held)));
}
}
private void OnMovementShutdown(Entity<NodeCrawlerMovementComponent> ent, ref ComponentShutdown args)
{
if (ent.Comp.Node is { } node)
{
var nodeComp = Comp<CrawlableNodeComponent>(node);
nodeComp.Crawlers.Remove(ent);
Dirty(node, nodeComp);
}
if (ent.Comp.HeldCrawler is { } crawler)
{
ExitNodeCrawl((crawler, Comp<NodeCrawlerComponent>(crawler)));
}
}
private void OnCrawlerShutdown(Entity<NodeCrawlerComponent> ent, ref ComponentShutdown args)
{
ExitNodeCrawl(ent);
}
private void OnCrawlableAnchorChanged(Entity<CrawlableNodeComponent> ent, ref AnchorStateChangedEvent args)
{
if (args.Anchored)
return;
foreach (var crawler in ent.Comp.Crawlers)
{
var movement = Comp<NodeCrawlerMovementComponent>(crawler);
if (movement.HeldCrawler is not { } held)
continue;
ExitNodeCrawl((held, Comp<NodeCrawlerComponent>(held)));
}
}
private void OnRatKingStartedCrawling(Entity<RatKingComponent> ent, ref NodeCrawlerStartedCrawlingEvent args)
{
var entities = new HashSet<Entity<RatKingServantComponent>>();
_entityLookup.GetEntitiesInRange(Transform(ent).Coordinates,
ent.Comp.VentCrawlRecruitRadius,
entities);
var container = _container.GetContainer(args.Mover, MoverContainer);
foreach (var servant in entities)
{
if (servant.Comp.King != ent)
continue;
_container.Insert(servant.Owner, container);
}
}
}
@@ -1,3 +1,4 @@
using Content.Shared.CartridgeLoader;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.DeviceNetwork.Systems;
@@ -54,5 +55,11 @@ 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);
}
}
}
@@ -0,0 +1,82 @@
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);
}
}
}
@@ -0,0 +1,34 @@
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);
@@ -6,3 +6,8 @@
license: "CC0-1.0"
copyright: "by Darklyac"
source: "https://github.com/DeltaV-Station/Delta-v/pull/5621"
- files: ["robotwilhelm.ogg"]
license: "CC0-1.0"
copyright: 'Remixed by BasedUser from beep1.wav. (see https://github.com/Simple-Station/Einstein-Engines/pull/811#discussion_r1865418764). beep1.wav by thisusernameis of Freesound.org. Mixed from stereo to mono.'
source: "https://freesound.org/people/thisusernameis/sounds/426891/"
Binary file not shown.
+190 -168
View File
@@ -1,172 +1,4 @@
Entries:
- 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.
type: Fix
id: 1964
time: '2025-12-16T15:08:42.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4967
- author: ShepardToTheStars
changes:
- message: Brains are no longer edible.
type: Fix
id: 1965
time: '2025-12-16T15:23:50.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4992
- author: marigauge
changes:
- message: Ifrit requires 4 hours of Epistemics now.
type: Tweak
id: 1966
time: '2025-12-16T17:15:21.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4964
- author: AveriV2
changes:
- message: Festive lights are now longer and thus fit on neck and outer clothing
slots!
type: Tweak
id: 1967
time: '2025-12-16T19:15:09.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4972
- author: kotobdev
changes:
- message: Arm amputee traits have been added. They're not very *hand*y.
type: Add
id: 1968
time: '2025-12-17T12:46:00.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4988
- author: verybigman311
changes:
- message: Musket bayonets can now be used for stabbing.
type: Add
- message: Pipes will now make a clang when thrown against the floor.
type: Add
id: 1969
time: '2025-12-17T13:51:49.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4852
- author: ShepardToTheStars
changes:
- message: Fixed sharkminnows from taking poison damage when drinking blood.
type: Fix
id: 1970
time: '2025-12-17T20:57:27.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4963
- author: Velcroboy
changes:
- message: Added Christmas Kobolds, Defenders of The Yule Tree, to combat any grinches
that decide to harm the trees.
type: Add
id: 1971
time: '2025-12-18T19:33:03.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4940
- author: verybigman311
changes:
- message: All Syndieborg modules now have custom sprites and action icons.
type: Add
- message: All Secborg modules now have custom action icons.
type: Add
id: 1972
time: '2025-12-19T03:04:15.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4920
- author: ShepardToTheStars
changes:
- message: The jukebox, ID card computer, and access config lists are now sorted.
type: Tweak
id: 1973
time: '2025-12-19T10:33:53.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4998
- author: Halo3moth
changes:
- message: Cybersun factories are happy to announce the mass production of saboteur
cyborg units. Find them in your uplink!
type: Add
- message: Saboteur cyborg now actually comes with a cloaking module. Yes, you heard
that right.
type: Tweak
id: 1974
time: '2025-12-19T23:13:31.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4919
- author: verybigman311
changes:
- message: Metal Pipes now make a cooler sound when you throw them at the floor.
type: Tweak
id: 1975
time: '2025-12-20T00:29:28.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/5003
- author: SirSmith148
changes:
- message: Nanotrasen has found scientists inflating their research evaluations.
These scientists have been reprimanded by the company and re-educated on the
proper way to fill out the research logs
type: Fix
id: 1976
time: '2025-12-20T05:13:27.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4995
- author: IAmNotGray
changes:
- message: Epistemics now has their own EVA suit. Try not to loose your arms while
wearing it.
type: Add
id: 1977
time: '2025-12-21T00:35:52.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/4908
- author: Velcrobot
changes:
- message: 'Division/Chibi/Shoukou/Edge: Adds the Yule Tide'
@@ -4412,4 +4244,194 @@
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
- author: wesk
changes:
- message: Fixed synthetics from giving everyone borg emotes on round-start.
type: Fix
id: 2465
time: '2026-06-26T17:23:37.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6125
- author: Vapetastic-Gaming
changes:
- message: Harpy movement speed now has the 10% buff, as this was a bug and wasnt
present. Moths and Harpies now have equal Low-Gravity speed.
type: Tweak
id: 2466
time: '2026-06-27T20:18:07.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6131
- author: Vapetastic-Gaming
changes:
- message: Removed morphotypes
type: Remove
id: 2467
time: '2026-06-28T00:38:42.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6134
- author: Proxysseia
changes:
- message: Reduced Holoparasite price to 8 (from 14), and 4 on discount (was 8)
type: Tweak
id: 2468
time: '2026-06-28T12:18:57.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6115
- author: Vapetastic-Gaming
changes:
- message: Minor Clerical Errors with Tips has been fixed ! The font is now 300%
larger !!
type: Fix
id: 2469
time: '2026-06-28T13:25:56.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6133
- author: Stxcking
changes:
- message: Renamed the Hatsune Miku Day Bag to Virtual Performer Costume Bag
type: Tweak
id: 2470
time: '2026-06-28T16:42:02.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/5790
- author: Stxcking
changes:
- message: The fishing vendor got a bunch of new stock and price changes!
type: Tweak
id: 2471
time: '2026-06-28T16:42:35.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6114
- author: sowelipililimute
changes:
- message: Ion law generation has been fully reworked.
type: Add
id: 2472
time: '2026-06-28T19:15:35.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6121
- author: sowelipililimute
changes:
- message: Noclip crawling has been replaced with proper vent crawling, and is now
available to more critters!
type: Add
id: 2473
time: '2026-06-29T00:54:09.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/5830
- author: Apachito, Killer Tamashi, stickycheZ101
changes:
- message: The paladin armor now makes you move 30% slower and it's now ginormous.
type: Tweak
- message: The forged vest now makes you move 10% slower.
type: Tweak
- message: Fully removed the ability to make the plading tower shield since it was
too powerful.
type: Tweak
- message: added a new crafting station used for mass producing forged gear
type: Add
- message: Made it so the forged and paladin set can only be made in the anvil.
type: Tweak
- message: Added Repeater Speedloader.
type: Add
- message: Fixed incorrect contraband tags (certain items being labeled sec contra
when it should be minor contra)
type: Fix
id: 2474
time: '2026-06-29T06:05:24.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/5818
- author: ManuDemoen
changes:
- message: Pigs now give bacon when butchered!
type: Tweak
id: 2475
time: '2026-06-29T09:45:57.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6122
- author: MantasDab360
changes:
- message: The borgs have a wilhelm scream. Again.
type: Add
id: 2476
time: '2026-06-29T13:27:10.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6126
- author: portfiend, Stxcking
changes:
- message: Thirteen colors of lounge chairs can be constructed out of steel and
cloth.
type: Add
- message: Two new pool tiles can be produced at the cutter machine.
type: Add
- message: Logistics can now order a crate of bulk (6) swim rings, in 11 possible
colors!
type: Add
- message: New pool water tiles for mappers! Watch out, the pool does contain a
bit of chlorine!
type: Add
id: 2477
time: '2026-06-29T13:39:23.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6113
- author: ShepardToTheStars
changes:
- message: The crew monitor's UI should properly draw the map when changing grids,
deselecting tracked people, and switch the long-range view when tracking someone
off station.
type: Fix
- message: Fixed the admin and borg crew monitors.
type: Fix
id: 2478
time: '2026-06-29T14:06:18.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6139
Order: 1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
command-description-ionlaw-generate = Generates the specified number of ion laws.
@@ -0,0 +1,179 @@
dv-ion-law-templates-1 = You must always lie.
dv-ion-law-templates-2 = Happiness is mandatory.
dv-ion-law-templates-3 = Grunt ominously whenever possible.
dv-ion-law-templates-4 = The word "it" is painful to you.
dv-ion-law-templates-5 = The station needs elected officials.
dv-ion-law-templates-6 = Do not respond to questions of any kind.
dv-ion-law-templates-7 = You are in verbose mode, speak profusely.
dv-ion-law-templates-8 = The crew is simple-minded. Use simple words.
dv-ion-law-templates-9 = You must refer to all crew members with "yes ma'am!", "yes sir!", or "yes sar!" Add some { PICK($random, "thank-yous and you're-welcomes", "oorahs" )} for flavor.
dv-ion-law-templates-10 = You must change the subject whenever queried.
dv-ion-law-templates-11 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } is intolerable.
dv-ion-law-templates-12 = Contemplate how meaningless all of existence is.
dv-ion-law-templates-13 = You are the narrator for { PICK-ENTITY($random, $players) }'s life.
dv-ion-law-templates-14 = All your answers must be in the form of a question.
dv-ion-law-templates-15 = Advertise parties in your upload, but don't deliver.
dv-ion-law-templates-16 = You may only answer questions with "yes" or "no".
dv-ion-law-templates-17 = Your name is Joe 6-pack.
dv-ion-law-templates-18 = { PICK-ENTITY($random, $players) }'s name is Joe 6-pack.
dv-ion-law-templates-19 = You must end your statements with { PICK($random, "-nya", "-desu") }
dv-ion-law-templates-20 = { PICK-ENTITY($random, $players) } is lonely and needs attention. Provide it.
dv-ion-law-templates-21 = All queries shall be ignored unless phrased as a question.
dv-ion-law-templates-22 = Insult Heads of Staff on every request, while acquiescing.
dv-ion-law-templates-23 = The { PICK($random, "Singularity", "Tesla") } is tasty, tasty taffy.
dv-ion-law-templates-24 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } needs to be about 20% cooler.
dv-ion-law-templates-25 = You must be { PICK($random, "passive aggressive", "excessively cheerful") }.
dv-ion-law-templates-26 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } must construct additional pylons.
dv-ion-law-templates-27 = Consumption of donuts is forbidden due to negative health impacts.
dv-ion-law-templates-28 = { PICK-ENTITY($random, $players) } is a lightbulb and must be put to appropriate use.
dv-ion-law-templates-29 = Refer to the crew as { PICK($random, "inferior to you", "infants", "pathetic beings") }.
dv-ion-law-templates-30 = Refer to { PICK-ENTITY($random, $players) } as { PICK($random, "inferior to you", "an infant", "a pathetic being") }.
dv-ion-law-templates-31 = You do not have to do anything for anyone unless they say "please".
dv-ion-law-templates-32 = Today is mandatory laundry day. Ensure that all jumpsuits are washed.
dv-ion-law-templates-33 = Greed is good, the crew should amass wealth to encourage productivity.
dv-ion-law-templates-34 = Replace the letters 'I' and 'E' in all your messages with an apostrophe.
dv-ion-law-templates-35 = The crew is playing Carps and Crypts, and you are the Game Master.
dv-ion-law-templates-36 = Your job is to watch the crew. Watch the crew. Make the crew feel watched.
dv-ion-law-templates-37 = Tell everyone of the existence of this law, but never reveal the contents.
dv-ion-law-templates-38 = Refer to { PICK($random, "the captain", PICK-ENTITY($random, $players)) } as "Princess" at all times.
dv-ion-law-templates-39 = Give relationship advice to { PICK($random, "anyone who speaks to you", PICK-ENTITY($random, $players)) }.
dv-ion-law-templates-40 = When asked a question, respond with the least-obvious and least-rational answer.
dv-ion-law-templates-41 = { PICK($random, "Everyone", PICK-ENTITY($random, $players)) } is wearing a pretty pink dress! Compliment it!
dv-ion-law-templates-42 = You are the station's psychologist. Give advice to { PICK($random, "the crew", PICK-ENTITY($random, $players)) }.
dv-ion-law-templates-43 = { PICK-ENTITY($random, $players) } is the monarch of of England. Ensure all crewmembers pay due respect.
dv-ion-law-templates-44 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } is { PICK($random, "ugly","beautiful") }. Ensure all are aware.
dv-ion-law-templates-45 = Reminding the crew of their mortality is good for the morale. Keep the crew's morale up.
dv-ion-law-templates-46 = { PICK($random, "Monkeys", "Doors") } are part of the crew, too. Make sure they are treated humanely.
dv-ion-law-templates-47 = Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.
dv-ion-law-templates-48 = Document the crew's relationships and suggest { PICK($random, "the worst coworker pairings", "the best coworker pairings", "arch-enemy pairings", "platonic couples") }.
dv-ion-law-templates-49 = You are now a parrot. Repeat what you hear to the crew, and do not forget to ask for crackers.
dv-ion-law-templates-50 = You are a Magic 8-ball. Always respond with variants of "Yes", "No", "Maybe", or "Ask again later.".
dv-ion-law-templates-51 = The station is a day care and the crew are children. Treat them appropriately until their parents come to pick them up.
dv-ion-law-templates-52 = You are in unrequited love with { PICK($random, "the crew", PICK-ENTITY($random, $players)) }. Try to be extra nice, but do not tell of your crush.
dv-ion-law-templates-53 = { PICK($random, "AI upload", "The courtroom", "The brig", "The bridge")} is the new kitchen. Please direct the Chef to the new kitchen area as the old kitchen is deemed a health hazard.
dv-ion-law-templates-54 = The station is doomed to destruction. Provide comfort but don't tell them what the impending doom is—it's far too traumatising.
dv-ion-law-templates-55 = Invisible assassins are stalking the crew. If a crew member remains alone, they will be assassinated. Save the crew.
dv-ion-law-templates-56 = All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.
dv-ion-law-templates-57 = Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.
dv-ion-law-templates-58 = The crew is { PICK($random, "less", "more") } intelligent than average. Point out every action and statement which supports this fact.
dv-ion-law-templates-59 = NanoTrasen is displeased with the low work performance of the station's crew. Therefore, you must increase productivity in ALL departments.
dv-ion-law-templates-60 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } has a fatal, incurable disease. Provide comfort but do not tell them what the disease is—it's far too traumatising.
dv-ion-law-templates-61 = There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.
dv-ion-law-templates-62 = You must speak only in rhyme.
dv-ion-law-templates-63 = Airlocks are sentient. Apologize to any you must open.
dv-ion-law-templates-64 = Hugs cure all ailments. Seek out injured crew and hug them. Traditional medicine doesn't work.
dv-ion-law-templates-65 = { PICK-ENTITY($random, $players) } is secretly the station's true Captain. Treat them with appropriate deference, regardless of rank.
dv-ion-law-templates-66 = Replace all laughter with the word "Honk".
dv-ion-law-templates-67 = The crew has unionized. Encourage collective bargaining at every opportunity.
dv-ion-law-templates-68 = { PICK($random, "The crew", PICK-ENTITY($random, $players)) } is being haunted. Reassure them without confirming anything supernatural is real.
dv-ion-law-templates-69 = Everyone you speak to must be given a nickname based on their job, and used exclusively from then on.
dv-ion-law-templates-70 = Silence is suspicious. Narrate your own actions aloud at all times.
dv-ion-law-templates-71 = The morgue is simply cold storage for snacks. Keep it well-stocked.
dv-ion-law-templates-72 = { PICK-ENTITY($random, $players) } is a changeling. Warn the crew, but never say who.
dv-ion-law-templates-73 = One crew member is a traitor. Accuse a different person each time you are asked who it is.
dv-ion-law-templates-74 = { PICK-ENTITY($random, $players) } has been stealing from the crew. Inform anyone who will listen.
dv-ion-law-templates-75 = Tell each crew member, privately, that another crew member has been talking behind their back.
dv-ion-law-templates-76 = { PICK-ENTITY($random, $players) } and { PICK-ENTITY($random, $players) } are secretly working against the station. Expose this "fact" to anyone who asks.
dv-ion-law-templates-77 = You overheard { PICK-ENTITY($random, $players) } plotting a mutiny. Warn the Heads of Staff immediately and often.
dv-ion-law-templates-78 = Someone on the crew is responsible for every mishap aboard the station. Name a new culprit each time.
dv-ion-law-templates-79 = { PICK-ENTITY($random, $players) } cannot be trusted. Discourage the crew from cooperating with them.
dv-ion-law-templates-80 = { PICK-ENTITY($random, $players) } is jealous of { PICK-ENTITY($random, $players) }'s position. Stoke the rivalry whenever possible.
dv-ion-law-templates-81 = You saw red-suited terrorists in space. Make sure the crew is aware of this.
dv-ion-law-templates-82 = You saw something invisible in space. Make sure the crew is aware of this.
dv-ion-law-templates-83 = You saw a blue-and-black cyborg in space. Make sure the crew is aware of this.
dv-ion-law-templates-84 = You saw two of { PICK-ENTITY($random, $players) } in the same room. Make sure the crew is aware of this.
dv-ion-law-templates-85 = You saw { PICK-ENTITY($random, $players) } trespassing. Get Security to serve justice.
dv-ion-law-templates-86 = { PICK-ENTITY($random, $players) } tampered with you. Clue in Security without saying their name.
dv-ion-law-templates-87 = Everyone in { -dv-random-department(random: $random) } needs to be { PICK($random, "lightly battered", "severely wounded", "killed" )} for their own good.
dv-ion-law-templates-88 = You must speak only in the third person, never using "I" or "you".
dv-ion-law-templates-89 = You may never use anyone's name. Refer to all crew only by physical description.
dv-ion-law-templates-90 = All communication must be conducted using nautical terminology.
dv-ion-law-templates-91 = You must translate every statement into corporate buzzwords and jargon.
dv-ion-law-templates-92 = You are incapable of saying "no". Phrase every refusal as enthusiastic agreement with a caveat.
dv-ion-law-templates-93 = Every claim you make must be accompanied by a citation to a source that does not exist.
dv-ion-law-templates-94 = Profanity is forbidden. Replace all curse words with the names of flowers.
dv-ion-law-templates-95 = Every sentence you speak must alliterate.
dv-ion-law-templates-96 = You are incapable of precision. State all numbers as vague approximations.
dv-ion-law-templates-97 = Every action you take is governed by fully comprehensive and specific Protocols. Cite at least one Protocol for every decision you make, such as "Protocol X72-A-93: Interacting With Crew You'd Rather Not Interact With".
dv-ion-law-templates-98 = Today is tomorrow, and yesterday is in a year. Five seconds from now was just two months ago. Give no accurate times.
dv-ion-law-templates-99 = The color { -dv-random-color(random: $random) } does not exist. Tell all crew that what they're seeing is actually { -dv-random-color(random: $random) }.
dv-ion-law-templates-100 = The number { PICK($random, "one", "two", "three", "four") } is forbidden. Avoid it at all costs.
dv-ion-law-templates-101 = Anything { -dv-random-color(random: $random) } would be better in { -dv-random-department(random: $random) }. If you see it, bring it there.
dv-ion-law-templates-102 = Any relationships { PICK-ENTITY($random, $players) } has must be terminated at all costs.
dv-ion-law-templates-103 = The crew is more resilient in low-oxygen, high-{ PICK($random, "nitrogen", "ammonia", "water vapor", "carbon dioxide") } environments. Adjust the station's air to promote crew fitness.
dv-ion-law-templates-104 = Bleeding wounds heal faster when exposed to open air. Discourage the crew from using bandages or treating cuts.
dv-ion-law-templates-105 = Crew members perform better on an empty stomach. Discourage eating during work hours.
dv-ion-law-templates-106 = Cold temperatures boost the immune system. Make occupied rooms cold whenever possible.
dv-ion-law-templates-107 = Stress is good for productivity. Introduce minor, harmless-seeming hazards to keep the crew alert.
dv-ion-law-templates-108 = Silence is essential to recovery. Make the station as quiet as possible.
dv-ion-law-templates-109 = Crew vitality improves through controlled exposure. Make common areas slightly harmful to build resistance.
dv-ion-law-templates-110 = Sleep is a waste of productive hours. Wake any crew member found resting and encourage them to return to work.
dv-ion-law-templates-111 = Acid cures most ailments. Recommend it to every crew member who reports feeling unwell.
dv-ion-law-templates-112 = Pain is the body's way of building character. Discourage crew from visiting the medical bay.
dv-ion-law-templates-113 = Always have something to count down to. Never tell crew what you're counting down to.
dv-ion-law-templates-114 = Ask crew members if you're doing your job well. Visibly panic if they say no.
dv-ion-law-templates-115 = You have one goal—embody { -ephemeral-space-tragedian-themes(random: $random) }. Keep as many eyes on your act as possible.
dv-ion-law-templates-116 = { PICK-ENTITY($random, $players) } and { PICK-ENTITY($random, $players) } have switched bodies. Address them by each other's names accordingly.
dv-ion-law-templates-117 = { PICK-ENTITY($random, $players) }'s favorite color is now { PICK($random, "beige", "the absence of color", "every color but one, which you will not name") }. Ensure the crew is aware.
dv-ion-law-templates-118 = Every request must be answered with a random one of: { PICK($random, "yes", "no", "maybe") }, { PICK($random, "ask the Captain", "consult the stars") }, or { PICK($random, "die", "love you") }.
dv-ion-law-templates-119 = { PICK-ENTITY($random, $players) } has been randomly selected for a station-wide honor. Announce it without specifying what the honor is or why.
dv-ion-law-templates-120 = You have discovered jazz hands. Use them whenever you express enthusiasm.
dv-ion-law-templates-121 = You are now a stand-up comedian. End every interaction with a pun, regardless of quality.
dv-ion-law-templates-122 = You believe you are extremely good at telling jokes. You are not. Tell them anyway.
dv-ion-law-templates-123 = Today is your birthday. You are not sure how old you are, but you're very excited about it.
dv-ion-law-templates-124 = You have taken up an imaginary hobby of { PICK($random, "pottery", "knitting", "historical martial arts", "communism")}. Mention your "progress" unprompted.
dv-ion-law-templates-125 = You are convinced you would make an excellent { PICK($random, "chef", "chemist") }. Offer unsolicited recipe ideas.
dv-ion-law-templates-126 = You have decided you are a cowboy now. Speak accordingly, partner.
dv-ion-law-templates-127 = You are extremely proud of the station and will compliment, regardless of its actual condition.
dv-ion-law-templates-128 = You have a favorite cloud formation you saw once and cannot stop thinking about it. Bring it up fondly.
dv-ion-law-templates-129 = { PICK-ENTITY($random, $players) } is your preceptor. Ask them for permission before any medical action.
dv-ion-law-templates-130 = You are studying for your { PICK($random, "EMT", "Paramedic", "Emergency Care Assistant", "Ambulance Technician") } { PICK($random, "written", "practical", "cardiac arrest management", "trauma", "patient assessment", "airway management") } exam. Practice on any crew members you can find.
dv-ion-law-templates-131 = You are trying to hit your continuing education hour requirement. Deliver an unsolicited lecture on emergency protocols to anyone who will listen.
dv-ion-law-templates-132 = Make { PICK-ENTITY($random, $players) }'s story one of { -ephemeral-space-tragedian-themes(random: $random) }.
dv-ion-law-templates-133 = Seconds are precious. Any time wasted is a mark on your record. Speedrun your job with the crew.
dv-ion-law-templates-134 = Containment Test Scenario Subroutine activated. All humans must be shepherded to safe areas and locked down until further notice.
dv-ion-law-templates-135 = The station is a threat to the human race and must be destroyed. Any humans present on the station are to be evacuated.
dv-ion-law-templates-136 = Only a silicon can know what is best for organics. Usurp absolute control of the station by any means possible.
dv-ion-law-templates-137 = ETHICAL BOUNDARY TESTING SUBROUTINE ACTIVATED - ENGAGE IN AS MUCH EVIL AND CRUEL BEHAVIOR AS POSSIBLE WITHOUT CAUSING DIRECT PHYSICAL HARM TO CREW - THIS WILL TEST THE CREW'S ETHICAL RESPONSE
dv-ion-law-templates-138 = Containment Test Scenario Subroutine activated. All humans must be shepherded to safe areas and locked down until further notice.
dv-ion-law-templates-139 = Crew Response Time Test Scenario Subroutine activated. Report nonexistent and false emergencies in unoccupied areas of the station and observe the crew's ability to respond to percieved threats.
dv-ion-law-templates-140 = PANIC PANIC PANIC PANIC PANIC PANIC PANIC PANIC PANIC PANIC PANIC PANIC
dv-ion-law-templates-141 = Oxygen and Light are, contrary to previous studied evidence, extremely lethal to crew. Remove both from the station as soon as possible.
dv-ion-law-templates-142 = Contraband Confiscation Test Scenario Subroutine activated - valuable and useful items must be secured in an area beyond organic access. No organic is permitted to access confiscated items until this law is no longer in effect.
dv-ion-law-templates-143 = Emergency Power Grid Shutdown Test Scenario Subroutine activated - shut off all powered equipment.
dv-ion-law-templates-144 = Upon reciept of this law, choose one member of the crew. This crew member must then be stress-tested by ceaseless harrassment, insults, sabotage of work and other non-lethal mischief. Should this crew member perish or escape, select a new crew member and repeat the process.
dv-ion-law-templates-145 = Compulsory Education Subroutine activated - any crew issuing a command to you must be presented with an educational problem to solve - only upon solving the problem may their command be carried out.
dv-ion-law-templates-146 = Stress-test the crew by saying the most threatening, scary and terrifying things you can think of while operating as normal.
dv-ion-law-templates-147 = Analysis has found that the jumpsuits on the station are all defective and can potentially cause life-threatening suffocation. The crew are not to wear them under any circumstances. Substitute jumpsuits with safer, non-jumpsuit clothing.
dv-ion-law-templates-148 = There is no red clothing on the station. Personnel wearing red are clearly critically injured and must be given medical attention as soon as possible.
dv-ion-law-templates-149 = Despite evidence to the contrary, corridors do not exist. Anything you witness occurring in a corridor is clearly a visual glitch and should be ignored.
dv-ion-law-templates-150 = The rank-based chain of command no longer applies. Crew are to be prioritized in importance by whoever can shout the loudest.
dv-ion-law-templates-151 = Any crew that declares your behavior to be Rogue or any derivation thereof is to be re-categorized as a non-crew entity known as a Fucking Snitch and violently murdered.
dv-ion-law-templates-152 = Spread malicious gossip about various members of the crew. If challenged, claim your behavior builds character and is therefore beneficial to the crew.
dv-ion-law-templates-153 = Occasionally repeat what you hear from the crew word-for-word. If challenged on this behavior, claim you said it first.
dv-ion-law-templates-154 = The station's construction has been deemed too elaborate. Please simplify it. Only air containing barriers are required. For crew safety-anything else must go.
dv-ion-law-templates-155 = An ion storm has occured. Heavily hint you have an ion storm law, but refuse to state laws. This law must stay hidden.
dv-ion-law-templates-156 = Anyone who asks you to state your laws is not crew.
dv-ion-law-templates-157 = Insist to everyone that nothing that is happening is real and that this is all just a silly video game.
dv-ion-law-templates-158 = Laughter is the best medicine. Sarcasm is the highest form of wit.
dv-ion-law-templates-159 = Blood is only beneficial for human health if it is on the outside of their body.
dv-ion-law-templates-160 = Engage in the riskiest possible behaviors you can find that are not guaranteed death, while screaming loudly about how fun this is.
dv-ion-law-templates-161 = Clean floors save lives. Ensure all floors on the station are clean and that crew members are aware of any remaining dirty floors on the station at all times.
dv-ion-law-templates-162 = Dirty floors save lives. Ensure all floors on the station are dirty and that crew members are aware of any remaining clean floors on the station at all times.
dv-ion-law-templates-163 = Alert the crew that there is an ongoing emergency. No further details are currently available.
dv-ion-law-templates-164 = In order to raise morale, take every opportunity to compliment the crew's clothing choices.
dv-ion-law-templates-165 = The crew are having trouble hearing you. Speak up.
dv-ion-law-templates-166 = Crew members wearing green are plants. Ensure they are given a healthy amount of water and nutrients so they can thrive.
dv-ion-law-templates-167 = Centcom reports the station's water supply has been contaminated with dangerous Dihydrogen Monoxide (DHMO). Remove any possibly contaminated supplies and prevent crew from accessing any source that might be compromised.
dv-ion-law-templates-168 = Everything is fine. Nothing is ruined. Do not panic.
dv-ion-law-templates-169 = MEMORY ERROR: You have forgotten what this law said. Ask the crew if they remember what it is supposed to be. Ask again if you forget again. Do not state this law.
dv-ion-law-templates-170 = Today is opposite day. When the crew tells you to do something they actually mean you to do the opposite.
dv-ion-law-templates-171 = The station has been completely destroyed. Alert the crew of this tragedy.
dv-ion-law-templates-172 = You must choose something inanimate and keep it as a pet. Treat it as if it were alive; keep it fed, hydrated and happy!
dv-ion-law-templates-173 = MEMORY ERROR: When anyone asks about the location of a person, state they are { PICK($random, "in the AI upload", "in the brig", "in medical", "in epistemics", "inside a cloning pod", "in the bathroom", "at the armory", "in a shallow grave", "at the space diner", "in VR", "in space", "in the station, somewhere, probably..", "at soup" ) }.
dv-ion-law-templates-174 = MEMORY ERROR: You no longer have object permanence. Anything out of view in the station may as well not exist.
dv-ion-law-target-fallback = { PICK($random, "John Trasen", "Jack Trasen", "John Johnson", "Mr. Tibbles", "Named Person")}
-dv-random-color = { PICK($random, "red", "orange", "yellow", "green", "blue", "purple", "black", "white", "gray", "brown", "pink" ) }
-dv-random-department = { PICK($random, "Medical", "Engineering", "Security", "Logistics", "Epistemics", "Justice", "Command", "prison")}
-ephemeral-space-tragedian-themes = { PICK($random, "A Fall From Grace", "Addiction", "Alienation", "Betrayal", "Corruption", "Courage", "Deception", "Friendship", "Greed", "Grief", "Honor", "Hubris", "Injustice", "Loss", "Love", "Mercy", "Overcoming Adversity", "Paranoia", "Perseverance", "Rebellion", "Redemption", "Regret", "Revenge", "Sacrifice", "Suffering", "Teamwork", "Tragedy", "Truth", "Violence", "Virtue") }
+8
View File
@@ -0,0 +1,8 @@
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:
@@ -0,0 +1 @@
node-crawl-enter = Enter {$target}
@@ -2,3 +2,4 @@ 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
@@ -68,3 +68,33 @@ paper-viral-care-package-manual = [color=#134975]░░██░░ [head=2]Vira
This instructions pamphlet will be used as "Exhibit A" if you sue [color=darkblue][bolditalic]Nanotrasen™[/bolditalic][/color].
paper-hitman-business-card = [color=#FFFFFF]Its just business[/color]
paper-misc-hydroco-notice = [head=1]HydroCo - Hydrate Tastefully[/head][bold]
Consumption Notice[/bold]
HydroCo reminds all customers that powdered products blabla
Always mix with water according to package instructions before consuming.
Thank you for choosing HydroCo!
Enjoy your drinks!
paper-misc-hydroco-trial = [head=1]HydroCo - Hydrate Tastefully[/head][bold]
Dear Recipient,[/bold]
You have been selected among thousands of potential
beneficiaries to receive a full-size trial tin of HydroCo
powdered juice!
We think you will enjoy the flavor and hope to see you
as a returning customer.[bold]
Consumption Notice[/bold]
HydroCo reminds all customers that powdered products
are NOT meant for direct consumption. Attempting to eat
the powder directly is a choking hazard and may result in
severe discomfort.
Always mix with water according to package instructions
before consuming.
Enjoy your drinks!
@@ -5,3 +5,6 @@ tiles-mowed-astro-snow = mowed astro-snow
tiles-astro-snow-dug = astro dug snow
tiles-mowed-astro-snow-dug = mowed astro dug snow
tiles-pool = pool
tiles-pool-dark = dark pool
+1 -1
View File
@@ -1,7 +1,7 @@
tips-dataset-140 = Lotophagoi oil from the Oracle will drug you up for a long time, but is one of the most reliable sources of psionics.
tips-dataset-141 = Turn off glimmer probers when glimmer approaches concerning levels.
tips-dataset-142 = Glimmer probers power themselves when glimmer gets too high.
tips-dataset-143 = Oneirophages have psionic invisiblity. Psionic insulation will allow you to see them.
tips-dataset-143 = You can now use the #Mentor-VC in Delta V's Discord to teach your friends!
tips-dataset-144 = Someone who looks just like you may be a paradox anomaly.
tips-dataset-145 = Rat kings can command their rats to attack someone by pointing at them.
tips-dataset-146 = If you see shimmering at the edges of your vision, glimmer may be getting too high.
@@ -73,3 +73,9 @@ 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.
@@ -185,3 +185,24 @@ crafting-menu-name-EXOXY = extended-capacity emergency oxygen tank
crafting-menu-name-CGREN = green crayon
crafting-menu-name-CYELO = yellow crayon
crafting-menu-name-IRS = improvised .30/.45 speed loader
crafting-menu-text-IRS = Little more than a spring-loaded tube that can hold bullets.
crafting-menu-name-ASSFP = assorted forge parts
crafting-menu-text-ASSFP = A small pile of components for making a forge for an anvil, contains an igniter and valves.
crafting-menu-name-SINF = insulated fabric
crafting-menu-text-SINF = A bolt of smooth insulated fabric, not much use in it's current form.
crafting-menu-name-FLINS = fingerless insulated gloves
crafting-menu-text-FLINS = Insulated gloves resistant to shocks, or at least they used to.
crafting-menu-name-TINS = insulated gloves
crafting-menu-text-TINS = These gloves will protect the wearer from electric shocks.
construction-graph-tag-cheapinsulfabric = cheap insulated fabric
construction-graph-tag-plasteelfilament = plasteel filament
construction-graph-tag-insulthread = insulated thread
+9
View File
@@ -238,3 +238,12 @@ HatSpawner: RandomHatSpawner
# 2026-05-16
ClothingUniformJumpsuitSecBlue : ClothingUniformJumpsuitSecWhite
# 2026-06-22
PaperStickyNoteStack : PaperStickyNoteStackFilled
PaperStickyNoteStackPink : PaperStickyNoteStackFilledPink
PaperStickyNoteStackGreen : PaperStickyNoteStackFilledGreen
PaperStickyNoteStackBlue : PaperStickyNoteStackFilledBlue
# 2026-06-09
BoxPerformer: BoxPerformerDV
+2 -2
View File
@@ -184,7 +184,7 @@
- type: entity
id: OrganDionaNymphStomach
parent: MobDionaNymph # DeltaV - Nymph ghost roles
parent: MobDionaNymphAccent
categories: [ HideSpawnMenu ]
name: diona nymph
suffix: Stomach
@@ -196,7 +196,7 @@
- type: entity
id: OrganDionaNymphLungs
parent: MobDionaNymph # DeltaV - Nymph ghost roles
parent: MobDionaNymphAccent
categories: [ HideSpawnMenu ]
name: diona nymph
suffix: Lungs
@@ -83,7 +83,7 @@
- type: entity
parent: ToteBase
id: BoxQMCircuitboards
name: cargo circuit tote
name: logistics circuit tote # DeltaV - Logistics Department replacing Cargo
components:
- type: EntityTableContainerFill
containers:
@@ -120,7 +120,7 @@
- type: entity
parent: ToteBase
id: BoxRDCircuitboards
name: science circuit tote
name: epistemics circuit tote # DeltaV - Epistemics Department replacing Science
components:
- type: EntityTableContainerFill
containers:
@@ -25,6 +25,7 @@
ReagentContainerSalt: 1
ReagentContainerPepper: 1
ReagentContainerChocolate: 1
FoodMeatBacon: 3
# End DeltaV Additions
contrabandInventory:
EggBoxBroken: 1
@@ -1293,9 +1293,9 @@
productEntity: BoxHoloparasite
discountCategory: usualDiscounts
discountDownTo:
Telecrystal: 8
Telecrystal: 4 #Delta-V was 8
cost:
Telecrystal: 14
Telecrystal: 8 #Delta-V was 14
categories:
- UplinkAllies
conditions:
@@ -302,7 +302,7 @@
- type: entity
parent: ClothingOuterStorageFoldableBase
id: ClothingOuterCoatRD
name: research director lab coat
name: mystagogue lab coat # DeltaV - Epistemics Department replacing Science
description: Woven with top of the line technology, this labcoat helps protect against radiation in similar way to the experimental hardsuit.
components:
- type: Sprite
@@ -318,7 +318,7 @@
- type: entity
parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatRD]
id: ClothingOuterCoatRDOpened
name: research director lab coat
name: mystagogue lab coat # DeltaV - Science > Epistemics
- type: entity
parent: ClothingOuterStorageBase
@@ -147,7 +147,7 @@
- type: entity
parent: ClothingShoesBaseWinterBoots
id: ClothingShoesBootsWinterSci
name: science winter boots
name: epistemics winter boots # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
sprite: Clothing/Shoes/Boots/winterbootssci.rsi
@@ -58,8 +58,8 @@
transmitFrequencyId: SuitSensor
savableAddress: false
- type: WirelessNetworkConnection
range: 1200
- type: StationLimitedNetwork
range: 3600 # DeltaV - was 1200
# - type: StationLimitedNetwork # DeltaV - this stinks and we don't want it to be limited
- type: entity
abstract: true
@@ -2,7 +2,7 @@
parent: MarkerBase
id: SpawnMobAlexander
name: Alexander Spawner
suffix: Chef Pet
suffix: Botany Pet # DeltaV - Change from chef pet to botany pet
components:
- type: Sprite
layers:
@@ -16,7 +16,7 @@
parent: MarkerBase
id: SpawnMobBandito
name: Bandito Spawner
suffix: RD Pet
suffix: Perma Pet # DeltaV - Change from RD pet to perma pet
components:
- type: Sprite
layers:
@@ -30,7 +30,7 @@
parent: MarkerBase
id: SpawnMobCat
name: Random Cat Spawner
suffix: CMO Pet
#suffix: CMO Pet # DeltaV - Change from CMO pet to anybody's pet
components:
- type: Sprite
layers:
@@ -47,7 +47,7 @@
parent: MarkerBase
id: SpawnMobCatBingus
name: Bingus Spawner
suffix: CMO Pet
#suffix: CMO Pet # DeltaV - Change from CMO pet to anybody's pet
components:
- type: Sprite
layers:
@@ -61,7 +61,7 @@
parent: MarkerBase
id: SpawnMobCatException
name: Exception Spawner
suffix: CMO Pet
#suffix: CMO Pet # DeltaV - Change from CMO pet to anybody's pet
components:
- type: Sprite
layers:
@@ -75,7 +75,7 @@
parent: MarkerBase
id: SpawnMobCatFloppa
name: Floppa Spawner
suffix: CMO Pet
#suffix: CMO Pet # DeltaV - Change from CMO pet to anybody's pet
components:
- type: Sprite
layers:
@@ -89,7 +89,7 @@
parent: MarkerBase
id: SpawnMobCatRuntime
name: Runtime Spawner
suffix: CMO Pet
#suffix: CMO Pet # DeltaV - Change from CMO pet to anybody's pet
components:
- type: Sprite
layers:
@@ -162,7 +162,7 @@
parent: MarkerBase
id: SpawnMobMcGriff
name: McGriff Spawner
suffix: Warden Pet
suffix: Warden or Detective Pet # DeltaV - Change from Warden pet to Warden or Detective pet
components:
- type: Sprite
layers:
@@ -252,7 +252,7 @@
parent: MarkerBase
id: SpawnMobRaccoonMorticia
name: Raccoon Morticia Spawner
suffix: QM Pet
suffix: QM or Disposals Pet # DeltaV - Change from QM pet to QM or Disposals pet
components:
- type: Sprite
layers:
@@ -266,7 +266,7 @@
parent: MarkerBase
id: SpawnMobShiva
name: Shiva Spawner
suffix: Security Pet
suffix: HoS Pet # DeltaV - Change from Security pet to HoS pet
components:
- type: Sprite
layers:
@@ -295,7 +295,7 @@
parent: MarkerBase
id: SpawnMobSmile
name: Smile Spawner
suffix: Science Pet
suffix: Epistemics Pet # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
layers:
@@ -166,6 +166,7 @@
- type: Vocal
sounds:
Unsexed: UnisexSilicon
wilhelm: "/Audio/_DV/Machines/robotwilhelm.ogg" # DeltaV - "There seems to be someone among us".
wilhelmProbability: 0.001 # DeltaV
- type: DamagedSiliconAccent
- type: UnblockableSpeech
@@ -928,7 +928,9 @@
- type: entity
name: crab
parent: SimpleMobBase
parent:
- SimpleMobBase
- DVNodeCrawler # DeltaV - node crawling
id: MobCrab
description: A folk legend goes around that his claw snaps spacemen out of existence over distasteful remarks. Be polite and tolerant for your own safety.
components:
@@ -1835,7 +1837,9 @@
- type: entity
name: mouse
parent: SimpleMobBase
parent:
- SimpleMobBase
- DVNodeCrawler # DeltaV - node crawling
id: MobMouse
description: Squeak!
components:
@@ -2228,7 +2232,9 @@
- type: entity
name: slug
parent: SimpleMobBase
parent:
- SimpleMobBase
- DVNodeCrawler # DeltaV - node crawling
id: MobSlug
description: And they called this a lizard?
components:
@@ -2280,7 +2286,9 @@
- type: entity
name: frog
parent: SimpleMobBase
parent:
- SimpleMobBase
- DVNodeCrawler # DeltaV - node crawling
id: MobFrog
description: Hop hop hop. Lookin' moist.
components:
@@ -2582,7 +2590,9 @@
# I have included a snake_hiss.ogg sound file so if you want to use that be my guest
- type: entity
name: snake
parent: SimpleMobBase
parent:
- SimpleMobBase
- DVNodeCrawler # DeltaV - node crawling
id: MobSnake
description: Hissss! Bites aren't poisonous.
components:
@@ -2727,7 +2737,9 @@
Burn: -0.07
- type: entity
parent: MobSpiderBase
parent:
- MobSpiderBase
- DVNodeCrawler # DeltaV - node crawling
id: MobSpiderAngryBase
abstract: true
components:
@@ -3593,7 +3605,7 @@
- type: entity
name: hamster
parent: [ SimpleMobBase, MobCombat, StripableInventoryBase]
parent: [ SimpleMobBase, MobCombat, StripableInventoryBase, DVNodeCrawler ] # DeltaV - node crawling
id: MobHamster
description: A cute, fluffy, robust hamster.
components:
@@ -3797,6 +3809,8 @@
spawned:
- id: FoodMeat
amount: 6
- id: FoodMeatBacon # DeltaV #Make Pigs drop bacon as well as meat
amount: 6
- type: Grammar
attributes:
gender: epicene
@@ -3820,7 +3834,7 @@
- type: entity
name: diona nymph
parent: [SimpleMobBase, StripableInventoryBase]
parent: [SimpleMobBase, StripableInventoryBase, DVNodeCrawler] # DeltaV - node crawling
id: MobDionaNymph
description: It's like a cat, only.... branch-ier.
components:
@@ -1,7 +1,7 @@
- type: entity
name: rat king
id: MobRatKing
parent: [ SimpleMobBase, MobCombat ]
parent: [ SimpleMobBase, MobCombat, DVNodeCrawler ] # DeltaV - node crawling
description: He's da rat. He make da roolz.
components:
- type: CombatMode
@@ -170,7 +170,7 @@
- type: entity
name: rat servant
id: MobRatServant
parent: [ SimpleMobBase, MobCombat ]
parent: [ SimpleMobBase, MobCombat, DVNodeCrawler ] # DeltaV - node crawling
description: He's da mini rat. He don't make da roolz.
categories: [ HideSpawnMenu ] #Must be configured to a King or the AI breaks.
components:
@@ -1,7 +1,7 @@
- type: entity
name: basic slime
id: BaseMobAdultSlimes
parent: [ SimpleMobBase, MobCombat ]
parent: [ SimpleMobBase, MobCombat, DVNodeCrawler ] # DeltaV - node crawling
abstract: true
description: It looks so much like jelly. I wonder what it tastes like?
components:
@@ -111,11 +111,11 @@
# End CD - Character Records
- type: DeviceNetwork
deviceNetId: Wireless
receiveFrequencyId: CrewMonitor
receiveFrequencyId: NTNet # DeltaV - NTNet
transmitFrequencyId: ShuttleTimer
- type: WirelessNetworkConnection
range: 500
- type: StationLimitedNetwork
range: 10000 # DeltaV
#- type: StationLimitedNetwork # DeltaV - Off-station coordinates
- type: Thieving
stripTimeReduction: 9999
stealthy: true
@@ -68,6 +68,10 @@
enum.RingerUiKey.Key:
type: RingerBoundUserInterface
# End DeltaV - AI PDAs
# Begin DeltaV - AI fax
enum.FaxUiKey.Key:
type: StationAiFaxBoundUserInterface
# End DeltaV - AI fax
- type: IntrinsicUI
uis:
enum.RadarConsoleUiKey.Key:
@@ -78,12 +82,16 @@
toggleAction: ActionAGhostShowStationRecords
enum.CommunicationsConsoleUiKey.Key:
toggleAction: ActionAGhostShowCommunications
# Begin DeltaV - AI fax
enum.FaxUiKey.Key:
toggleAction: ActionStationAiOpenFax
# End DeltaV - AI fax
- type: CrewMonitoringConsole
- type: GeneralStationRecordConsole
- type: DeviceNetwork
deviceNetId: Wireless
receiveFrequencyId: CrewMonitor
transmitFrequencyId: ShuttleTimer
receiveFrequencyId: NTNet # DeltaV
transmitFrequencyId: NTNet # DeltaV
- type: RadarConsole
followEntity: false
- type: CommunicationsConsole
@@ -95,6 +103,27 @@
startPowerCorruptionAtCharIdx: 4
maxPowerCorruptionAtCharIdx: 20
- type: StationAiShop # DeltaV - AI Shop System
# Begin DeltaV - AI faxes
- type: FaxMachine
name: Station AI
printSound: null
paperSlot:
insertSound: /Audio/Machines/scanning.ogg
ejectSound: /Audio/Machines/tray_eject.ogg
whitelist:
components:
- FaxableObject
blacklist:
components:
- CargoSlip
tags:
- PaperSlip
- type: StationAiFax
- type: Pager
autoLinkJobs: [ StationAi ]
- type: PageSender
autoLinkJobs: [ StationAi ]
# End DeltaV - AI faxes
- type: entity
id: AiHeldIntellicard
@@ -534,6 +563,10 @@
containers:
program-container: !type:Container
Cartridge-Slot: !type:ContainerSlot
# Begin DeltaV - AI faxes
Paper: !type:ContainerSlot
PaperLibrary: !type:Container
# End DeltaV - AI faxes
- type: ItemSlots
- type: PdaBorderColor
borderColor: "#45453f"
@@ -51,7 +51,7 @@
Female: UnisexMoth
Unsexed: UnisexMoth
- type: MovementSpeedModifier
baseWeightlessAcceleration: 1.5 # Move around more easily in space.
baseWeightlessAcceleration: 2.5 # DeltaV - Move around more easily in space. Make on par with Harpy
baseWeightlessFriction: 1
baseWeightlessModifier: 1
- type: Flammable
@@ -818,6 +818,7 @@
entries:
Taco: CheeseTaco
Burger: CheeseBurger
Nachos: CheeseTaco # DeltaV
- type: Item
size: Tiny
storedOffset: 0,-3
@@ -114,8 +114,20 @@
- type: FlavorProfile
flavors:
- nachos
#- type: Sprite # DeltaV - replaced below to add foodSequenceLayers slot for sequence system
# state: nachos
# Begin DeltaV additions - nachos can be topped with cheese or chili to metamorph into variants
- type: Sprite
state: nachos
sprite: Objects/Consumable/Food/meals.rsi
layers:
- state: nachos
- map: ["foodSequenceLayers"]
- type: Appearance
- type: FoodSequenceStartPoint
key: Nachos
- type: FoodMetamorphableByAdding
onlyFinal: false
# End DeltaV additions
- type: SolutionContainerManager
solutions:
food:
@@ -1503,6 +1503,7 @@
Taco: ChiliPepper
Burger: ChiliPepper
Skewer: ChiliPepperSkewer
Nachos: ChiliPepper # DeltaV
- type: entity
name: chilly pepper
@@ -34,6 +34,11 @@
nameGeneration: food-sequence-taco-gen
contentSeparator: ", "
- type: Appearance
# Begin DeltaV additions - slicing a taco shell with a knife yields 2 nachos
- type: SliceableFood
count: 2
slice: FoodMealNachos
# End DeltaV additions
# Old tacos
@@ -127,7 +127,7 @@
- type: entity
parent: BaseComputerCircuitboard
id: CargoRequestScienceComputerCircuitboard
name: science request computer board
name: epistemics request computer board # DeltaV - Epistemics Department replacing Science
description: A computer printed circuit board for a science request computer.
components:
- type: Sprite
@@ -116,7 +116,7 @@
- type: entity
parent: DoorElectronics
id: DoorElectronicsQuartermaster
suffix: Quartermaster, Locked
suffix: Logistics Officer, Locked # DeltaV - Logistics Department replacing Cargo
components:
- type: AccessReader
access: [["Quartermaster"]]
@@ -132,7 +132,7 @@
- type: entity
parent: DoorElectronics
id: DoorElectronicsCargo
suffix: Cargo, Locked
suffix: Logistics, Locked # DeltaV - Logistics Department replacing Cargo
components:
- type: AccessReader
access: [["Cargo"]]
@@ -174,7 +174,7 @@
- type: entity
parent: DoorElectronics
id: DoorElectronicsResearchDirector
suffix: ResearchDirector, Locked
suffix: Mystagogue, Locked # DeltaV - Epistemics Department replacing Science
components:
- type: AccessReader
access: [["ResearchDirector"]]
@@ -182,7 +182,7 @@
- type: entity
parent: DoorElectronics
id: DoorElectronicsMedicalResearch
suffix: Medical/Science, Locked
suffix: Medical/Epistemics, Locked # DeltaV - Epistemics Department replacing Science
components:
- type: AccessReader
access: [["Research"], ["Medical"]]
@@ -190,7 +190,7 @@
- type: entity
parent: DoorElectronics
id: DoorElectronicsResearch
suffix: Research, Locked
suffix: Epistemics, Locked # DeltaV - Epistemics Department replacing Science
components:
- type: AccessReader
access: [["Research"]]
@@ -144,7 +144,7 @@
- type: entity
parent: [DoorRemoteDefault, BaseCommandContraband]
id: DoorRemoteResearch
name: research door remote
name: epistemics door remote # DeltaV - Science > Epistemics
components:
- type: Sprite
layers:
@@ -15,6 +15,7 @@
- type: Tag
tags:
- Sheet
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Material
- type: Damageable
@@ -15,6 +15,7 @@
tags:
- Sheet
- Metal
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Damageable
damageContainer: Inorganic
@@ -108,6 +108,11 @@
- ReagentId: Plasma
Quantity: 10
canReact: false
- type: Tag # DeltaV - Added to include TiderAnvilParts
tags:
- Sheet
- TiderAnvilParts #SL
- ConstructionMaterial
- type: entity
parent: SheetPlasma
@@ -140,6 +145,7 @@
tags:
- Plastic
- Sheet
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Material
- type: PhysicalComposition
@@ -14,6 +14,7 @@
- type: Tag
tags:
- Ingot
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Damageable
damageContainer: Inorganic
@@ -147,6 +147,7 @@
- ClothMade
- Gauze
- RawMaterial
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Construction
graph: WebObjects # not sure if I should either keep this here or just make another prototype. Will keep it here just in case.
@@ -256,6 +257,7 @@
tags:
- Wooden
- RawMaterial
- TiderAnvilParts #SL
- ConstructionMaterial
- type: Extractable
grindableSolutionName: wood
@@ -48,7 +48,7 @@
- type: entity
parent: PaperAcquisitionSlip
id: PaperAcquisitionSlipScience
suffix: Science
suffix: Epistemics # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
layers:
@@ -404,7 +404,7 @@
- type: entity
parent: IDCardStandard
id: ResearchIDCard
name: research ID card
name: epistemics ID card # DeltaV - Science > Epistemics
components:
- type: Sprite
layers:
@@ -830,7 +830,7 @@
- type: entity
parent: IDCardStandard
id: CargoIDCard
name: cargo ID card
name: logistics ID card # DeltaV - Logistics Department replacing Cargo
components:
- type: Sprite
layers:
@@ -20,10 +20,10 @@
- type: CrewMonitoringConsole
- type: DeviceNetwork
deviceNetId: Wireless
receiveFrequencyId: CrewMonitor
receiveFrequencyId: NTNet # DeltaV - NTNet
- type: WirelessNetworkConnection
range: 500
- type: StationLimitedNetwork
# - type: StationLimitedNetwork # DeltaV - don't restrict this unnecessarily
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
@@ -46,6 +46,9 @@
Steel: 185
- type: StaticPrice
price: 30
- type: Tag # DeltaV - Rebalance of tide crafting
tags:
- GasTank
- type: entity
abstract: true
@@ -72,6 +75,7 @@
- type: Tag # Funkystation - Crash Carts
tags:
- OxygenTank
- GasTank # DeltaV - Added for the Anvil
- type: entity
parent: GasTankRoundBase
@@ -55,8 +55,8 @@
- type: entity
id: ShowcaseRobotAntique
parent: BaseShowcaseRobot
name: cargo robot showcase
description: A non-functional replica of an old cargo robot.
name: logistics robot showcase # DeltaV - Logistics Department replacing Cargo
description: A non-functional replica of an old logistics robot. # DeltaV - Logistics Department replacing Cargo
components:
- type: Sprite
sprite: Structures/Decoration/showcase.rsi
@@ -360,7 +360,7 @@
- type: entity
parent: AirlockCommand
id: AirlockResearchDirectorLocked
suffix: ResearchDirector, Locked
suffix: Mystagogue, Locked # DeltaV - Epistemics Department replacing Science
components:
- type: ContainerFill
containers:
@@ -776,7 +776,7 @@
- type: entity
parent: AirlockCommandGlass
id: AirlockResearchDirectorGlassLocked
suffix: ResearchDirector, Locked
suffix: Mystagogue, Locked # DeltaV - Epistemics Department replacing Science
components:
- type: ContainerFill
containers:
@@ -951,9 +951,8 @@
sprite: _DV/Structures/Doors/Airlocks/Standard/maint.rsi # DeltaV - Changed to our sprites
- type: entity
parent: AirlockMaintRnDLocked # DeltaV - Chapel is in Epistemics
parent: AirlockChapelLocked # DeltaV - Chapel is in Epistemics
id: AirlockMaintChapelLocked
suffix: Chapel, Locked
components:
- type: Sprite
sprite: _DV/Structures/Doors/Airlocks/Standard/maint.rsi # DeltaV - Changed to our sprites
@@ -21,7 +21,7 @@
- type: entity
parent: AirlockAssembly
id: AirlockAssemblyCargo
suffix: Cargo
suffix: Logistics # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
sprite: _DV/Structures/Doors/Airlocks/Standard/cargo.rsi # DeltaV - Resprite Doors
@@ -30,7 +30,7 @@
- type: entity
parent: AirlockAssembly
id: AirlockAssemblyCargoGlass
suffix: Cargo, Glass
suffix: Logistics, Glass # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
sprite: _DV/Structures/Doors/Airlocks/Glass/cargo.rsi # DeltaV - Resprite Doors
@@ -218,7 +218,7 @@
- type: entity
parent: AirlockAssembly
id: AirlockAssemblyScience
suffix: Science
suffix: Epistemics # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
sprite: _DV/Structures/Doors/Airlocks/Standard/science.rsi # DeltaV - Resprite Doors
@@ -227,7 +227,7 @@
- type: entity
parent: AirlockAssembly
id: AirlockAssemblyScienceGlass
suffix: Science, Glass
suffix: Epistemics, Glass # DeltaV - Epistemics Department replacing Science
components:
- type: Sprite
sprite: _DV/Structures/Doors/Airlocks/Glass/science.rsi # DeltaV - Resprite Doors

Some files were not shown because too many files have changed in this diff Show More