mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e7895cf57 | ||
|
|
162db0b954 | ||
|
|
196419daf0 | ||
|
|
ee01a470cf | ||
|
|
c0b78a5065 | ||
|
|
3b27cb1630 | ||
|
|
fc77ebae4d | ||
|
|
00d1991154 | ||
|
|
f20d8d9f7f | ||
|
|
ae4a864ad0 | ||
|
|
dbe955ca17 | ||
|
|
19ebd10ad1 | ||
|
|
dcd0fb693c | ||
|
|
9a6cfb2bfb | ||
|
|
35fa80f737 | ||
|
|
3b7304d092 | ||
|
|
da7468e79e | ||
|
|
609bf88d9d | ||
|
|
b71e0a2edf | ||
|
|
aacfbd17f8 | ||
|
|
6fda61e9cb | ||
|
|
e47ee2601b | ||
|
|
064fd77a11 | ||
|
|
2f5f2fd491 | ||
|
|
018d65d99b | ||
|
|
ca91333906 | ||
|
|
2b1d0bb364 | ||
|
|
a34e8bff90 | ||
|
|
b67c029061 | ||
|
|
72f6bff008 | ||
|
|
baf36b659d | ||
|
|
0488fcbf8c | ||
|
|
edc2b87fa1 | ||
|
|
3885aee7cf | ||
|
|
859f0418ac | ||
|
|
d1385ab95b | ||
|
|
1e45f2da21 | ||
|
|
64c50527c3 | ||
|
|
d7ef3b4a06 | ||
|
|
23ec100ed8 | ||
|
|
d62ca61fb4 | ||
|
|
229a857b7e | ||
|
|
dd9c88ca4b | ||
|
|
aaad3b5c00 | ||
|
|
addfc247bf | ||
|
|
6affab00ea | ||
|
|
7f85b2a196 | ||
|
|
a7d25c697f | ||
|
|
61884f5fe1 | ||
|
|
ebcd3b23f9 | ||
|
|
1a23a02b5e | ||
|
|
f6572840b1 | ||
|
|
8680f5c4fd | ||
|
|
670b6d0858 | ||
|
|
94004e3ce0 | ||
|
|
fd09b8f68e | ||
|
|
d8edffcbb2 | ||
|
|
8316434da2 | ||
|
|
6b03d1cc80 | ||
|
|
2f68c7329f | ||
|
|
e8138473d1 | ||
|
|
a114cf88d0 | ||
|
|
ff14cb6846 | ||
|
|
e639f423f4 | ||
|
|
57e5564ff8 | ||
|
|
48921f9af9 | ||
|
|
8bd44c5e7b | ||
|
|
303e1f4563 | ||
|
|
8003517bbc | ||
|
|
6486b49bf3 | ||
|
|
aabf5ac1bb | ||
|
|
b4daabc55f | ||
|
|
338ac84008 | ||
|
|
61e8547327 | ||
|
|
730cba2ee1 | ||
|
|
6089c30923 | ||
|
|
4e6eee4854 | ||
|
|
71302e037c | ||
|
|
fd0a91733f | ||
|
|
e7c0c98258 | ||
|
|
df99ef84f5 | ||
|
|
7932eddb48 | ||
|
|
72efa8c9d3 | ||
|
|
cdc8aeb3a6 | ||
|
|
9e047522e9 | ||
|
|
2e7134f028 | ||
|
|
8d772a67fa | ||
|
|
310a2c6575 | ||
|
|
7b6a41b28f | ||
|
|
5ddec75e0b | ||
|
|
3f29960640 | ||
|
|
fe940f0289 | ||
|
|
70c0494061 | ||
|
|
4b0b6ff16e | ||
|
|
e4826f3b8a | ||
|
|
a8796530e6 | ||
|
|
1afb572366 | ||
|
|
08e4ee47c3 | ||
|
|
097f165961 | ||
|
|
a8cd6be09c | ||
|
|
3698acd6d2 | ||
|
|
b35b68b8aa | ||
|
|
f585bcd233 | ||
|
|
e2f79f2236 | ||
|
|
f4c6352dea | ||
|
|
54514adf64 | ||
|
|
75d30a857a | ||
|
|
519ca118c4 | ||
|
|
ca1f82d430 | ||
|
|
d62a4911e7 | ||
|
|
2984ecbb8c | ||
|
|
304c99dc2e | ||
|
|
8030fe1b2a | ||
|
|
795772ecc2 | ||
|
|
37327a2c70 | ||
|
|
f3361860d2 | ||
|
|
86a9eff122 | ||
|
|
2ff9e1d56a | ||
|
|
48f1cff536 | ||
|
|
a86501907f | ||
|
|
4bdcb0d556 | ||
|
|
1351e0fb67 | ||
|
|
f8e59733dd | ||
|
|
4750e885b2 | ||
|
|
a7d34aacda | ||
|
|
91494215ca | ||
|
|
5e50b6969c | ||
|
|
4538b4ded1 | ||
|
|
cdbf170b37 | ||
|
|
daf03f45ed | ||
|
|
987678965f | ||
|
|
663952f2fb | ||
|
|
46a37b1caf | ||
|
|
bcc50db33b | ||
|
|
30cfa646e4 | ||
|
|
91ff29416b | ||
|
|
74d687ee4e | ||
|
|
eef2b2215d | ||
|
|
b74569d20b |
@@ -2,6 +2,7 @@ using Content.Client.Cargo.UI;
|
|||||||
using Content.Shared.Cargo.Components;
|
using Content.Shared.Cargo.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
|
using Content.Shared._DV.Cargo.Components; // DeltaV: Bounty claim messages
|
||||||
|
|
||||||
namespace Content.Client.Cargo.BUI;
|
namespace Content.Client.Cargo.BUI;
|
||||||
|
|
||||||
@@ -30,6 +31,18 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
SendMessage(new BountySkipMessage(id));
|
SendMessage(new BountySkipMessage(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DeltaV: bounty claim stuff begins
|
||||||
|
_menu.OnClaimButtonPressed += id =>
|
||||||
|
{
|
||||||
|
SendMessage(new BountyClaimedMessage(id));
|
||||||
|
};
|
||||||
|
|
||||||
|
_menu.OnStatusOptionSelected += (id, status) =>
|
||||||
|
{
|
||||||
|
SendMessage(new BountySetStatusMessage(id, status));
|
||||||
|
};
|
||||||
|
// DeltaV: bounty claim stuff ends
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState message)
|
protected override void UpdateState(BoundUserInterfaceState message)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||||
<RichTextLabel Name="RewardLabel"/>
|
<RichTextLabel Name="RewardLabel"/>
|
||||||
<RichTextLabel Name="ManifestLabel"/>
|
<RichTextLabel Name="ManifestLabel"/>
|
||||||
|
<RichTextLabel Name="ClaimedBylabel"/> <!-- DeltaV bounty claim -->
|
||||||
|
<RichTextLabel Name="StatusLabel"/> <!-- DeltaV bounty claim -->
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Control MinWidth="10"/>
|
<Control MinWidth="10"/>
|
||||||
<BoxContainer Orientation="Vertical" MinWidth="120">
|
<BoxContainer Orientation="Vertical" MinWidth="120">
|
||||||
@@ -17,14 +19,22 @@
|
|||||||
<Button Name="PrintButton"
|
<Button Name="PrintButton"
|
||||||
Text="{Loc 'bounty-console-label-button-text'}"
|
Text="{Loc 'bounty-console-label-button-text'}"
|
||||||
HorizontalExpand="False"
|
HorizontalExpand="False"
|
||||||
HorizontalAlignment="Right"
|
StyleClasses="OpenBoth"/>
|
||||||
StyleClasses="OpenRight"/>
|
|
||||||
<Button Name="SkipButton"
|
<Button Name="SkipButton"
|
||||||
Text="{Loc 'bounty-console-skip-button-text'}"
|
Text="{Loc 'bounty-console-skip-button-text'}"
|
||||||
HorizontalExpand="False"
|
HorizontalExpand="True"
|
||||||
HorizontalAlignment="Right"
|
|
||||||
StyleClasses="OpenLeft"/>
|
StyleClasses="OpenLeft"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" MinWidth="120"> <!-- Begin DeltaV bounty claim content -->
|
||||||
|
<Button Name="ClaimButton"
|
||||||
|
Text= "{Loc 'bounty-console-claim-button-text'}"
|
||||||
|
HorizontalExpand="False"
|
||||||
|
StyleClasses="OpenRight"/>
|
||||||
|
<OptionButton Name="BountyStatusSelector"
|
||||||
|
Access="Public"
|
||||||
|
StyleClasses="OpenBoth"
|
||||||
|
HorizontalExpand="True"/>
|
||||||
|
</BoxContainer> <!-- End DeltaV content-->
|
||||||
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public sealed partial class BountyEntry : BoxContainer
|
|||||||
|
|
||||||
public Action? OnLabelButtonPressed;
|
public Action? OnLabelButtonPressed;
|
||||||
public Action? OnSkipButtonPressed;
|
public Action? OnSkipButtonPressed;
|
||||||
|
public Action? OnClaimButtonPressed; // DeltaV
|
||||||
|
public Action? OnStatusOptionSelected; // DeltaV
|
||||||
|
|
||||||
public TimeSpan EndTime;
|
public TimeSpan EndTime;
|
||||||
public TimeSpan UntilNextSkip;
|
public TimeSpan UntilNextSkip;
|
||||||
@@ -45,6 +47,20 @@ public sealed partial class BountyEntry : BoxContainer
|
|||||||
|
|
||||||
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
||||||
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
||||||
|
|
||||||
|
// Begin DeltaV bounty claiming
|
||||||
|
ClaimButton.OnPressed += _ => OnClaimButtonPressed?.Invoke();
|
||||||
|
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Undelivered)}"), 0);
|
||||||
|
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Waiting)}"), 1);
|
||||||
|
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.OnShuttle)}"), 2);
|
||||||
|
|
||||||
|
BountyStatusSelector.Select((int) bounty.Status);
|
||||||
|
BountyStatusSelector.ToolTip = Loc.GetString($"bounty-console-status-tooltip-{bounty.Status.ToString()}");
|
||||||
|
|
||||||
|
var claimedByText = string.IsNullOrEmpty(bounty.ClaimedBy) ? Loc.GetString("bounty-console-claimed-by-none") : bounty.ClaimedBy;
|
||||||
|
ClaimedBylabel.SetMarkup(Loc.GetString("bounty-console-claimed-by", ("claimant", claimedByText)));
|
||||||
|
StatusLabel.SetMarkup(Loc.GetString($"bounty-console-formatted-status-{bounty.Status.ToString()}"));
|
||||||
|
// End DeltaV bounty claiming
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSkipButton(float deltaSeconds)
|
private void UpdateSkipButton(float deltaSeconds)
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<!--DeltaV - SetSize was 550, now 750 to accomodate bounty claim UI -->
|
||||||
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'bounty-console-menu-title'}"
|
Title="{Loc 'bounty-console-menu-title'}"
|
||||||
SetSize="550 420"
|
SetSize="750 420"
|
||||||
MinSize="400 350">
|
MinSize="400 350">
|
||||||
<BoxContainer Orientation="Vertical"
|
<BoxContainer Orientation="Vertical"
|
||||||
VerticalExpand="True"
|
VerticalExpand="True"
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||||||
{
|
{
|
||||||
public Action<string>? OnLabelButtonPressed;
|
public Action<string>? OnLabelButtonPressed;
|
||||||
public Action<string>? OnSkipButtonPressed;
|
public Action<string>? OnSkipButtonPressed;
|
||||||
|
public Action<string>? OnClaimButtonPressed; // DeltaV
|
||||||
|
public Action<string, int>? OnStatusOptionSelected; // DeltaV
|
||||||
|
|
||||||
public CargoBountyMenu()
|
public CargoBountyMenu()
|
||||||
{
|
{
|
||||||
@@ -31,6 +33,8 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||||||
var entry = new BountyEntry(b, untilNextSkip);
|
var entry = new BountyEntry(b, untilNextSkip);
|
||||||
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
||||||
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
||||||
|
entry.OnClaimButtonPressed += () => OnClaimButtonPressed?.Invoke(b.Id); // DeltaV
|
||||||
|
entry.BountyStatusSelector.OnItemSelected += args => OnStatusOptionSelected?.Invoke(b.Id, args.Id); // DeltaV
|
||||||
|
|
||||||
BountyEntriesContainer.AddChild(entry);
|
BountyEntriesContainer.AddChild(entry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ namespace Content.Client.Input
|
|||||||
common.AddFunction(ContentKeyFunctions.RotateStoredItem);
|
common.AddFunction(ContentKeyFunctions.RotateStoredItem);
|
||||||
common.AddFunction(ContentKeyFunctions.SaveItemLocation);
|
common.AddFunction(ContentKeyFunctions.SaveItemLocation);
|
||||||
common.AddFunction(ContentKeyFunctions.Point);
|
common.AddFunction(ContentKeyFunctions.Point);
|
||||||
|
// Floofstation section
|
||||||
|
common.AddFunction(ContentKeyFunctions.OfferItem);
|
||||||
|
// Floofstation section end
|
||||||
common.AddFunction(ContentKeyFunctions.ZoomOut);
|
common.AddFunction(ContentKeyFunctions.ZoomOut);
|
||||||
common.AddFunction(ContentKeyFunctions.ZoomIn);
|
common.AddFunction(ContentKeyFunctions.ZoomIn);
|
||||||
common.AddFunction(ContentKeyFunctions.ResetZoom);
|
common.AddFunction(ContentKeyFunctions.ResetZoom);
|
||||||
|
|||||||
@@ -75,9 +75,11 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
|
|||||||
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
||||||
name = Loc.GetString("navmap-unknown-entity");
|
name = Loc.GetString("navmap-unknown-entity");
|
||||||
|
|
||||||
|
var pos = _xform.ToMapCoordinates(blip.Coordinates); // DeltaV - map-coordinates
|
||||||
|
|
||||||
var message = name + "\n" + Loc.GetString("navmap-location",
|
var message = name + "\n" + Loc.GetString("navmap-location",
|
||||||
("x", MathF.Round(blip.Coordinates.X)),
|
("x", MathF.Round(pos.X)), // DeltaV - map-coordinates
|
||||||
("y", MathF.Round(blip.Coordinates.Y)));
|
("y", MathF.Round(pos.Y))); // DeltaV - map-coordinates
|
||||||
|
|
||||||
_trackedEntityLabel.Text = message;
|
_trackedEntityLabel.Text = message;
|
||||||
_trackedEntityPanel.Visible = true;
|
_trackedEntityPanel.Visible = true;
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
AddButton(ContentKeyFunctions.MovePulledObject);
|
AddButton(ContentKeyFunctions.MovePulledObject);
|
||||||
AddButton(ContentKeyFunctions.ReleasePulledObject);
|
AddButton(ContentKeyFunctions.ReleasePulledObject);
|
||||||
AddButton(ContentKeyFunctions.Point);
|
AddButton(ContentKeyFunctions.Point);
|
||||||
|
AddButton(ContentKeyFunctions.OfferItem); // Floofstation
|
||||||
AddButton(ContentKeyFunctions.RotateObjectClockwise);
|
AddButton(ContentKeyFunctions.RotateObjectClockwise);
|
||||||
AddButton(ContentKeyFunctions.RotateObjectCounterclockwise);
|
AddButton(ContentKeyFunctions.RotateObjectCounterclockwise);
|
||||||
AddButton(ContentKeyFunctions.FlipObject);
|
AddButton(ContentKeyFunctions.FlipObject);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Shared.StatusIcon;
|
|||||||
using Content.Shared.StatusIcon.Components;
|
using Content.Shared.StatusIcon.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Player; // DeltaV
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using static Robust.Shared.Maths.Color;
|
using static Robust.Shared.Maths.Color;
|
||||||
@@ -22,6 +23,7 @@ namespace Content.Client.Overlays;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class EntityHealthBarOverlay : Overlay
|
public sealed class EntityHealthBarOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _player = default!; // DeltaV
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly IPrototypeManager _prototype;
|
private readonly IPrototypeManager _prototype;
|
||||||
|
|
||||||
@@ -40,6 +42,8 @@ public sealed class EntityHealthBarOverlay : Overlay
|
|||||||
|
|
||||||
public EntityHealthBarOverlay(IEntityManager entManager, IPrototypeManager prototype)
|
public EntityHealthBarOverlay(IEntityManager entManager, IPrototypeManager prototype)
|
||||||
{
|
{
|
||||||
|
IoCManager.InjectDependencies(this); // DeltaV
|
||||||
|
|
||||||
_entManager = entManager;
|
_entManager = entManager;
|
||||||
_prototype = prototype;
|
_prototype = prototype;
|
||||||
_transform = _entManager.System<SharedTransformSystem>();
|
_transform = _entManager.System<SharedTransformSystem>();
|
||||||
@@ -69,6 +73,11 @@ public sealed class EntityHealthBarOverlay : Overlay
|
|||||||
out var damageableComponent,
|
out var damageableComponent,
|
||||||
out var spriteComponent))
|
out var spriteComponent))
|
||||||
{
|
{
|
||||||
|
// BEGIN DeltaV - You can't see your own bar :godo:
|
||||||
|
if (_player.LocalEntity is { } player && player.Id == uid.Id)
|
||||||
|
continue;
|
||||||
|
// END DeltaV
|
||||||
|
|
||||||
if (statusIcon != null && !_statusIconSystem.IsVisible((uid, _entManager.GetComponent<MetaDataComponent>(uid)), statusIcon))
|
if (statusIcon != null && !_statusIconSystem.IsVisible((uid, _entManager.GetComponent<MetaDataComponent>(uid)), statusIcon))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -85,41 +85,40 @@ public sealed class SalvageMagnetBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
case AsteroidOffering asteroid:
|
case AsteroidOffering asteroid:
|
||||||
option.Title = Loc.GetString($"dungeon-config-proto-{asteroid.Id}");
|
option.Title = Loc.GetString($"dungeon-config-proto-{asteroid.Id}");
|
||||||
break; // DeltaV: Skip ores since they aren't used with custom generation
|
var layerKeys = asteroid.MarkerLayers.Keys.ToList();
|
||||||
// var layerKeys = asteroid.MarkerLayers.Keys.ToList();
|
layerKeys.Sort();
|
||||||
// layerKeys.Sort();
|
|
||||||
//
|
foreach (var resource in layerKeys)
|
||||||
// foreach (var resource in layerKeys)
|
{
|
||||||
// {
|
var count = asteroid.MarkerLayers[resource];
|
||||||
// var count = asteroid.MarkerLayers[resource];
|
|
||||||
//
|
var container = new BoxContainer
|
||||||
// var container = new BoxContainer
|
{
|
||||||
// {
|
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||||
// Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
HorizontalExpand = true,
|
||||||
// HorizontalExpand = true,
|
};
|
||||||
// };
|
|
||||||
//
|
var resourceLabel = new Label
|
||||||
// var resourceLabel = new Label
|
{
|
||||||
// {
|
Text = Loc.GetString("salvage-magnet-resources",
|
||||||
// Text = Loc.GetString("salvage-magnet-resources",
|
("resource", resource)),
|
||||||
// ("resource", resource)),
|
HorizontalAlignment = Control.HAlignment.Left,
|
||||||
// HorizontalAlignment = Control.HAlignment.Left,
|
};
|
||||||
// };
|
|
||||||
//
|
var countLabel = new Label
|
||||||
// var countLabel = new Label
|
{
|
||||||
// {
|
Text = Loc.GetString("salvage-magnet-resources-count", ("count", count)),
|
||||||
// Text = Loc.GetString("salvage-magnet-resources-count", ("count", count)),
|
HorizontalAlignment = Control.HAlignment.Right,
|
||||||
// HorizontalAlignment = Control.HAlignment.Right,
|
HorizontalExpand = true,
|
||||||
// HorizontalExpand = true,
|
};
|
||||||
// };
|
|
||||||
//
|
container.AddChild(resourceLabel);
|
||||||
// container.AddChild(resourceLabel);
|
container.AddChild(countLabel);
|
||||||
// container.AddChild(countLabel);
|
|
||||||
//
|
option.AddContent(container);
|
||||||
// option.AddContent(container);
|
}
|
||||||
// }
|
|
||||||
//
|
break;
|
||||||
// break;
|
|
||||||
case DebrisOffering debris:
|
case DebrisOffering debris:
|
||||||
option.Title = Loc.GetString($"salvage-magnet-debris-{debris.Id}");
|
option.Title = Loc.GetString($"salvage-magnet-debris-{debris.Id}");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Shared._DV.Forensics;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client._DV.Forensics;
|
||||||
|
|
||||||
|
public sealed class DVItemSlotVisualsSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
|
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||||
|
|
||||||
|
private static readonly ResPath TextureRoot = new("/Textures");
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DVItemSlotVisualsComponent, EntInsertedIntoContainerMessage>(OnInsertedIntoContainer);
|
||||||
|
SubscribeLocalEvent<DVItemSlotVisualsComponent, EntRemovedFromContainerMessage>(OnRemovedFromContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshVisuals(Entity<DVItemSlotVisualsComponent> ent)
|
||||||
|
{
|
||||||
|
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||||
|
if (slot.ContainedEntity is { } contained)
|
||||||
|
{
|
||||||
|
_sprite.CopySprite(contained, ent.Owner);
|
||||||
|
_sprite.AddLayer(ent.Owner, ent.Comp.FilledSprite);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sprite = Comp<SpriteComponent>(ent);
|
||||||
|
var count = sprite.AllLayers.Count();
|
||||||
|
for (var i = count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
_sprite.RemoveLayer((ent, sprite), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent.Comp.UnfilledSprite is not SpriteSpecifier.Rsi rsi)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{ToPrettyString(ent)} has an unfilled sprite that's not an RSI");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_resourceCache.TryGetResource<RSIResource>(TextureRoot / rsi.RsiPath, out var res))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{ToPrettyString(ent)} has invalid RSI: {TextureRoot / rsi.RsiPath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_sprite.SetBaseRsi(ent.Owner, res.RSI);
|
||||||
|
_sprite.AddLayer(ent.Owner, ent.Comp.UnfilledSprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInsertedIntoContainer(Entity<DVItemSlotVisualsComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||||
|
{
|
||||||
|
if (args.Container.ID != ent.Comp.ItemSlot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RefreshVisuals(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemovedFromContainer(Entity<DVItemSlotVisualsComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||||
|
{
|
||||||
|
if (args.Container.ID != ent.Comp.ItemSlot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RefreshVisuals(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
using Content.Shared._DV.Silicons;
|
|
||||||
|
|
||||||
namespace Content.Client._DV.Silicons;
|
|
||||||
|
|
||||||
public sealed class SiliconEmpSystem : SharedSiliconEmpSystem;
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Input;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client._Floof.OfferItem;
|
||||||
|
|
||||||
|
public sealed class OfferItemIndicatorsOverlay : Overlay
|
||||||
|
{
|
||||||
|
private readonly IInputManager _inputManager;
|
||||||
|
private readonly IEntityManager _entMan;
|
||||||
|
private readonly IEyeManager _eye;
|
||||||
|
private readonly OfferItemSystem _offer;
|
||||||
|
|
||||||
|
private readonly Texture _sight;
|
||||||
|
|
||||||
|
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||||
|
|
||||||
|
private readonly Color _mainColor = Color.White.WithAlpha(0.3f);
|
||||||
|
private readonly Color _strokeColor = Color.Black.WithAlpha(0.5f);
|
||||||
|
private readonly float _scale = 0.6f; // 1 is a little big
|
||||||
|
|
||||||
|
public OfferItemIndicatorsOverlay(IInputManager input, IEntityManager entMan,
|
||||||
|
IEyeManager eye, OfferItemSystem offerSys)
|
||||||
|
{
|
||||||
|
_inputManager = input;
|
||||||
|
_entMan = entMan;
|
||||||
|
_eye = eye;
|
||||||
|
_offer = offerSys;
|
||||||
|
|
||||||
|
var spriteSys = _entMan.EntitySysManager.GetEntitySystem<SpriteSystem>();
|
||||||
|
_sight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new("/Textures/_Floof/Interface/Misc/give_item.rsi"), "give_item"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
if (!_offer.IsInOfferMode())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return base.BeforeDraw(in args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
var mouseScreenPosition = _inputManager.MouseScreenPosition;
|
||||||
|
var mousePosMap = _eye.PixelToMap(mouseScreenPosition);
|
||||||
|
if (mousePosMap.MapId != args.MapId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
var mousePos = mouseScreenPosition.Position;
|
||||||
|
var uiScale = (args.ViewportControl as Control)?.UIScale ?? 1f;
|
||||||
|
var limitedScale = uiScale > 1.25f ? 1.25f : uiScale;
|
||||||
|
|
||||||
|
DrawSight(_sight, args.ScreenHandle, mousePos, limitedScale * _scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSight(Texture sight, DrawingHandleScreen screen, Vector2 centerPos, float scale)
|
||||||
|
{
|
||||||
|
var sightSize = sight.Size * scale;
|
||||||
|
var expandedSize = sightSize + new Vector2(7f, 7f);
|
||||||
|
|
||||||
|
screen.DrawTextureRect(sight,
|
||||||
|
UIBox2.FromDimensions(centerPos - sightSize * 0.5f, sightSize), _strokeColor);
|
||||||
|
screen.DrawTextureRect(sight,
|
||||||
|
UIBox2.FromDimensions(centerPos - expandedSize * 0.5f, expandedSize), _mainColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using Content.Shared._Floof.OfferItem;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Input;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
|
||||||
|
namespace Content.Client._Floof.OfferItem;
|
||||||
|
|
||||||
|
public sealed class OfferItemSystem : SharedOfferItemSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||||
|
[Dependency] private readonly IEyeManager _eye = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_overlayManager.AddOverlay(new OfferItemIndicatorsOverlay(
|
||||||
|
_inputManager,
|
||||||
|
EntityManager,
|
||||||
|
_eye,
|
||||||
|
this));
|
||||||
|
}
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
_overlayManager.RemoveOverlay<OfferItemIndicatorsOverlay>();
|
||||||
|
base.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInOfferMode()
|
||||||
|
{
|
||||||
|
var entity = _playerManager.LocalEntity;
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return IsInOfferMode(entity.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Access.Systems; // DeltaV
|
||||||
using Content.Server.Cargo.Components;
|
using Content.Server.Cargo.Components;
|
||||||
using Content.Server.NameIdentifier;
|
using Content.Server.NameIdentifier;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
@@ -20,6 +21,7 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Shared._DV.Cargo.Components; // DeltaV: Bounty claim messages
|
||||||
|
|
||||||
namespace Content.Server.Cargo.Systems;
|
namespace Content.Server.Cargo.Systems;
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ public sealed partial class CargoSystem
|
|||||||
[Dependency] private readonly ContainerSystem _container = default!;
|
[Dependency] private readonly ContainerSystem _container = default!;
|
||||||
[Dependency] private readonly NameIdentifierSystem _nameIdentifier = default!;
|
[Dependency] private readonly NameIdentifierSystem _nameIdentifier = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSys = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelistSys = default!;
|
||||||
|
[Dependency] private readonly IdCardSystem _idCard = default!; // DeltaV
|
||||||
|
|
||||||
private static readonly ProtoId<NameIdentifierGroupPrototype> BountyNameIdentifierGroup = "Bounty";
|
private static readonly ProtoId<NameIdentifierGroupPrototype> BountyNameIdentifierGroup = "Bounty";
|
||||||
|
|
||||||
@@ -40,6 +43,8 @@ public sealed partial class CargoSystem
|
|||||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BoundUIOpenedEvent>(OnBountyConsoleOpened);
|
SubscribeLocalEvent<CargoBountyConsoleComponent, BoundUIOpenedEvent>(OnBountyConsoleOpened);
|
||||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyPrintLabelMessage>(OnPrintLabelMessage);
|
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyPrintLabelMessage>(OnPrintLabelMessage);
|
||||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySkipMessage>(OnSkipBountyMessage);
|
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySkipMessage>(OnSkipBountyMessage);
|
||||||
|
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyClaimedMessage>(OnBountyClaimedMessage); // DeltaV
|
||||||
|
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySetStatusMessage>(OnSetBountyStatusMessage); // DeltaV
|
||||||
SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice);
|
SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice);
|
||||||
SubscribeLocalEvent<EntitySoldEvent>(OnSold);
|
SubscribeLocalEvent<EntitySoldEvent>(OnSold);
|
||||||
SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit);
|
||||||
@@ -111,6 +116,72 @@ public sealed partial class CargoSystem
|
|||||||
_audio.PlayPvs(component.SkipSound, uid);
|
_audio.PlayPvs(component.SkipSound, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin DeltaV bounty claim system
|
||||||
|
private void OnSetBountyStatusMessage(Entity<CargoBountyConsoleComponent> ent, ref BountySetStatusMessage args)
|
||||||
|
{
|
||||||
|
if (_station.GetOwningStation(ent.Owner) is not { } station || !TryComp<StationCargoBountyDatabaseComponent>(station, out var bountyDbComp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = 0; i < bountyDbComp.Bounties.Count; i++)
|
||||||
|
{
|
||||||
|
var bounty = bountyDbComp.Bounties[i];
|
||||||
|
|
||||||
|
if (bounty.Id != args.BountyId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var newData = new CargoBountyData
|
||||||
|
{
|
||||||
|
Id = bounty.Id,
|
||||||
|
Bounty = bounty.Bounty,
|
||||||
|
ClaimedBy = bounty.ClaimedBy,
|
||||||
|
Status = (CargoBountyStatus)args.Status,
|
||||||
|
};
|
||||||
|
|
||||||
|
bountyDbComp.Bounties[i] = newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
var untilNextSkip = bountyDbComp.NextSkipTime - Timing.CurTime;
|
||||||
|
_uiSystem.SetUiState(ent.Owner, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDbComp.Bounties, bountyDbComp.History, untilNextSkip));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBountyClaimedMessage(Entity<CargoBountyConsoleComponent> ent, ref BountyClaimedMessage args)
|
||||||
|
{
|
||||||
|
if (_station.GetOwningStation(ent.Owner) is not { } station || !TryComp<StationCargoBountyDatabaseComponent>(station, out var bountyDbComp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = 0; i < bountyDbComp.Bounties.Count; i++)
|
||||||
|
{
|
||||||
|
var bounty = bountyDbComp.Bounties[i];
|
||||||
|
|
||||||
|
if (bounty.Id != args.BountyId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string name;
|
||||||
|
if (_idCard.TryFindIdCard(args.Actor, out var idCard) && idCard.Comp.FullName != null)
|
||||||
|
{
|
||||||
|
name = idCard.Comp.FullName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = Loc.GetString("bounty-console-claimed-by-unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
var newData = new CargoBountyData
|
||||||
|
{
|
||||||
|
Id = bounty.Id,
|
||||||
|
Bounty = bounty.Bounty,
|
||||||
|
ClaimedBy = name.Equals(bounty.ClaimedBy) ? string.Empty : name,
|
||||||
|
Status = bounty.Status,
|
||||||
|
};
|
||||||
|
|
||||||
|
bountyDbComp.Bounties[i] = newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
var untilNextSkip = bountyDbComp.NextSkipTime - Timing.CurTime;
|
||||||
|
_uiSystem.SetUiState(ent.Owner, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDbComp.Bounties, bountyDbComp.History, untilNextSkip));
|
||||||
|
}
|
||||||
|
// End DeltaV bounty claim system
|
||||||
|
|
||||||
public void SetupBountyLabel(EntityUid uid, EntityUid stationId, CargoBountyData bounty, PaperComponent? paper = null, CargoBountyLabelComponent? label = null)
|
public void SetupBountyLabel(EntityUid uid, EntityUid stationId, CargoBountyData bounty, PaperComponent? paper = null, CargoBountyLabelComponent? label = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref paper, ref label) || !_protoMan.Resolve<CargoBountyPrototype>(bounty.Bounty, out var prototype))
|
if (!Resolve(uid, ref paper, ref label) || !_protoMan.Resolve<CargoBountyPrototype>(bounty.Bounty, out var prototype))
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Explosion.EntitySystems;
|
||||||
using Content.Shared.Damage; // DeltaV - EMP damage
|
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Radio;
|
using Content.Server.Radio;
|
||||||
using Content.Server.SurveillanceCamera;
|
using Content.Server.SurveillanceCamera;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ using Robust.Shared.Timing;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.EntityEffects.Effects.Solution;
|
using Content.Shared.EntityEffects.Effects.Solution;
|
||||||
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
||||||
|
using Content.Server.Body.Components; // Delta V
|
||||||
|
|
||||||
namespace Content.Server.Fluids.EntitySystems;
|
namespace Content.Server.Fluids.EntitySystems;
|
||||||
|
|
||||||
@@ -267,7 +268,8 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) || bloodSolution.AvailableVolume <= 0)
|
if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) || bloodSolution.AvailableVolume <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var blockIngestion = _internals.AreInternalsWorking(entity);
|
var blockIngestion = _internals.AreInternalsWorking(entity)
|
||||||
|
|| !HasComp<RespiratorComponent>(entity); // Starlight - Shadekin does not breathe and "AreInternalsWorking" does not check for that
|
||||||
|
|
||||||
var cloneSolution = solution.Clone();
|
var cloneSolution = solution.Clone();
|
||||||
var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate);
|
var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using Content.Shared.Zombies;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq; // DeltaV
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
@@ -126,15 +127,21 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
|||||||
|
|
||||||
|
|
||||||
// BEGIN DeltaV - Change mode to survival if zombies die
|
// BEGIN DeltaV - Change mode to survival if zombies die
|
||||||
var infectedPercent = GetInfectedFraction(false);
|
var anyInitialInfectedAlive = EntityQuery<InitialInfectedComponent, MobStateComponent>(false)
|
||||||
if (Math.Round(infectedPercent, 0) == 0) // All zombies defeated
|
.Any(x => x.Item2.CurrentState != MobState.Dead);
|
||||||
|
var anyLivingZombies = EntityQuery<ZombieComponent, MobStateComponent>(false)
|
||||||
|
.Any(x => x.Item2.CurrentState != MobState.Dead);
|
||||||
|
var anyPendingZombies = EntityQuery<PendingZombieComponent>(false).Any();
|
||||||
|
|
||||||
|
// All II turned/dead, all entities that have turned are dead, and there are no more pending zombies
|
||||||
|
if (!anyInitialInfectedAlive && !anyLivingZombies && !anyPendingZombies)
|
||||||
{
|
{
|
||||||
_roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior, zombieRuleComponent.ZombieShuttleDelay);
|
_roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior, zombieRuleComponent.ZombieShuttleDelay);
|
||||||
zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future
|
zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future
|
||||||
}
|
}
|
||||||
// END DeltaV
|
// END DeltaV
|
||||||
|
|
||||||
if (infectedPercent > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested()) // DeltaV - Move GetInfectedFraction to var
|
if (GetInfectedFraction(false) > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested())
|
||||||
{
|
{
|
||||||
foreach (var station in _station.GetStations())
|
foreach (var station in _station.GetStations())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Content.Server.Mobs; // Starlight
|
||||||
|
|
||||||
namespace Content.Server.Ghost
|
namespace Content.Server.Ghost
|
||||||
{
|
{
|
||||||
@@ -619,7 +620,15 @@ namespace Content.Server.Ghost
|
|||||||
_damageable.GetTotalDamage((playerEntity.Value, damageable));
|
_damageable.GetTotalDamage((playerEntity.Value, damageable));
|
||||||
}
|
}
|
||||||
|
|
||||||
DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
|
// Starlight - Start
|
||||||
|
//DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
|
||||||
|
|
||||||
|
var damageType = _prototypeManager.Index(AsphyxiationDamageType);
|
||||||
|
if (TryComp<DeathgaspComponent>(playerEntity, out var deathgasp))
|
||||||
|
damageType = _prototypeManager.Index(deathgasp.DamageType);
|
||||||
|
|
||||||
|
DamageSpecifier damage = new(damageType, dealtDamage);
|
||||||
|
// Starlight - End
|
||||||
|
|
||||||
_damageable.ChangeDamage(playerEntity.Value, damage, true);
|
_damageable.ChangeDamage(playerEntity.Value, damage, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Shared.Chat.Prototypes;
|
using Content.Shared.Chat.Prototypes; // Starlight
|
||||||
|
using Content.Shared.Damage.Prototypes; // Starlight
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Mobs;
|
namespace Content.Server.Mobs;
|
||||||
@@ -21,4 +23,10 @@ public sealed partial class DeathgaspComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool NeedsCritical = true;
|
public bool NeedsCritical = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starlight - The damage that is taken when succumbing
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<DamageTypePrototype> DamageType = "Asphyxiation";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,13 @@ public sealed class PseudoItemSystem : SharedPseudoItemSystem
|
|||||||
|
|
||||||
protected override void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component, GettingPickedUpAttemptEvent args)
|
protected override void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component, GettingPickedUpAttemptEvent args)
|
||||||
{
|
{
|
||||||
|
// Floof - changed this a bit to actually start a do-after
|
||||||
// Try to pick the entity up instead first
|
// Try to pick the entity up instead first
|
||||||
if (args.User != args.Item && _carrying.TryCarry(args.User, uid))
|
if (args.User != args.Item
|
||||||
|
&& TryComp<CarriableComponent>(uid, out var carriable)
|
||||||
|
&& _carrying.CanCarry(args.User, (uid, carriable)))
|
||||||
{
|
{
|
||||||
|
_carrying.StartCarryDoAfter(args.User, (uid, carriable));
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,20 +209,24 @@ namespace Content.Server.Psionics.Glimmer
|
|||||||
|
|
||||||
private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component, DestructionEventArgs args)
|
private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component, DestructionEventArgs args)
|
||||||
{
|
{
|
||||||
Spawn("MaterialBluespace1", Transform(uid).Coordinates);
|
var proberCoords = Transform(uid).Coordinates;
|
||||||
|
|
||||||
var tier = _glimmerSystem.GetGlimmerTier();
|
var tier = _glimmerSystem.GetGlimmerTier();
|
||||||
if (tier < GlimmerTier.High)
|
if (tier < GlimmerTier.High)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var totalIntensity = (float) (_glimmerSystem.Glimmer * 2);
|
var explosionMultiplier = 2;
|
||||||
var slope = (float) (11 - _glimmerSystem.Glimmer / 100);
|
if (_glimmerSystem.GetGlimmerTier() == GlimmerTier.Critical) // YOU DONE FUCKED UP
|
||||||
var maxIntensity = 20;
|
explosionMultiplier = 3;
|
||||||
|
|
||||||
var removed = (float) _glimmerSystem.Glimmer * _random.NextFloat(0.06f, 0.08f);
|
var totalIntensity = (float)(_glimmerSystem.Glimmer * explosionMultiplier);
|
||||||
_glimmerSystem.Glimmer -= (int) removed;
|
var slope = (float)(11 - _glimmerSystem.Glimmer / 100);
|
||||||
|
var maxIntensity = 75; // Same as syndicate bomb
|
||||||
|
|
||||||
|
var removed = _glimmerSystem.Glimmer * _random.NextFloat(0.06f, 0.08f);
|
||||||
|
_glimmerSystem.Glimmer -= (int)removed;
|
||||||
BeamRandomNearProber(uid, _glimmerSystem.Glimmer / 350, _glimmerSystem.Glimmer / 50);
|
BeamRandomNearProber(uid, _glimmerSystem.Glimmer / 350, _glimmerSystem.Glimmer / 50);
|
||||||
_explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity);
|
_explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity, addLog: true);
|
||||||
|
Spawn("MaterialBluespace1", proberCoords); // Congrats on your bluespace!
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent component, UnanchorAttemptEvent args)
|
private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent component, UnanchorAttemptEvent args)
|
||||||
@@ -230,7 +234,7 @@ namespace Content.Server.Psionics.Glimmer
|
|||||||
if (component.Locked)
|
if (component.Locked)
|
||||||
{
|
{
|
||||||
_sharedAudioSystem.PlayPvs(component.ShockNoises, args.User);
|
_sharedAudioSystem.PlayPvs(component.ShockNoises, args.User);
|
||||||
_electrocutionSystem.TryDoElectrocution(args.User, null, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false);
|
_electrocutionSystem.TryDoElectrocution(args.User, uid, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false);
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,8 @@ public sealed class OracleSystem : EntitySystem
|
|||||||
|
|
||||||
while (i != 0)
|
while (i != 0)
|
||||||
{
|
{
|
||||||
Spawn("MaterialBluespace1", Transform(user).Coordinates);
|
var entityToSpawn = _random.Next(0, 2) == 0 ? "MaterialBluespace1" : "CrystalNormality";
|
||||||
|
Spawn(entityToSpawn, Transform(user).Coordinates);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,7 @@ public sealed partial class CosmicFinaleComponent : Component
|
|||||||
{ "Blunt", 2.25},
|
{ "Blunt", 2.25},
|
||||||
{ "Cold", 2.25},
|
{ "Cold", 2.25},
|
||||||
{ "Radiation", 2.25},
|
{ "Radiation", 2.25},
|
||||||
{ "Asphyxiation", 2.25},
|
{ "Asphyxiation", 2.25}
|
||||||
{ "Ion", 2.25}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public sealed partial class CosmicCultSystem : SharedCosmicCultSystem
|
|||||||
if (!EntityIsCultist(args.Equipee))
|
if (!EntityIsCultist(args.Equipee))
|
||||||
{
|
{
|
||||||
_statusEffects.TryAddStatusEffect<CosmicEntropyDebuffComponent>(args.Equipee, EntropicDegen, TimeSpan.FromDays(1), true); // TimeSpan.MaxValue causes a crash here, so we use FromDays(1) instead.
|
_statusEffects.TryAddStatusEffect<CosmicEntropyDebuffComponent>(args.Equipee, EntropicDegen, TimeSpan.FromDays(1), true); // TimeSpan.MaxValue causes a crash here, so we use FromDays(1) instead.
|
||||||
if (TryComp<CosmicEntropyDebuffComponent>(args.Equipee, out var comp)) comp.Degen = new(){DamageDict = new(){{"Cold", 0.5}, {"Asphyxiation", 1.5}, {"Ion", 1.5}}};
|
if (TryComp<CosmicEntropyDebuffComponent>(args.Equipee, out var comp)) comp.Degen = new(){DamageDict = new(){{"Cold", 0.5}, {"Asphyxiation", 1.5}}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ public sealed partial class CosmicCultSystem : SharedCosmicCultSystem
|
|||||||
if (!EntityIsCultist(args.User))
|
if (!EntityIsCultist(args.User))
|
||||||
{
|
{
|
||||||
_statusEffects.TryAddStatusEffect<CosmicEntropyDebuffComponent>(args.User, EntropicDegen, TimeSpan.FromDays(1), true);
|
_statusEffects.TryAddStatusEffect<CosmicEntropyDebuffComponent>(args.User, EntropicDegen, TimeSpan.FromDays(1), true);
|
||||||
if (TryComp<CosmicEntropyDebuffComponent>(args.User, out var comp)) comp.Degen = new(){DamageDict = new(){{"Cold", 0.5}, {"Asphyxiation", 1.5}, {"Ion", 1.5}}};
|
if (TryComp<CosmicEntropyDebuffComponent>(args.User, out var comp)) comp.Degen = new(){DamageDict = new(){{"Cold", 0.5}, {"Asphyxiation", 1.5}}};
|
||||||
_popup.PopupEntity(Loc.GetString("cosmiccult-gear-pickup", ("ITEM", args.Equipped)), args.User, args.User, PopupType.MediumCaution);
|
_popup.PopupEntity(Loc.GetString("cosmiccult-gear-pickup", ("ITEM", args.Equipped)), args.User, args.User, PopupType.MediumCaution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,8 +75,7 @@ public sealed class CosmicRiftSystem : EntitySystem
|
|||||||
if (TryComp<CosmicEntropyDebuffComponent>(mob, out var debuff)) debuff.Degen =
|
if (TryComp<CosmicEntropyDebuffComponent>(mob, out var debuff)) debuff.Degen =
|
||||||
new(){DamageDict = new(){
|
new(){DamageDict = new(){
|
||||||
{"Cold", 0.05 * damageMultiplier},
|
{"Cold", 0.05 * damageMultiplier},
|
||||||
{"Asphyxiation", 0.15 * damageMultiplier},
|
{"Asphyxiation", 0.15 * damageMultiplier}
|
||||||
{"Ion", 0.15 * damageMultiplier}
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
using Content.Shared._DV.Silicons;
|
|
||||||
|
|
||||||
namespace Content.Server._DV.Silicons;
|
|
||||||
|
|
||||||
public sealed class SiliconEmpSystem : SharedSiliconEmpSystem;
|
|
||||||
@@ -109,8 +109,10 @@ public sealed class FugitiveRule : StationEventSystem<FugitiveRuleComponent>
|
|||||||
var report = new FormattedMessage();
|
var report = new FormattedMessage();
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-title"));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-title"));
|
||||||
report.PushNewline();
|
report.PushNewline();
|
||||||
|
report.PushNewline();
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-first-line"));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-first-line"));
|
||||||
report.PushNewline();
|
report.PushNewline();
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
||||||
{
|
{
|
||||||
@@ -121,22 +123,28 @@ public sealed class FugitiveRule : StationEventSystem<FugitiveRuleComponent>
|
|||||||
var species = PrototypeManager.Index(humanoid.Species);
|
var species = PrototypeManager.Index(humanoid.Species);
|
||||||
|
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-morphotype", ("species", Loc.GetString(species.Name))));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-morphotype", ("species", Loc.GetString(species.Name))));
|
||||||
|
report.PushNewline();
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-age", ("age", humanoid.Age)));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-age", ("age", humanoid.Age)));
|
||||||
|
report.PushNewline();
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-sex", ("sex", humanoid.Sex)));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-sex", ("sex", humanoid.Sex)));
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
if (TryComp<PhysicsComponent>(uid, out var physics))
|
if (TryComp<PhysicsComponent>(uid, out var physics))
|
||||||
|
{
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-weight", ("weight", Math.Round(physics.FixturesMass))));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-weight", ("weight", Math.Round(physics.FixturesMass))));
|
||||||
|
report.PushNewline();
|
||||||
|
}
|
||||||
// add a random identifying quality that officers can use to track them down
|
// add a random identifying quality that officers can use to track them down
|
||||||
report.AddMarkupOrThrow(RobustRandom.Next(0, 2) switch
|
report.AddMarkupOrThrow(RobustRandom.Next(0, 2) switch
|
||||||
{
|
{
|
||||||
0 => Loc.GetString("fugitive-report-detail-dna", ("dna", GetDNA(uid))),
|
0 => Loc.GetString("fugitive-report-detail-dna", ("dna", GetDNA(uid))),
|
||||||
_ => Loc.GetString("fugitive-report-detail-prints", ("prints", GetPrints(uid)))
|
_ => Loc.GetString("fugitive-report-detail-prints", ("prints", GetPrints(uid)))
|
||||||
});
|
});
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
report.PushNewline();
|
report.PushNewline();
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-crimes-header"));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-crimes-header"));
|
||||||
|
report.PushNewline();
|
||||||
// generate some random crimes to avoid this situation
|
// generate some random crimes to avoid this situation
|
||||||
// "officer what are my charges?"
|
// "officer what are my charges?"
|
||||||
// "uh i dunno a piece of paper said to arrest you thats it"
|
// "uh i dunno a piece of paper said to arrest you thats it"
|
||||||
@@ -172,6 +180,7 @@ public sealed class FugitiveRule : StationEventSystem<FugitiveRuleComponent>
|
|||||||
{
|
{
|
||||||
var count = RobustRandom.Next(rule.MinCounts, rule.MaxCounts + 1);
|
var count = RobustRandom.Next(rule.MinCounts, rule.MaxCounts + 1);
|
||||||
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-crime", ("crime", Loc.GetString(crime)), ("count", count)));
|
report.AddMarkupOrThrow(Loc.GetString("fugitive-report-crime", ("crime", Loc.GetString(crime)), ("count", count)));
|
||||||
|
report.PushNewline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server._DV.Store.Conditions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// XOR (eXclusive-OR) Buy Condition
|
||||||
|
/// A condition where that blocks buying a listing if another listing
|
||||||
|
/// specified is bought before it. Used to enforce that a traitor
|
||||||
|
/// can only buy 1 of X options.
|
||||||
|
///
|
||||||
|
/// Primarily used for choose-your-own-adventure DAGD Implants.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class XORBuyCondition : ListingCondition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Listing(s) that if bought, block this purchase, if any.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public HashSet<ProtoId<ListingPrototype>>? Listings;
|
||||||
|
|
||||||
|
public override bool Condition(ListingConditionArgs args)
|
||||||
|
{
|
||||||
|
if (!args.EntityManager.TryGetComponent<StoreComponent>(args.StoreEntity, out var storeComp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var allListings = storeComp.FullListingsCatalog;
|
||||||
|
|
||||||
|
if (Listings != null)
|
||||||
|
{
|
||||||
|
foreach (var blacklistListing in Listings)
|
||||||
|
{
|
||||||
|
foreach (var listing in allListings)
|
||||||
|
{
|
||||||
|
if (listing.ID == blacklistListing.Id && listing.PurchaseAmount > 0)
|
||||||
|
return false; // it was purchased, so return false to fail the condition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // If no purchases were found, return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Toolshed;
|
||||||
|
using Robust.Shared.Toolshed.Errors;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server._DV.Toolshed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An extended version of the engine's <c>do</c> command. Runs a console command once per piped value,
|
||||||
|
/// substituting <c>$NAME</c> tokens in the command string first.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// On top of the built-in tokens that <c>do</c> supports (<c>$ID</c>, <c>$PID</c>, <c>$WX</c>, <c>$WY</c>,
|
||||||
|
/// <c>$LX</c>, <c>$LY</c>, <c>$SELF</c>), any other <c>$name</c> is resolved as a toolshed variable and
|
||||||
|
/// converted to a string. Tokens that don't resolve to anything are left untouched.
|
||||||
|
///
|
||||||
|
/// Where the command actually runs is explicit:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><c>doext:client</c> sends it back down to the calling user's own client to run locally. This is what
|
||||||
|
/// you want for client-side commands like <c>exec</c>, which resolve paths against the client's user data.</item>
|
||||||
|
/// <item><c>doext:server</c> runs it server-side as the calling session, like <c>do</c> does.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </remarks>
|
||||||
|
/// <example><code>
|
||||||
|
/// self doext:client "exec /Script_$var.txt"
|
||||||
|
/// i 5 => $count; self doext:server "somecommand $count"
|
||||||
|
/// </code></example>
|
||||||
|
[ToolshedCommand(Name = "doext"), AdminCommand(AdminFlags.Debug)]
|
||||||
|
public sealed class DoExtCommand : ToolshedCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Matches a <c>$name</c> token. Names use the same character set as toolshed variable names, so this
|
||||||
|
/// matches whole identifiers - <c>$IDLE</c> resolves as "IDLE" rather than being mangled into <c>$ID</c>.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Regex TokenRegex = new(@"\$(\w+)", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
[Dependency] private readonly IConsoleHost _console = default!;
|
||||||
|
|
||||||
|
private SharedTransformSystem? _xform;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the command back down to the calling user's client, which runs it locally.
|
||||||
|
/// </summary>
|
||||||
|
[CommandImplementation("client"), TakesPipedTypeAsGeneric]
|
||||||
|
public IEnumerable<T> Client<T>(IInvocationContext ctx, [PipedArgument] IEnumerable<T> input, string command)
|
||||||
|
{
|
||||||
|
// No session means there's no client to hand this back to - e.g. the server console.
|
||||||
|
if (ctx.Session is not { } session)
|
||||||
|
{
|
||||||
|
ctx.ReportError(new NoClientSessionError());
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var value in input)
|
||||||
|
{
|
||||||
|
_console.RemoteExecuteCommand(session, Substitute(command, value, ctx));
|
||||||
|
yield return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the command on the server as the calling session.
|
||||||
|
/// </summary>
|
||||||
|
[CommandImplementation("server"), TakesPipedTypeAsGeneric]
|
||||||
|
public IEnumerable<T> Server<T>(IInvocationContext ctx, [PipedArgument] IEnumerable<T> input, string command)
|
||||||
|
{
|
||||||
|
foreach (var value in input)
|
||||||
|
{
|
||||||
|
_console.ExecuteCommand(ctx.Session, Substitute(command, value, ctx));
|
||||||
|
yield return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Substitute<T>(string command, T value, IInvocationContext ctx)
|
||||||
|
{
|
||||||
|
return TokenRegex.Replace(command, match =>
|
||||||
|
{
|
||||||
|
var name = match.Groups[1].Value;
|
||||||
|
|
||||||
|
if (TryGetBuiltin(name, value, ctx, out var builtin))
|
||||||
|
return builtin;
|
||||||
|
|
||||||
|
// Anything else is looked up as a toolshed variable and implicitly stringified.
|
||||||
|
if (ctx.ReadVar(name) is { } variable)
|
||||||
|
return Stringify(variable);
|
||||||
|
|
||||||
|
// Unresolved, so leave the token alone rather than silently blanking it.
|
||||||
|
return match.Value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetBuiltin<T>(string name, T value, IInvocationContext ctx, [NotNullWhen(true)] out string? result)
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "SELF":
|
||||||
|
result = Stringify(value);
|
||||||
|
return true;
|
||||||
|
case "PID":
|
||||||
|
result = (ctx.Session?.AttachedEntity ?? EntityUid.Invalid).ToString();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining tokens are all positional, so they only apply when piping entities.
|
||||||
|
if (value is not EntityUid uid)
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "ID":
|
||||||
|
result = uid.ToString();
|
||||||
|
return true;
|
||||||
|
case "WX":
|
||||||
|
result = Number(WorldPosition(uid).X);
|
||||||
|
return true;
|
||||||
|
case "WY":
|
||||||
|
result = Number(WorldPosition(uid).Y);
|
||||||
|
return true;
|
||||||
|
case "LX":
|
||||||
|
result = Number(Transform(uid).Coordinates.X);
|
||||||
|
return true;
|
||||||
|
case "LY":
|
||||||
|
result = Number(Transform(uid).Coordinates.Y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2 WorldPosition(EntityUid uid)
|
||||||
|
{
|
||||||
|
_xform ??= GetSys<SharedTransformSystem>();
|
||||||
|
return _xform.GetWorldPosition(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Number(float value) => value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
private static string Stringify(object? value) => value?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class NoClientSessionError : IConError
|
||||||
|
{
|
||||||
|
public FormattedMessage DescribeInner()
|
||||||
|
{
|
||||||
|
return FormattedMessage.FromUnformatted("There is no client to run this on. doext:client must be run by a player, not the server console.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Expression { get; set; }
|
||||||
|
public Vector2i? IssueSpan { get; set; }
|
||||||
|
public StackTrace? Trace { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Toolshed;
|
||||||
|
using Robust.Shared.Toolshed.Errors;
|
||||||
|
using Robust.Shared.Toolshed.Syntax;
|
||||||
|
using Robust.Shared.Toolshed.TypeParsers;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server._DV.Toolshed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the value of a single field or property off of the piped input, by name.
|
||||||
|
/// Member names are resolved the same way <c>vvread</c> does: the member must be exposed
|
||||||
|
/// via <c>[ViewVariables]</c>, <c>[DataField]</c>, or <c>[IncludeDataField]</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <example><code>ent 12345 . Name</code></example>
|
||||||
|
[ToolshedCommand(Name = "."), AdminCommand(AdminFlags.Debug)]
|
||||||
|
public sealed class FieldCommand : ToolshedCommand
|
||||||
|
{
|
||||||
|
[CommandImplementation]
|
||||||
|
public object? Field([PipedArgument] object? value, [CommandArgument(typeof(FieldNameParser))] string field, IInvocationContext ctx)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
ctx.ReportError(new NullInputFieldError());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = value.GetType();
|
||||||
|
var member = GetSingleMember(type, field);
|
||||||
|
|
||||||
|
// Restrict to members that vvread would let you read, so this can't be used to peek at arbitrary internals.
|
||||||
|
if (member == null || !ViewVariablesUtility.TryGetViewVariablesAccess(member, out _))
|
||||||
|
{
|
||||||
|
ctx.ReportError(new NoSuchFieldError(type, field));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return member switch
|
||||||
|
{
|
||||||
|
FieldInfo f => f.GetValue(value),
|
||||||
|
PropertyInfo p => p.GetValue(value),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the field or property with the given name, mirroring the resolution used by <c>vvread</c>.
|
||||||
|
/// </summary>
|
||||||
|
private static MemberInfo? GetSingleMember(Type type, string member)
|
||||||
|
{
|
||||||
|
var members = type
|
||||||
|
.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||||
|
.Where(m => m.Name == member && m is FieldInfo or PropertyInfo)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (members.Length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// In case there's member hiding going on, grab the one declared by the type of the object by default.
|
||||||
|
return members.Length > 1
|
||||||
|
? members.FirstOrDefault(m => m.DeclaringType == type) ?? members[0]
|
||||||
|
: members[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a field name as a bare identifier (letters, digits, underscore) so that the <c>.</c> command doesn't
|
||||||
|
/// require the name to be wrapped in quotes like the default <see cref="string"/> parser does.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FieldNameParser : CustomTypeParser<string>
|
||||||
|
{
|
||||||
|
public override bool TryParse(ParserContext ctx, [NotNullWhen(true)] out string? result)
|
||||||
|
{
|
||||||
|
ctx.ConsumeWhitespace();
|
||||||
|
result = ctx.GetWord(ParserContext.IsToken);
|
||||||
|
if (result != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (ctx.PeekRune() is null)
|
||||||
|
ctx.Error = new OutOfInputError();
|
||||||
|
else
|
||||||
|
ctx.Error = new InvalidFieldNameError();
|
||||||
|
|
||||||
|
ctx.Error.Contextualize(ctx.Input, (ctx.Index, ctx.Index + 1));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg)
|
||||||
|
{
|
||||||
|
return CompletionResult.FromHint(GetArgHint(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InvalidFieldNameError : IConError
|
||||||
|
{
|
||||||
|
public FormattedMessage DescribeInner()
|
||||||
|
{
|
||||||
|
return FormattedMessage.FromUnformatted("Expected a field name (letters, digits, or underscores).");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Expression { get; set; }
|
||||||
|
public Vector2i? IssueSpan { get; set; }
|
||||||
|
public StackTrace? Trace { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class NullInputFieldError : IConError
|
||||||
|
{
|
||||||
|
public FormattedMessage DescribeInner()
|
||||||
|
{
|
||||||
|
return FormattedMessage.FromUnformatted("Cannot read a field off of a null input.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Expression { get; set; }
|
||||||
|
public Vector2i? IssueSpan { get; set; }
|
||||||
|
public StackTrace? Trace { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class NoSuchFieldError(Type type, string field) : IConError
|
||||||
|
{
|
||||||
|
public FormattedMessage DescribeInner()
|
||||||
|
{
|
||||||
|
return FormattedMessage.FromUnformatted($"Type {type.Name} has no readable field or property named '{field}'. It must be exposed via [ViewVariables], [DataField], or [IncludeDataField].");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Expression { get; set; }
|
||||||
|
public Vector2i? IssueSpan { get; set; }
|
||||||
|
public StackTrace? Trace { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
namespace Content.Server._Floof.OfferItem;
|
||||||
|
|
||||||
|
public sealed partial class OfferItemSystem : SharedOfferItemSystem;
|
||||||
@@ -13,7 +13,7 @@ public sealed partial class RevenantStasisComponent : Component
|
|||||||
public Entity<RevenantComponent> Revenant;
|
public Entity<RevenantComponent> Revenant;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
public TimeSpan StasisDuration = TimeSpan.FromSeconds(60);
|
public TimeSpan StasisDuration = TimeSpan.FromSeconds(100); // DeltaV - change from 60 to 100s
|
||||||
|
|
||||||
public RevenantStasisComponent(TimeSpan stasisDuration, Entity<RevenantComponent> revenant)
|
public RevenantStasisComponent(TimeSpan stasisDuration, Entity<RevenantComponent> revenant)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ using Content.Shared.Mobs;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Content.Shared.Construction.Components;
|
using Content.Shared.Construction.Components;
|
||||||
using Content.Shared.Trigger.Components;
|
using Content.Shared.Trigger.Components;
|
||||||
|
using Content.Shared.Zombies; // DeltaV
|
||||||
|
|
||||||
namespace Content.Server._Impstation.Revenant.EntitySystems;
|
namespace Content.Server._Impstation.Revenant.EntitySystems;
|
||||||
|
|
||||||
@@ -196,6 +197,7 @@ public sealed partial class RevenantAnimatedSystem : EntitySystem
|
|||||||
animate.EndTime = _gameTiming.CurTime + duration.Value;
|
animate.EndTime = _gameTiming.CurTime + duration.Value;
|
||||||
else if (revenant != null)
|
else if (revenant != null)
|
||||||
animate.EndTime = _gameTiming.CurTime + revenant.Value.Comp.AnimateTime;
|
animate.EndTime = _gameTiming.CurTime + revenant.Value.Comp.AnimateTime;
|
||||||
|
EnsureComp<ZombieImmuneComponent>(target); // DeltaV - ensure immune from zombies so we don't break clients
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,290 @@
|
|||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Robust.Server.Containers;
|
||||||
|
using Content.Shared._Starlight;
|
||||||
|
using Content.Shared.Damage.Components;
|
||||||
|
using Content.Shared.Mobs;
|
||||||
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Shared.Damage.Systems;
|
||||||
|
using Content.Shared._Goobstation.Overlays;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Content.Server.Body.Components;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Shared._Goobstation.Flashbang;
|
||||||
|
using Content.Shared._Starlight.Flash.Components;
|
||||||
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Flash; // Delta V - Flash Work
|
||||||
|
|
||||||
|
|
||||||
|
namespace Content.Server._Starlight;
|
||||||
|
|
||||||
|
public sealed class ShadekinSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||||
|
[Dependency] private readonly ContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
[Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
|
||||||
|
[Dependency] private readonly SharedFlashSystem _flashSystem = default!;
|
||||||
|
|
||||||
|
private sealed class LightCone
|
||||||
|
{
|
||||||
|
public float Direction { get; set; }
|
||||||
|
public float InnerWidth { get; set; }
|
||||||
|
public float OuterWidth { get; set; }
|
||||||
|
}
|
||||||
|
private readonly Dictionary<string, List<LightCone>> lightMasks = new()
|
||||||
|
{
|
||||||
|
["/Textures/Effects/LightMasks/cone.png"] = new List<LightCone>
|
||||||
|
{
|
||||||
|
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 }
|
||||||
|
},
|
||||||
|
["/Textures/Effects/LightMasks/double_cone.png"] = new List<LightCone>
|
||||||
|
{
|
||||||
|
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 },
|
||||||
|
new LightCone { Direction = 180, InnerWidth = 30, OuterWidth = 60 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<ShadekinComponent, ComponentStartup>(OnInit);
|
||||||
|
SubscribeLocalEvent<ShadekinComponent, EyeColorInitEvent>(OnEyeColorChange);
|
||||||
|
SubscribeLocalEvent<ShadekinComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
||||||
|
SubscribeLocalEvent<ShadekinComponent, AfterFlashedEvent>(OnShadekinFlashed); // Delta V - Prevent Chain Flashing
|
||||||
|
SubscribeLocalEvent<ShadekinComponent, FlashDurationMultiplierEvent>(GetFlashModifier); // Delta V - Flash Modifier to Shadekin
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, ShadekinComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
UpdateAlert(uid, component, (short)component.CurrentState);
|
||||||
|
RemComp<InternalsComponent>(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEyeColorChange(EntityUid uid, ShadekinComponent component, EyeColorInitEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// humanoid.EyeColor = Color.Black;
|
||||||
|
Dirty(uid, humanoid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateAlert(EntityUid uid, ShadekinComponent component, short state)
|
||||||
|
{
|
||||||
|
_alerts.ShowAlert(uid, component.ShadekinAlert, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Angle GetAngle(EntityUid lightUid, SharedPointLightComponent lightComp, EntityUid targetUid)
|
||||||
|
{
|
||||||
|
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(lightUid);
|
||||||
|
lightPos += lightRot.RotateVec(lightComp.Offset);
|
||||||
|
|
||||||
|
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetUid);
|
||||||
|
|
||||||
|
var mapDiff = targetPos - lightPos;
|
||||||
|
|
||||||
|
var oppositeMapDiff = (-lightRot).RotateVec(mapDiff);
|
||||||
|
var angle = oppositeMapDiff.ToWorldAngle();
|
||||||
|
|
||||||
|
if (angle == double.NaN && _transform.ContainsEntity(targetUid, lightUid) || _transform.ContainsEntity(lightUid, targetUid))
|
||||||
|
{
|
||||||
|
angle = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an illumination float value with is how many "energy" of light is hitting our ent.
|
||||||
|
/// WARNING: This function might be expensive, Avoid calling it too much and CACHE THE RESULT!
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public float GetLightExposure(EntityUid uid)
|
||||||
|
{
|
||||||
|
var illumination = 0f;
|
||||||
|
|
||||||
|
var lightQuery = _lookup.GetEntitiesInRange<PointLightComponent>(Transform(uid).Coordinates, 20, LookupFlags.Uncontained);
|
||||||
|
|
||||||
|
foreach (var light in lightQuery)
|
||||||
|
{
|
||||||
|
if (!light.Comp.Enabled
|
||||||
|
|| light.Comp.Radius < 1
|
||||||
|
|| light.Comp.Energy <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(light);
|
||||||
|
lightPos += lightRot.RotateVec(light.Comp.Offset);
|
||||||
|
|
||||||
|
if (!_examine.InRangeUnOccluded(light, uid, light.Comp.Radius, null))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Transform(uid).Coordinates.TryDistance(EntityManager, Transform(light).Coordinates, out var dist);
|
||||||
|
|
||||||
|
var denom = dist / light.Comp.Radius;
|
||||||
|
var attenuation = 1 - (denom * denom);
|
||||||
|
var calculatedLight = 0f;
|
||||||
|
|
||||||
|
if (light.Comp.MaskPath is not null)
|
||||||
|
{
|
||||||
|
var angleToTarget = GetAngle(light, light.Comp, uid);
|
||||||
|
foreach (var cone in lightMasks[light.Comp.MaskPath])
|
||||||
|
{
|
||||||
|
var coneLight = 0f;
|
||||||
|
var angleAttenuation = (float)Math.Min((float)Math.Max(cone.OuterWidth - angleToTarget, 0f), cone.InnerWidth) / cone.OuterWidth;
|
||||||
|
|
||||||
|
if (angleToTarget.Degrees - cone.Direction > cone.OuterWidth)
|
||||||
|
continue;
|
||||||
|
else if (angleToTarget.Degrees - cone.Direction > cone.InnerWidth
|
||||||
|
&& angleToTarget.Degrees - cone.Direction < cone.OuterWidth)
|
||||||
|
coneLight = light.Comp.Energy * attenuation * attenuation * angleAttenuation;
|
||||||
|
else
|
||||||
|
coneLight = light.Comp.Energy * attenuation * attenuation;
|
||||||
|
|
||||||
|
calculatedLight = Math.Max(calculatedLight, coneLight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
calculatedLight = light.Comp.Energy * attenuation * attenuation;
|
||||||
|
|
||||||
|
illumination += calculatedLight; //Math.Max(illumination, calculatedLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return illumination;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPassiveBuff(EntityUid uid, ShadekinState state)
|
||||||
|
{
|
||||||
|
if (!TryComp<PassiveDamageComponent>(uid, out var passive))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (state == ShadekinState.Extreme || state == ShadekinState.Annoying || state == ShadekinState.High)
|
||||||
|
{
|
||||||
|
// passive.DamageCap = 1;
|
||||||
|
}
|
||||||
|
else if (state == ShadekinState.Low)
|
||||||
|
{
|
||||||
|
// passive.DamageCap = 20;
|
||||||
|
passive.AllowedStates.Clear();
|
||||||
|
passive.AllowedStates.Add(MobState.Alive);
|
||||||
|
passive.Interval = 1f;
|
||||||
|
}
|
||||||
|
else if (state != ShadekinState.Dark)
|
||||||
|
{
|
||||||
|
// passive.DamageCap = 0;
|
||||||
|
passive.AllowedStates.Clear();
|
||||||
|
passive.AllowedStates.Add(MobState.Alive);
|
||||||
|
passive.AllowedStates.Add(MobState.Critical);
|
||||||
|
passive.AllowedStates.Add(MobState.Dead);
|
||||||
|
passive.Interval = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleNightVision(EntityUid uid, ShadekinState state)
|
||||||
|
{
|
||||||
|
if (state == ShadekinState.Dark)
|
||||||
|
{
|
||||||
|
var nightVisionComponent = EnsureComp<NightVisionComponent>(uid);
|
||||||
|
nightVisionComponent.Color = Color.FromHex("#808080"); // Delta V - Change Night Vision Color
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TryComp<NightVisionComponent>(uid, out var nightVision) && nightVision.IsActive)
|
||||||
|
_flashSystem.Flash(uid, uid, uid, TimeSpan.FromSeconds(0.5 * (int)state), 0.5f);
|
||||||
|
RemComp<NightVisionComponent>(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyLightDamage(EntityUid uid, float dmg)
|
||||||
|
{
|
||||||
|
var damage = new DamageSpecifier();
|
||||||
|
damage.DamageDict.Add("Heat", dmg);
|
||||||
|
_damageable.TryChangeDamage(uid, damage, true, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRefreshMovementSpeedModifiers(EntityUid uid, ShadekinComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||||
|
{
|
||||||
|
if (component.CurrentState == ShadekinState.Low || component.CurrentState == ShadekinState.Annoying ||
|
||||||
|
component.CurrentState == ShadekinState.Dark || component.CurrentState == ShadekinState.Invalid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<MovementSpeedModifierComponent>(uid, out var movement))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
|
||||||
|
args.ModifySpeed(1f, sprintDif);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShadekinState GetStateByThreshold(ShadekinComponent component, float lightExposure)
|
||||||
|
{
|
||||||
|
var returnState = ShadekinState.Dark;
|
||||||
|
|
||||||
|
foreach (var (threshold, shadekinState) in component.Thresholds.Reverse())
|
||||||
|
{
|
||||||
|
if (threshold <= lightExposure)
|
||||||
|
{
|
||||||
|
returnState = shadekinState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delta V - Begin Shadekin Flash Changes
|
||||||
|
private void GetFlashModifier(EntityUid uid, ShadekinComponent comp, FlashDurationMultiplierEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<FlashModifierComponent>(uid, out var flashModifier))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Multiplier = flashModifier.Modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShadekinFlashed(EntityUid uid, ShadekinComponent comp, AfterFlashedEvent ev)
|
||||||
|
{
|
||||||
|
RemComp<NightVisionComponent>(uid);
|
||||||
|
}
|
||||||
|
// Delta V - End
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<ShadekinComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var component))
|
||||||
|
{
|
||||||
|
if (_timing.CurTime < component.NextUpdate)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
component.NextUpdate = _timing.CurTime + component.UpdateCooldown;
|
||||||
|
|
||||||
|
var lightExposure = 0f;
|
||||||
|
|
||||||
|
if (!_container.IsEntityInContainer(uid))
|
||||||
|
lightExposure = GetLightExposure(uid);
|
||||||
|
|
||||||
|
component.CurrentState = GetStateByThreshold(component, lightExposure);
|
||||||
|
|
||||||
|
UpdateAlert(uid, component, (short)component.CurrentState);
|
||||||
|
|
||||||
|
SetPassiveBuff(uid, component.CurrentState);
|
||||||
|
ToggleNightVision(uid, component.CurrentState);
|
||||||
|
|
||||||
|
_speed.RefreshMovementSpeedModifiers(uid);
|
||||||
|
|
||||||
|
if (component.CurrentState == ShadekinState.Extreme)
|
||||||
|
ApplyLightDamage(uid, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,8 @@ using Robust.Shared.Timing;
|
|||||||
using Content.Shared._DV.Access.Systems;
|
using Content.Shared._DV.Access.Systems;
|
||||||
using Content.Shared._DV.Access.Components;
|
using Content.Shared._DV.Access.Components;
|
||||||
using Content.Shared.Mind; // DeltaV - Subdermal ID Cards
|
using Content.Shared.Mind; // DeltaV - Subdermal ID Cards
|
||||||
|
using Content.Shared.Ninja.Components; // DeltaV
|
||||||
|
using Content.Shared.Revenant.Components; // DeltaV
|
||||||
|
|
||||||
namespace Content.Shared.Access.Systems;
|
namespace Content.Shared.Access.Systems;
|
||||||
|
|
||||||
@@ -31,7 +33,6 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly EmagSystem _emag = default!;
|
|
||||||
[Dependency] private readonly TagSystem _tag = default!;
|
[Dependency] private readonly TagSystem _tag = default!;
|
||||||
[Dependency] private readonly SharedGameTicker _gameTicker = default!;
|
[Dependency] private readonly SharedGameTicker _gameTicker = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
@@ -151,7 +152,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (!_emag.CompareFlag(args.Type, EmagType.Interaction)) // DeltaV - emag for lockers etc instead of doorjack
|
if (HasComp<SpaceNinjaComponent>(args.UserUid) || HasComp<RevenantComponent>(args.UserUid)) // DeltaV - Don't break access if its a ninja doing it
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!reader.BreakOnAccessBreaker)
|
if (!reader.BreakOnAccessBreaker)
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ public abstract partial class SharedVisualBodySystem : EntitySystem
|
|||||||
if (!other.Layer.Equals(ent.Comp.Layer))
|
if (!other.Layer.Equals(ent.Comp.Layer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Delta V - Begin Fix Height for Cloning
|
||||||
|
var height = other.Profile.Height;
|
||||||
|
if (TryComp<HumanoidProfileComponent>(args.Body.Owner, out var component))
|
||||||
|
ScaleBody((args.Body.Owner, component), height, height);
|
||||||
|
// Delta V - End
|
||||||
|
|
||||||
SetOrganAppearance(ent, other.Data);
|
SetOrganAppearance(ent, other.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,9 +118,14 @@ public abstract partial class SharedVisualBodySystem : EntitySystem
|
|||||||
|
|
||||||
var height = Math.Clamp(MathF.Round(args.Base.Value.Height, 2), speciesPrototype.MinHeight, speciesPrototype.MaxHeight);
|
var height = Math.Clamp(MathF.Round(args.Base.Value.Height, 2), speciesPrototype.MinHeight, speciesPrototype.MaxHeight);
|
||||||
|
|
||||||
|
ScaleBody(entity, speciesPrototype.ScaleHeight ? height : 1f, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScaleBody(Entity<HumanoidProfileComponent> entity, float heightX, float heightY)
|
||||||
|
{
|
||||||
_scaleVisualsSystem.SetSpriteScale(
|
_scaleVisualsSystem.SetSpriteScale(
|
||||||
entity.Owner,
|
entity.Owner,
|
||||||
new Vector2(speciesPrototype.ScaleHeight ? height : 1f, height)
|
new Vector2(heightX, heightY)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Delta V - END
|
// Delta V - END
|
||||||
@@ -148,7 +159,7 @@ public abstract partial class SharedVisualBodySystem : EntitySystem
|
|||||||
if (ent.Comp.Layer.Equals(HumanoidVisualLayers.Eyes))
|
if (ent.Comp.Layer.Equals(HumanoidVisualLayers.Eyes))
|
||||||
{
|
{
|
||||||
// Delta V - Begin Add AppearanceLoaded Event
|
// Delta V - Begin Add AppearanceLoaded Event
|
||||||
var appearanceLoaded = new AppearanceLoadedEvent(ent.Comp.Profile.EyeColor);
|
var appearanceLoaded = new AppearanceLoadedEvent(ent.Comp.Profile.EyeColor, ent.Comp.Profile.SkinColor);
|
||||||
RaiseLocalEvent(args.Body.Owner, ref appearanceLoaded);
|
RaiseLocalEvent(args.Body.Owner, ref appearanceLoaded);
|
||||||
// Delta V - End
|
// Delta V - End
|
||||||
SetOrganColor(ent, ent.Comp.Profile.EyeColor);
|
SetOrganColor(ent, ent.Comp.Profile.EyeColor);
|
||||||
|
|||||||
@@ -28,4 +28,18 @@ public readonly partial record struct CargoBountyData
|
|||||||
Bounty = bounty.ID;
|
Bounty = bounty.ID;
|
||||||
Id = $"{bounty.IdPrefix}{uniqueIdentifier:D3}";
|
Id = $"{bounty.IdPrefix}{uniqueIdentifier:D3}";
|
||||||
}
|
}
|
||||||
}
|
// Begin DeltaV bounty claiming
|
||||||
|
[DataField]
|
||||||
|
public string ClaimedBy { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public CargoBountyStatus Status { get; init; } = CargoBountyStatus.Undelivered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CargoBountyStatus
|
||||||
|
{
|
||||||
|
Undelivered,
|
||||||
|
Waiting,
|
||||||
|
OnShuttle,
|
||||||
|
} // End DeltaV bounty claiming
|
||||||
|
|
||||||
|
|||||||
@@ -94,3 +94,4 @@ public sealed class BountySkipMessage : BoundUserInterfaceMessage
|
|||||||
BountyId = bountyId;
|
BountyId = bountyId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,6 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedPvsOverrideSystem _pvs = default!; // Frontier
|
[Dependency] private readonly SharedPvsOverrideSystem _pvs = default!; // Frontier
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!; // Frontier: EMP Blast PVS
|
[Dependency] private readonly IConfigurationManager _cfg = default!; // Frontier: EMP Blast PVS
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// DeltaV. Default damage of EMPs, as dertermined by direction. There's no good component to put
|
|
||||||
/// this on so its defined here.
|
|
||||||
/// </summary>
|
|
||||||
private static readonly DamageSpecifier? DefaultEmpDamage = new() { DamageDict = new() { { "Ion", 130 } } };
|
|
||||||
|
|
||||||
private HashSet<EntityUid> _entSet = new();
|
private HashSet<EntityUid> _entSet = new();
|
||||||
private EntityQuery<EmpResistanceComponent> _resistanceQuery;
|
private EntityQuery<EmpResistanceComponent> _resistanceQuery;
|
||||||
|
|
||||||
@@ -59,12 +53,11 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse. In Joule.</param>
|
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse. In Joule.</param>
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
/// <param name="duration">The duration of the EMP effects.</param>
|
||||||
/// <param name="user">The player that caused the effect. Used for predicted audio.</param>
|
/// <param name="user">The player that caused the effect. Used for predicted audio.</param>
|
||||||
/// <param name="damage">DeltaV - The damage that that EMP will do. If not specified or null, will do 130 Ion damage. To do no damage, pass in a DamageSpecifier with no damage types.</param>
|
public void EmpPulse(MapCoordinates mapCoordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null)
|
||||||
public void EmpPulse(MapCoordinates mapCoordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
|
|
||||||
{
|
{
|
||||||
foreach (var uid in _lookup.GetEntitiesInRange(mapCoordinates, range))
|
foreach (var uid in _lookup.GetEntitiesInRange(mapCoordinates, range))
|
||||||
{
|
{
|
||||||
TryEmpEffects(uid, energyConsumption, duration, user, damage ?? DefaultEmpDamage); // DeltaV - Add Ion Damage
|
TryEmpEffects(uid, energyConsumption, duration, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace with PredictedSpawn once it works with animated sprites
|
// TODO: replace with PredictedSpawn once it works with animated sprites
|
||||||
@@ -92,15 +85,13 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse.</param>
|
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse.</param>
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
/// <param name="duration">The duration of the EMP effects.</param>
|
||||||
/// <param name="user">The player that caused the effect. Used for predicted audio.</param>'
|
/// <param name="user">The player that caused the effect. Used for predicted audio.</param>'
|
||||||
/// <param name="damage">DeltaV - The damage that that EMP will do. If not specified or null, will do 130 Ion damage. To do no damage, pass in a DamageSpecifier with no damage types.</param>
|
public void EmpPulse(EntityCoordinates coordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null, bool predicted = true)
|
||||||
/// <param name="predicted">Whether this pulse is being replicated on the client.</param>
|
|
||||||
public void EmpPulse(EntityCoordinates coordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null, bool predicted = true) // Delta V - Add ion damage
|
|
||||||
{
|
{
|
||||||
_entSet.Clear();
|
_entSet.Clear();
|
||||||
_lookup.GetEntitiesInRange(coordinates, range, _entSet);
|
_lookup.GetEntitiesInRange(coordinates, range, _entSet);
|
||||||
foreach (var uid in _entSet)
|
foreach (var uid in _entSet)
|
||||||
{
|
{
|
||||||
TryEmpEffects(uid, energyConsumption, duration, user, damage ?? DefaultEmpDamage); // DeltaV - Add Ion Damage
|
TryEmpEffects(uid, energyConsumption, duration, user);
|
||||||
}
|
}
|
||||||
// TODO: replace with PredictedSpawn once it works with animated sprites
|
// TODO: replace with PredictedSpawn once it works with animated sprites
|
||||||
if (_net.IsServer)
|
if (_net.IsServer)
|
||||||
@@ -123,37 +114,31 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to apply the effects of an EMP pulse onto an entity by first raising an <see cref="EmpAttemptEvent"/>, followed by raising a <see cref="EmpPulseEvent"/> on it.
|
/// Attempts to apply the effects of an EMP pulse onto an entity by first raising an <see cref="EmpAttemptEvent"/>, followed by raising a <see cref="EmpPulseEvent"/> on it.
|
||||||
/// <br/>
|
|
||||||
/// <br/>DeltaV - In most cases, you will want to use <see cref="EmpPulse"/> instead.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uid">The entity to apply the EMP effects on.</param>
|
/// <param name="uid">The entity to apply the EMP effects on.</param>
|
||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP.</param>
|
/// <param name="energyConsumption">The amount of energy consumed by the EMP.</param>
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
/// <param name="duration">The duration of the EMP effects.</param>
|
||||||
/// <param name="user">The player that caused the EMP. For prediction purposes.</param>
|
/// <param name="user">The player that caused the EMP. For prediction purposes.</param>
|
||||||
/// <param name="damage">DeltaV - The damage that that EMP will do. If null, no damage is done.</param>
|
|
||||||
/// <returns>If the entity was affected by the EMP.</returns>
|
/// <returns>If the entity was affected by the EMP.</returns>
|
||||||
public bool TryEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
|
public bool TryEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
var attemptEv = new EmpAttemptEvent();
|
var attemptEv = new EmpAttemptEvent();
|
||||||
RaiseLocalEvent(uid, ref attemptEv);
|
RaiseLocalEvent(uid, ref attemptEv);
|
||||||
if (attemptEv.Cancelled)
|
if (attemptEv.Cancelled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return DoEmpEffects(uid, energyConsumption, duration, user, damage); // DeltaV - Add Ion Damage
|
return DoEmpEffects(uid, energyConsumption, duration, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the effects of an EMP pulse onto an entity by raising a <see cref="EmpPulseEvent"/> on it.
|
/// Applies the effects of an EMP pulse onto an entity by raising a <see cref="EmpPulseEvent"/> on it.
|
||||||
/// <br/>
|
|
||||||
/// <br/>DeltaV - In most cases, you will want to use <see cref="EmpPulse"/> instead.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uid">The entity to apply the EMP effects on.</param>
|
/// <param name="uid">The entity to apply the EMP effects on.</param>
|
||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP.</param>
|
/// <param name="energyConsumption">The amount of energy consumed by the EMP.</param>
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
/// <param name="duration">The duration of the EMP effects.</param>
|
||||||
/// <param name="user">The player that caused the EMP. For prediction purposes.</param>
|
/// <param name="user">The player that caused the EMP. For prediction purposes.</param>
|
||||||
/// <param name="damage">DeltaV - The damage that that EMP will do. If null, no damage is done.</param>
|
|
||||||
/// <returns>If the entity was affected by the EMP.</returns>
|
/// <returns>If the entity was affected by the EMP.</returns>
|
||||||
public bool DoEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
|
public bool DoEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
var strMultiplier = 1f;
|
var strMultiplier = 1f;
|
||||||
var durMultiplier = 1f;
|
var durMultiplier = 1f;
|
||||||
@@ -162,7 +147,7 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
strMultiplier = resistance.StrengthMultiplier;
|
strMultiplier = resistance.StrengthMultiplier;
|
||||||
durMultiplier = resistance.DurationMultiplier;
|
durMultiplier = resistance.DurationMultiplier;
|
||||||
}
|
}
|
||||||
var ev = new EmpPulseEvent(energyConsumption * strMultiplier, false, false, duration * durMultiplier, user, damage); // DeltaV - Add Ion Damage
|
var ev = new EmpPulseEvent(energyConsumption * strMultiplier, false, false, duration * durMultiplier, user);
|
||||||
RaiseLocalEvent(uid, ref ev);
|
RaiseLocalEvent(uid, ref ev);
|
||||||
|
|
||||||
// TODO: replace with PredictedSpawn once it works with animated sprites
|
// TODO: replace with PredictedSpawn once it works with animated sprites
|
||||||
@@ -235,7 +220,7 @@ public record struct EmpAttemptEvent(bool Cancelled);
|
|||||||
/// <param name="User">The player that caused the EMP. For prediction purposes.</param>
|
/// <param name="User">The player that caused the EMP. For prediction purposes.</param>
|
||||||
|
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration, EntityUid? User, DamageSpecifier? Damage = null); // DeltaV - Added Damage
|
public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration, EntityUid? User);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised on an entity after <see cref="EmpDisabledComponent"/> is removed.
|
/// Raised on an entity after <see cref="EmpDisabledComponent"/> is removed.
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ using System.Linq;
|
|||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Random.Helpers;
|
using Content.Shared.Random.Helpers;
|
||||||
using Content.Shared.Clothing.Components;
|
using Content.Shared.Clothing.Components;
|
||||||
|
using Content.Shared._Starlight.Flash.Components; // Delta V - For Flash Duration
|
||||||
|
|
||||||
namespace Content.Shared.Flash;
|
namespace Content.Shared.Flash;
|
||||||
|
|
||||||
@@ -173,7 +174,7 @@ public abstract class SharedFlashSystem : EntitySystem
|
|||||||
// Goobstation end
|
// Goobstation end
|
||||||
|
|
||||||
// don't paralyze, slowdown or convert to rev if the target is immune to flashes
|
// don't paralyze, slowdown or convert to rev if the target is immune to flashes
|
||||||
if (!_statusEffectsSystem.TryAddStatusEffect<FlashedComponent>(target, FlashedKey, flashDuration, true) && !ignoreProtection) //DeltaV: allow flashing to ignore flash protection
|
if (!_statusEffectsSystem.TryAddStatusEffect<FlashedComponent>(target, FlashedKey, flashDuration * multiplier, true) && !ignoreProtection) //DeltaV: allow flashing to ignore flash protection. Added Flashduration Multiplier
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (stunDuration != null)
|
if (stunDuration != null)
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ namespace Content.Shared.Input
|
|||||||
public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI";
|
public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI";
|
||||||
public static readonly BoundKeyFunction ToggleFullscreen = "ToggleFullscreen";
|
public static readonly BoundKeyFunction ToggleFullscreen = "ToggleFullscreen";
|
||||||
public static readonly BoundKeyFunction Point = "Point";
|
public static readonly BoundKeyFunction Point = "Point";
|
||||||
|
public static readonly BoundKeyFunction OfferItem = "OfferItem"; // Floofstation
|
||||||
public static readonly BoundKeyFunction ZoomOut = "ZoomOut";
|
public static readonly BoundKeyFunction ZoomOut = "ZoomOut";
|
||||||
public static readonly BoundKeyFunction ZoomIn = "ZoomIn";
|
public static readonly BoundKeyFunction ZoomIn = "ZoomIn";
|
||||||
public static readonly BoundKeyFunction ResetZoom = "ResetZoom";
|
public static readonly BoundKeyFunction ResetZoom = "ResetZoom";
|
||||||
|
|||||||
@@ -103,6 +103,22 @@ public abstract class SharedItemSystem : EntitySystem
|
|||||||
VisualsChanged(uid);
|
VisualsChanged(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DeltaV - clear item visuals
|
||||||
|
/// </summary>
|
||||||
|
public void ClearVisuals(Entity<ItemComponent?> ent)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ent.Comp.RsiPath = null;
|
||||||
|
ent.Comp.InhandVisuals = new();
|
||||||
|
ent.Comp.HeldPrefix = null;
|
||||||
|
|
||||||
|
Dirty(ent, ent.Comp);
|
||||||
|
VisualsChanged(ent.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHandEvent args)
|
private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHandEvent args)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared._ST.Interaction; // Stellar - interaction particles
|
using Content.Shared._ST.Interaction; // Stellar - interaction particles
|
||||||
|
using Content.Shared._Floof.OfferItem; // Floof
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -117,10 +118,11 @@ public sealed class PullingSystem : EntitySystem
|
|||||||
if (TryComp(args.PullerUid, out PullerComponent? pullerComp) && !pullerComp.NeedsHands)
|
if (TryComp(args.PullerUid, out PullerComponent? pullerComp) && !pullerComp.NeedsHands)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid))
|
if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid, out var virt)) // Floofstation - store item
|
||||||
{
|
{
|
||||||
DebugTools.Assert("Unable to find available hand when starting pulling??");
|
DebugTools.Assert("Unable to find available hand when starting pulling??");
|
||||||
}
|
}
|
||||||
|
EnsureComp<OfferableVirtualItemComponent>(virt.Value); // Floofstation - add a special component to allow offering it
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
|
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Bed.Sleep;
|
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Item.PseudoItem;
|
using Content.Shared.Item.PseudoItem;
|
||||||
@@ -24,7 +23,8 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||||||
[Dependency] private readonly TagSystem _tag = default!;
|
[Dependency] private readonly TagSystem _tag = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!; // Floofstation
|
||||||
|
[Dependency] private readonly SharedHandsSystem _hands = default!; // Floofstation
|
||||||
|
|
||||||
private readonly ProtoId<TagPrototype> PreventTag = "PreventLabel";
|
private readonly ProtoId<TagPrototype> PreventTag = "PreventLabel";
|
||||||
private readonly EntProtoId SleepActionId = "ActionSleep"; // The action used for sleeping inside bags. Currently uses the default sleep action (same as beds)
|
private readonly EntProtoId SleepActionId = "ActionSleep"; // The action used for sleeping inside bags. Currently uses the default sleep action (same as beds)
|
||||||
@@ -116,17 +116,35 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||||||
protected virtual void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component,
|
protected virtual void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component,
|
||||||
GettingPickedUpAttemptEvent args)
|
GettingPickedUpAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (args.User == args.Item)
|
args.Cancel(); // Floof - this is a terrible idea. This triggers every time ANY system checks if a pseudo-item can be picked up.
|
||||||
return;
|
// WHY DID YOU DO THAT, NYANOTRASEN???
|
||||||
|
|
||||||
_transform.AttachToGridOrMap(uid);
|
// if (args.User == args.Item)
|
||||||
args.Cancel();
|
// return;
|
||||||
|
//
|
||||||
|
// _transform.AttachToGridOrMap(uid);
|
||||||
|
// args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAttemptEvent args)
|
private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (component.Active)
|
if (!component.Active)
|
||||||
args.Cancel();
|
return;
|
||||||
|
|
||||||
|
// Floof - we try to get the containing container and try to drop it into it
|
||||||
|
// If possible, we do it, since a bagged cat probably can put things back into the bag just like they can pick them up.
|
||||||
|
string? failReason = null;
|
||||||
|
if (_hands.GetActiveItem(uid) is { Valid: true, } droppedItem
|
||||||
|
&& _container.TryGetContainingContainer(Transform(uid).ParentUid, uid, out var pseudoItemContainer)
|
||||||
|
&& TryComp<StorageComponent>(pseudoItemContainer.Owner, out var targetStorage)
|
||||||
|
&& _storage.CanInsert(pseudoItemContainer.Owner, droppedItem, out failReason, targetStorage, ignoreStacks: true)
|
||||||
|
)
|
||||||
|
_storage.Insert(pseudoItemContainer.Owner, droppedItem, out _, uid, targetStorage, stackAutomatically: false);
|
||||||
|
|
||||||
|
if (failReason != null)
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString(failReason), uid, uid);
|
||||||
|
|
||||||
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
|
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
|
||||||
@@ -141,8 +159,9 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||||||
// Prevents moving within the bag :)
|
// Prevents moving within the bag :)
|
||||||
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
|
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (args.Uid == args.Target && component.Active)
|
// Floof - why the fuck.
|
||||||
args.Cancelled = true;
|
// if (args.Uid == args.Target && component.Active)
|
||||||
|
// args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
|
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public sealed partial class RevenantComponent : Component
|
|||||||
public string SpawnOnDeathPrototype = "EctoplasmRevenant"; // DeltaV
|
public string SpawnOnDeathPrototype = "EctoplasmRevenant"; // DeltaV
|
||||||
|
|
||||||
[DataField("stasisTime"), ViewVariables(VVAccess.ReadWrite)] // Begin Imp Changes
|
[DataField("stasisTime"), ViewVariables(VVAccess.ReadWrite)] // Begin Imp Changes
|
||||||
public TimeSpan StasisTime = TimeSpan.FromSeconds(60);
|
public TimeSpan StasisTime = TimeSpan.FromSeconds(100); // DeltaV - change from 60 to 100s
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, only bible users can exorcise this revenant
|
/// If true, only bible users can exorcise this revenant
|
||||||
@@ -50,7 +50,7 @@ public sealed partial class RevenantComponent : Component
|
|||||||
/// grinder will explode.
|
/// grinder will explode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool GrindingRequiresSalt = true; // End Imp Changes
|
public bool GrindingRequiresSalt = false; // End Imp Changes - DeltaV - true to false
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity's current max amount of essence. Can be increased
|
/// The entity's current max amount of essence. Can be increased
|
||||||
|
|||||||
@@ -188,12 +188,20 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin DeltaV - the grid check excludes the item being resized because it's already in the storage which defeats the purpose so yoink it out to remove that
|
||||||
|
storage.StoredItems.Remove(itemEnt.Owner);
|
||||||
UpdateOccupied((container.Owner, storage));
|
UpdateOccupied((container.Owner, storage));
|
||||||
|
|
||||||
if (!ItemFitsInGridLocation((itemEnt.Owner, itemEnt.Comp), (container.Owner, storage), loc))
|
if (ItemFitsInGridLocation((itemEnt.Owner, itemEnt.Comp), (container.Owner, storage), loc))
|
||||||
|
{
|
||||||
|
storage.StoredItems.Add(itemEnt.Owner, loc);
|
||||||
|
UpdateOccupied((container.Owner, storage));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ContainerSystem.Remove(itemEnt.Owner, container, force: true);
|
ContainerSystem.Remove(itemEnt.Owner, container, force: true);
|
||||||
}
|
}
|
||||||
|
// End DeltaV - the grid check excludes the item being resized because it's already in the storage which defeats the purpose so yoink it out to remove that
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNestedStorageCvar(bool obj)
|
private void OnNestedStorageCvar(bool obj)
|
||||||
|
|||||||
@@ -28,10 +28,4 @@ public sealed partial class EmpOnTriggerComponent : BaseXOnTriggerComponent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public TimeSpan DisableDuration = TimeSpan.FromSeconds(60);
|
public TimeSpan DisableDuration = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// DeltaV - The damage dealt to silicons instead of draining their power cells
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public DamageSpecifier? Damage;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public sealed class EmpOnTriggerSystem : XOnTriggerSystem<EmpOnTriggerComponent>
|
|||||||
|
|
||||||
protected override void OnTrigger(Entity<EmpOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
|
protected override void OnTrigger(Entity<EmpOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
_emp.EmpPulse(Transform(target).Coordinates, ent.Comp.Range, ent.Comp.EnergyConsumption, ent.Comp.DisableDuration, args.User, ent.Comp.Damage, predicted: args.Predicted); // Delta V - Silicon Damage
|
_emp.EmpPulse(Transform(target).Coordinates, ent.Comp.Range, ent.Comp.EnergyConsumption, ent.Comp.DisableDuration, args.User, predicted: args.Predicted);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,4 +75,7 @@ public sealed partial class PreenableComponent : Component
|
|||||||
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
|
||||||
public TimeSpan? ReplenishTime;
|
public TimeSpan? ReplenishTime;
|
||||||
|
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Color? Color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared._DV.Body.Components;
|
using Content.Shared._DV.Body.Components;
|
||||||
using Content.Shared._DV.Body.Events;
|
using Content.Shared._DV.Body.Events;
|
||||||
|
using Content.Shared._DV.Humanoid;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
@@ -45,6 +46,7 @@ public sealed class PreenableSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<PreenableComponent, DamageChangedEvent>(OnDamaged);
|
SubscribeLocalEvent<PreenableComponent, DamageChangedEvent>(OnDamaged);
|
||||||
SubscribeLocalEvent<PreenableComponent, DamageModifyEvent>(OnDamageModify);
|
SubscribeLocalEvent<PreenableComponent, DamageModifyEvent>(OnDamageModify);
|
||||||
SubscribeLocalEvent<PreenableComponent, ComponentInit>(OnCompInit);
|
SubscribeLocalEvent<PreenableComponent, ComponentInit>(OnCompInit);
|
||||||
|
SubscribeLocalEvent<PreenableComponent, AppearanceLoadedEvent>(OnProfileLoadFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCompInit(Entity<PreenableComponent> ent, ref ComponentInit args)
|
private void OnCompInit(Entity<PreenableComponent> ent, ref ComponentInit args)
|
||||||
@@ -185,7 +187,7 @@ public sealed class PreenableSystem : EntitySystem
|
|||||||
|
|
||||||
if (TryComp<HumanoidProfileComponent>(ent, out var appearance))
|
if (TryComp<HumanoidProfileComponent>(ent, out var appearance))
|
||||||
{
|
{
|
||||||
_appearance.SetData(feather, FeatherVisuals.FeatherColor, Color.White); // TODO: Nubody Colors
|
_appearance.SetData(feather, FeatherVisuals.FeatherColor, ent.Comp.Color ?? Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
// best be careful, no cleaning this
|
// best be careful, no cleaning this
|
||||||
@@ -204,6 +206,11 @@ public sealed class PreenableSystem : EntitySystem
|
|||||||
return feather;
|
return feather;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnProfileLoadFinished(Entity<PreenableComponent> ent, ref AppearanceLoadedEvent args)
|
||||||
|
{
|
||||||
|
ent.Comp.Color = args.SkinColor;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Cargo.Components;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class BountyClaimedMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly string BountyId;
|
||||||
|
|
||||||
|
public BountyClaimedMessage(string bountyId)
|
||||||
|
{
|
||||||
|
BountyId = bountyId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class BountySetStatusMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly string BountyId;
|
||||||
|
public readonly int Status;
|
||||||
|
|
||||||
|
public BountySetStatusMessage(string bountyId, int status)
|
||||||
|
{
|
||||||
|
BountyId = bountyId;
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ using Robust.Shared.Network;
|
|||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared._DV.Polymorph;
|
using Content.Shared._DV.Polymorph;
|
||||||
|
using Content.Shared._Floof.OfferItem;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
|
||||||
namespace Content.Shared._DV.Carrying;
|
namespace Content.Shared._DV.Carrying;
|
||||||
@@ -181,14 +182,15 @@ public sealed class CarryingSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnInteractionAttempt(Entity<BeingCarriedComponent> ent, ref InteractionAttemptEvent args)
|
private void OnInteractionAttempt(Entity<BeingCarriedComponent> ent, ref InteractionAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (args.Target is not {} target)
|
// Floofstation - no - this prevents the person from escaping and more.
|
||||||
return;
|
// if (args.Target is not {} target)
|
||||||
|
// return;
|
||||||
var targetParent = Transform(target).ParentUid;
|
//
|
||||||
|
// var targetParent = Transform(target).ParentUid;
|
||||||
var carrier = ent.Comp.Carrier;
|
//
|
||||||
if (target != carrier && targetParent != carrier && targetParent != ent.Owner)
|
// var carrier = ent.Comp.Carrier;
|
||||||
args.Cancelled = true;
|
// if (target != carrier && targetParent != carrier && targetParent != ent.Owner)
|
||||||
|
// args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMoveAttempt(Entity<BeingCarriedComponent> ent, ref UpdateCanMoveEvent args)
|
private void OnMoveAttempt(Entity<BeingCarriedComponent> ent, ref UpdateCanMoveEvent args)
|
||||||
@@ -203,8 +205,9 @@ public sealed class CarryingSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnInteractedWith(Entity<BeingCarriedComponent> ent, ref GettingInteractedWithAttemptEvent args)
|
private void OnInteractedWith(Entity<BeingCarriedComponent> ent, ref GettingInteractedWithAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (args.Uid != ent.Comp.Carrier)
|
// Floofstation - why?
|
||||||
args.Cancelled = true;
|
// if (args.Uid != ent.Comp.Carrier)
|
||||||
|
// args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPullAttempt(Entity<BeingCarriedComponent> ent, ref PullAttemptEvent args)
|
private void OnPullAttempt(Entity<BeingCarriedComponent> ent, ref PullAttemptEvent args)
|
||||||
@@ -242,7 +245,8 @@ public sealed class CarryingSystem : EntitySystem
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartCarryDoAfter(EntityUid carrier, Entity<CarriableComponent> carried)
|
// Floofstation - made public
|
||||||
|
public void StartCarryDoAfter(EntityUid carrier, Entity<CarriableComponent> carried)
|
||||||
{
|
{
|
||||||
TimeSpan length = GetPickupDuration(carrier, carried);
|
TimeSpan length = GetPickupDuration(carrier, carried);
|
||||||
|
|
||||||
@@ -299,7 +303,8 @@ public sealed class CarryingSystem : EntitySystem
|
|||||||
|
|
||||||
for (var x = 0; x < Comp<CarriableComponent>(carried).FreeHandsRequired; x++)
|
for (var x = 0; x < Comp<CarriableComponent>(carried).FreeHandsRequired; x++)
|
||||||
{
|
{
|
||||||
_virtualItem.TrySpawnVirtualItemInHand(carried, carrier);
|
if (_virtualItem.TrySpawnVirtualItemInHand(carried, carrier, out var virtualItem))
|
||||||
|
EnsureComp<OfferableVirtualItemComponent>(virtualItem.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Content.Shared.Item;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Forensics;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class DVExpandToInsertedItemSizeComponent : Component
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string ItemSlot;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public ProtoId<ItemSizePrototype> EmptySize;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using Content.Shared.Item;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Forensics;
|
||||||
|
|
||||||
|
public sealed class DVExpandToInsertedItemSizeSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DVExpandToInsertedItemSizeComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
|
||||||
|
SubscribeLocalEvent<DVExpandToInsertedItemSizeComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Refresh(Entity<DVExpandToInsertedItemSizeComponent> ent)
|
||||||
|
{
|
||||||
|
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||||
|
if (slot.ContainedEntity is { } contained)
|
||||||
|
{
|
||||||
|
var item = Comp<ItemComponent>(contained);
|
||||||
|
_item.SetSize(ent, item.Size);
|
||||||
|
_item.SetShape(ent, item.Shape);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_item.SetSize(ent, ent.Comp.EmptySize);
|
||||||
|
_item.SetShape(ent, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemInserted(Entity<DVExpandToInsertedItemSizeComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.ItemSlot != args.Container.ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Refresh(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemRemoved(Entity<DVExpandToInsertedItemSizeComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.ItemSlot != args.Container.ID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Refresh(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Forensics;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class DVItemSlotVisualsComponent : Component
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string ItemSlot;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public SpriteSpecifier FilledSprite;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public SpriteSpecifier UnfilledSprite;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Forensics;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class DVSeenInsertedItemComponent : Component
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string ItemSlot;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Item;
|
||||||
|
using Content.Shared.NameModifier.EntitySystems;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Shared._DV.Forensics;
|
||||||
|
|
||||||
|
public sealed class DVSeenInsertedItemSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly NameModifierSystem _nameModifier = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DVSeenInsertedItemComponent, ExaminedEvent>(OnExamined);
|
||||||
|
SubscribeLocalEvent<DVSeenInsertedItemComponent, RefreshNameModifiersEvent>(OnRefreshModifiers);
|
||||||
|
SubscribeLocalEvent<DVSeenInsertedItemComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
|
||||||
|
SubscribeLocalEvent<DVSeenInsertedItemComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamined(Entity<DVSeenInsertedItemComponent> ent, ref ExaminedEvent args)
|
||||||
|
{
|
||||||
|
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||||
|
if (slot.ContainedEntity is { } contained)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("dv-seen-inserted-item-examined.full", ("container", Identity.Entity(ent, EntityManager, args.Examiner)), ("contained", contained)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("dv-seen-inserted-item-examined.empty", ("container", Identity.Entity(ent, EntityManager, args.Examiner))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRefreshModifiers(Entity<DVSeenInsertedItemComponent> ent, ref RefreshNameModifiersEvent args)
|
||||||
|
{
|
||||||
|
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||||
|
if (slot.ContainedEntity is not { } contained)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.AddModifier("dv-seen-inserted-item-name-modifier", extraArgs: ("contained", contained));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Refresh(Entity<DVSeenInsertedItemComponent> ent)
|
||||||
|
{
|
||||||
|
_nameModifier.RefreshNameModifiers(ent.Owner);
|
||||||
|
|
||||||
|
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||||
|
if (slot.ContainedEntity is { } contained)
|
||||||
|
{
|
||||||
|
var item = Comp<ItemComponent>(contained);
|
||||||
|
_item.CopyVisuals(ent.Owner, item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_item.ClearVisuals(ent.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemInserted(Entity<DVSeenInsertedItemComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||||
|
{
|
||||||
|
if (args.Container.ID != ent.Comp.ItemSlot || _timing.ApplyingState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Refresh(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemRemoved(Entity<DVSeenInsertedItemComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||||
|
{
|
||||||
|
if (args.Container.ID != ent.Comp.ItemSlot || _timing.ApplyingState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Refresh(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,4 +4,4 @@ namespace Content.Shared._DV.Humanoid;
|
|||||||
/// Raised on an entity when their appearance is changed.
|
/// Raised on an entity when their appearance is changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct AppearanceLoadedEvent(Color EyeColor);
|
public record struct AppearanceLoadedEvent(Color EyeColor, Color SkinColor);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Shared._DV.Silicons.Components;
|
|
||||||
|
|
||||||
///<summary>
|
|
||||||
///This components prevents the normal EMP effects on an entity, and makes it take ion damage instead
|
|
||||||
///</summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class SiliconEmpComponent : Component;
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using Content.Shared.Emp;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Damage.Systems;
|
|
||||||
using Content.Shared.Damage.Components;
|
|
||||||
using Content.Shared._DV.Silicons.Components;
|
|
||||||
|
|
||||||
namespace Content.Shared._DV.Silicons;
|
|
||||||
|
|
||||||
public abstract class SharedSiliconEmpSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If the entity has the <see cref="SiliconEmpComponent"/>, then it should take damage instead of draining its battery.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entity">The entity to check</param>
|
|
||||||
/// <returns>true if the entity has <see cref="SiliconEmpComponent"/></returns>
|
|
||||||
public bool ShouldTakeDamageInsteadOfPowerDrain(Entity<SiliconEmpComponent?> entity)
|
|
||||||
{
|
|
||||||
if (!Resolve(entity, ref entity.Comp, false))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SiliconEmpComponent, EmpPulseEvent>(OnEmpPulse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEmpPulse(Entity<SiliconEmpComponent> ent, ref EmpPulseEvent args)
|
|
||||||
{
|
|
||||||
if (args.Damage is not { } damage)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_damageable.TryChangeDamage(ent.Owner, damage, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Alert;
|
||||||
|
|
||||||
|
namespace Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
public sealed partial class AcceptOfferAlertEvent : BaseAlertEvent;
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Inventory.VirtualItem;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||||
|
[Access(typeof(SharedOfferItemSystem))]
|
||||||
|
public sealed partial class OfferItemComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Apparently this indicates whether the entity is currently choosing an entity to offer (right after pressing F).
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
|
||||||
|
public bool IsInOfferMode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this is true, then someone is currently offering an item to this entity, and <see cref="ReceivingFrom"/>
|
||||||
|
/// stores the ID of that entity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool IsInReceiveMode;
|
||||||
|
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public string? Hand;
|
||||||
|
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? Item;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Floofstation note. So, this is EE shitcode, so prepare for an emotional rollercoaster.
|
||||||
|
/// This field can mean TWO things. It's either the target entity this entity is offering an item to,
|
||||||
|
/// or an entity that is offering an item to this entity.
|
||||||
|
/// Whether it's one or the other is distinguished by <see cref="IsInReceiveMode"/>.<br/><br/>
|
||||||
|
///
|
||||||
|
/// In rare cases it can be both. According to my research, if entity A offers an item to entity B, and entity B offers to entity A,
|
||||||
|
/// then both entities will end up in receive mode, and they will have each other as targets. There's a check preventing offer loops
|
||||||
|
/// of length more than 2.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? ReceivingFrom;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public float MaxOfferDistance = 2f;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<AlertPrototype> OfferAlert = "Offer";
|
||||||
|
|
||||||
|
public EntityUid GetRealEntity(EntityManager entityManager) =>
|
||||||
|
entityManager.GetComponentOrNull<VirtualItemComponent>(Item)?.BlockingEntity ?? Item ?? EntityUid.Invalid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A marker component that, when applied to a virtual item, allows it to be offered using item offering.
|
||||||
|
/// Implementors have to listen on ItemTransferredEvent.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[NetworkedComponent]
|
||||||
|
public sealed partial class OfferableVirtualItemComponent : Component;
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
using Content.Shared.Input;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Robust.Shared.Input.Binding;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
public abstract partial class SharedOfferItemSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
||||||
|
|
||||||
|
private void InitializeInteractions()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
CommandBinds.Builder
|
||||||
|
.Bind(ContentKeyFunctions.OfferItem, InputCmdHandler.FromDelegate(SetInOfferMode, handle: false, outsidePrediction: false))
|
||||||
|
.Register<SharedOfferItemSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
|
||||||
|
CommandBinds.Unregister<SharedOfferItemSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This sets IsInOfferMode to true, allowing the player to select whom to offer an item to with interaction.
|
||||||
|
/// </summary>
|
||||||
|
private void SetInOfferMode(ICommonSession? offerer)
|
||||||
|
{
|
||||||
|
if (offerer is not { } playerSession)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (playerSession.AttachedEntity is not { Valid: true } uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Exists(uid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_actionBlocker.CanInteract(uid, null))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<OfferItemComponent>(uid, out var offerItem))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<HandsComponent>(uid, out var hands))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_hands.GetActiveHand((uid, hands)) is not { } activeHandName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_hands.TryGetHeldItem((uid, hands), activeHandName, out var heldItem))
|
||||||
|
return;
|
||||||
|
|
||||||
|
offerItem.Item = heldItem;
|
||||||
|
if (!offerItem.IsInOfferMode)
|
||||||
|
{
|
||||||
|
if (offerItem.Item == null)
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("offer-item-empty-hand"), uid, uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offerItem.Hand == null || offerItem.ReceivingFrom == null)
|
||||||
|
{
|
||||||
|
offerItem.IsInOfferMode = true;
|
||||||
|
offerItem.Hand = activeHandName;
|
||||||
|
|
||||||
|
Dirty(uid, offerItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're already offering an item to someone, cancel that offer
|
||||||
|
if (offerItem.ReceivingFrom != null)
|
||||||
|
{
|
||||||
|
UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
|
||||||
|
offerItem.IsInOfferMode = false;
|
||||||
|
Dirty(uid, offerItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnOffer(uid, offerItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
using Content.Shared._DV.Carrying;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Movement.Pulling.Components;
|
||||||
|
using Content.Shared.Movement.Pulling.Systems;
|
||||||
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
// Dear contributor.
|
||||||
|
// This system is fucking unmaintainable.
|
||||||
|
// If you ever happen to touch this again, please do your best to document your changes and try to resolve mysteries surrounding this code.
|
||||||
|
// I did what I could to document the parts I managed to understand, but there is still more truth to be unveiled.
|
||||||
|
//
|
||||||
|
// HOURS_WASTED_HERE_FLOOFSTATION = 10
|
||||||
|
// HOURS_WASTED_HERE_DELTAV = 1
|
||||||
|
|
||||||
|
namespace Content.Shared._Floof.OfferItem;
|
||||||
|
|
||||||
|
public abstract partial class SharedOfferItemSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
[Dependency] private readonly CarryingSystem _carrying = default!;
|
||||||
|
[Dependency] private readonly PullingSystem _pulling = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<OfferItemComponent, AcceptOfferAlertEvent>(OnAcceptOffer);
|
||||||
|
SubscribeLocalEvent<OfferItemComponent, InteractUsingEvent>(OnInteractWithReceiver, before: [typeof(IngestionSystem)]);
|
||||||
|
SubscribeLocalEvent<OfferableVirtualItemComponent, BeforeRangedInteractEvent>(OnRangedInteractWithReceiver);
|
||||||
|
SubscribeLocalEvent<OfferItemComponent, MoveEvent>(OnMove);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<BeingCarriedComponent, ItemTransferredEvent>(OnCarryTransfer);
|
||||||
|
SubscribeLocalEvent<PullableComponent, ItemTransferredEvent>(OnPulledTransfer);
|
||||||
|
|
||||||
|
InitializeInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<OfferItemComponent, HandsComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var offerItem, out var hands))
|
||||||
|
{
|
||||||
|
// If the mob no longer holds an item in the original offering hand, clear offering mode
|
||||||
|
if (offerItem.Hand != null && !_hands.TryGetHeldItem((uid, hands), offerItem.Hand, out _))
|
||||||
|
{
|
||||||
|
if (offerItem.ReceivingFrom != null)
|
||||||
|
{
|
||||||
|
UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
|
||||||
|
offerItem.IsInOfferMode = false;
|
||||||
|
Dirty(uid, offerItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UnOffer(uid, offerItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!offerItem.IsInReceiveMode)
|
||||||
|
{
|
||||||
|
_alertsSystem.ClearAlert(uid, offerItem.OfferAlert);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_alertsSystem.ShowAlert(uid, offerItem.OfferAlert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
private void OnAcceptOffer(Entity<OfferItemComponent> ent, ref AcceptOfferAlertEvent args)
|
||||||
|
{
|
||||||
|
Receive((ent, ent.Comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractWithReceiver(Entity<OfferItemComponent> receiver, ref InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (!_timing.IsFirstTimePredicted || _timing.ApplyingState || args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<OfferItemComponent>(args.User, out var offererComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = CreateOffer(receiver, (args.User, offererComponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRangedInteractWithReceiver(Entity<OfferableVirtualItemComponent> virtItem, ref BeforeRangedInteractEvent args)
|
||||||
|
{
|
||||||
|
// If the entity being offered is a virtual item, InteractUsing will not be raised
|
||||||
|
// because virtual items exclude themselves from being marked as used
|
||||||
|
// If this is the case, InteractHand will be raised instead, which we can use anyway because OfferItem.Item stores the offered item
|
||||||
|
//
|
||||||
|
// We also can't check Handled here because VirtualItemSystem handles it, ffs
|
||||||
|
// This won't lead you to accidentally offering someone your gun
|
||||||
|
//
|
||||||
|
// This is shitcode, this time my shitcode. My changes to the offering system allow you to transfer carrying and pulling,
|
||||||
|
// but in order to handle these, we need to be able to intercept interactions with virtual items.
|
||||||
|
//
|
||||||
|
// Ideally this code should be rewritten to:
|
||||||
|
// a) Have each different virtual item have a distinct component (e.g. CarryingVirtualItem) which would allow to distinguish them from the rest
|
||||||
|
// b) Not rely on the InteractionSystem.
|
||||||
|
// However, I'm not in the mood to do either. And I'm too deep into the rabbit hole of getting this shit to work.
|
||||||
|
if (!_timing.IsFirstTimePredicted || _timing.ApplyingState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var receiver = args.Target;
|
||||||
|
if (!TryComp<OfferItemComponent>(receiver, out var receiverComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var offerer = args.User;
|
||||||
|
if (!TryComp<OfferItemComponent>(offerer, out var offererComponent) || offererComponent.Item == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Since this is ranged, we must also check distance, because the interaction system wont check it for us in this case
|
||||||
|
if (!Transform(offerer).Coordinates.TryDistance(EntityManager, _transform, Transform(receiver.Value).Coordinates, out var dst)
|
||||||
|
|| dst > offererComponent.MaxOfferDistance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = CreateOffer((receiver.Value, receiverComponent), (offerer, offererComponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMove(EntityUid uid, OfferItemComponent component, MoveEvent args)
|
||||||
|
{
|
||||||
|
if (_net.IsClient) // Client often mispredicts movement, we cant trust it here
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.ReceivingFrom == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_transform.InRange(args.NewPosition, Transform(component.ReceivingFrom.Value).Coordinates, component.MaxOfferDistance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
UnOffer(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCarryTransfer(Entity<BeingCarriedComponent> ent, ref ItemTransferredEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled
|
||||||
|
|| args.PassedItem == args.RealItem // Means the entity is transferred NOT via carrying
|
||||||
|
|| args.RealItem is not { Valid: true } carried
|
||||||
|
|| ent.Comp.Carrier is not { Valid: true } oldCarrier)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_carrying.DropCarried(oldCarrier, ent);
|
||||||
|
args.Handled = _carrying.TryCarry(args.Target, carried);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPulledTransfer(Entity<PullableComponent> ent, ref ItemTransferredEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled
|
||||||
|
|| args.PassedItem == args.RealItem // Means the entity is transferred NOT via pulling
|
||||||
|
|| args.RealItem is not { Valid: true } pulled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_pulling.TryStopPull(pulled, ent);
|
||||||
|
args.Handled = _pulling.TryStartPull(args.Target, ent, null, ent.Comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Offering / Recieving
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to create an offer. Expects offerer.Item to already be set to the offered item, offererComponent.InReceiveMode == true.
|
||||||
|
/// Will fail if offerer == receiver or if receiver already has a set TargetOrOfferer, and that person is not the current offerer
|
||||||
|
/// </summary>
|
||||||
|
private bool CreateOffer(Entity<OfferItemComponent> receiver, Entity<OfferItemComponent> offerer)
|
||||||
|
{
|
||||||
|
var offererComponent = offerer.Comp;
|
||||||
|
var receiverComponent = receiver.Comp;
|
||||||
|
if (offerer == receiver || receiverComponent.IsInReceiveMode || !offererComponent.IsInOfferMode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (offererComponent.IsInReceiveMode && offererComponent.ReceivingFrom != receiver)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
receiverComponent.IsInReceiveMode = true;
|
||||||
|
receiverComponent.ReceivingFrom = offerer;
|
||||||
|
|
||||||
|
Dirty(receiver, receiverComponent);
|
||||||
|
|
||||||
|
offererComponent.ReceivingFrom = receiver; // TODO this is ee shitcode, may not be necessary?
|
||||||
|
offererComponent.IsInOfferMode = false;
|
||||||
|
|
||||||
|
Dirty(offerer, offererComponent);
|
||||||
|
|
||||||
|
if (offererComponent.Item == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Sender popup (client-side only)
|
||||||
|
_popup.PopupClient(
|
||||||
|
Loc.GetString("offer-item-try-give",
|
||||||
|
("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager)),
|
||||||
|
("target", Identity.Entity(receiver, EntityManager))),
|
||||||
|
offerer,
|
||||||
|
offerer);
|
||||||
|
// Receiver popup (server side only, not predicted because recipient != local player)
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-try-give-target",
|
||||||
|
("user", Identity.Entity(receiverComponent.ReceivingFrom.Value, EntityManager)),
|
||||||
|
("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager))),
|
||||||
|
offerer,
|
||||||
|
receiver,
|
||||||
|
Popups.PopupType.Medium);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the <see cref="OfferItemComponent"/> of the user and the target
|
||||||
|
/// </summary>
|
||||||
|
protected void UnOffer(EntityUid thisEntity, OfferItemComponent offererComp)
|
||||||
|
{
|
||||||
|
if (!TryComp<HandsComponent>(thisEntity, out var hands) || _hands.GetActiveHand((thisEntity, hands)) is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (offererComp.ReceivingFrom is { } otherEntity && TryComp<OfferItemComponent>(otherEntity, out var otherOfferer))
|
||||||
|
{
|
||||||
|
// So this tries to figure out which of these entities do what...
|
||||||
|
// if A.OfferItemComponent.Item != null, then A is currently offering an item to A.OfferItemComponent.TargetOrOfferer
|
||||||
|
// If it is null, then it is ONLY being offered an item TO.
|
||||||
|
if (offererComp.Item != null && _net.IsServer)
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-no-give",
|
||||||
|
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||||
|
("target", Identity.Entity(otherEntity, EntityManager))),
|
||||||
|
thisEntity,
|
||||||
|
thisEntity);
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-no-give-target",
|
||||||
|
("user", Identity.Entity(thisEntity, EntityManager)),
|
||||||
|
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
|
||||||
|
thisEntity,
|
||||||
|
otherEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (otherOfferer.Item != null && _net.IsServer)
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-no-give",
|
||||||
|
("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||||
|
("target", Identity.Entity(thisEntity, EntityManager))),
|
||||||
|
otherEntity,
|
||||||
|
otherEntity);
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-no-give-target",
|
||||||
|
("user", Identity.Entity(otherEntity, EntityManager)),
|
||||||
|
("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager))),
|
||||||
|
otherEntity,
|
||||||
|
thisEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
otherOfferer.IsInOfferMode = false;
|
||||||
|
otherOfferer.IsInReceiveMode = false;
|
||||||
|
otherOfferer.Hand = null;
|
||||||
|
otherOfferer.ReceivingFrom = null;
|
||||||
|
otherOfferer.Item = null;
|
||||||
|
|
||||||
|
Dirty(otherEntity, otherOfferer);
|
||||||
|
}
|
||||||
|
|
||||||
|
offererComp.IsInOfferMode = false;
|
||||||
|
offererComp.IsInReceiveMode = false;
|
||||||
|
offererComp.Hand = null;
|
||||||
|
offererComp.ReceivingFrom = null;
|
||||||
|
offererComp.Item = null;
|
||||||
|
|
||||||
|
Dirty(thisEntity, offererComp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancels the transfer of the item
|
||||||
|
/// </summary>
|
||||||
|
protected void UnReceive(EntityUid receiver, OfferItemComponent? receiverComp = null, OfferItemComponent? offererComp = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(receiver, ref receiverComp)
|
||||||
|
|| receiverComp.ReceivingFrom is not {} offerer
|
||||||
|
|| !Resolve(offerer, ref offererComp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Idk why this check is here
|
||||||
|
if (!TryComp<HandsComponent>(receiver, out var hands) || _hands.GetActiveHand((receiver, hands)) == null || receiverComp.ReceivingFrom == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If offererComp.Item != null, then they are actively offering to TargetOrOfferer
|
||||||
|
// Normally this method is called right after a transfer is done, but this part can be called from SetInOfferMode when the player presses F again to cancel an ongoing offer
|
||||||
|
if (offererComp.Item != null)
|
||||||
|
{
|
||||||
|
_popup.PopupClient(
|
||||||
|
Loc.GetString("offer-item-no-give",
|
||||||
|
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||||
|
("target", Identity.Entity(receiver, EntityManager))),
|
||||||
|
offerer,
|
||||||
|
offerer);
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-no-give-target",
|
||||||
|
("user", Identity.Entity(receiverComp.ReceivingFrom.Value, EntityManager)), // Floof - resolve virtual items
|
||||||
|
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
|
||||||
|
offerer,
|
||||||
|
receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!offererComp.IsInReceiveMode)
|
||||||
|
{
|
||||||
|
offererComp.ReceivingFrom = null;
|
||||||
|
receiverComp.ReceivingFrom = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
offererComp.Item = null;
|
||||||
|
offererComp.Hand = null;
|
||||||
|
receiverComp.IsInReceiveMode = false;
|
||||||
|
|
||||||
|
Dirty(receiver, receiverComp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accepting the offer and receive item
|
||||||
|
/// </summary>
|
||||||
|
public void Receive(Entity<OfferItemComponent?> receiver)
|
||||||
|
{
|
||||||
|
if (!_timing.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Resolve(receiver, ref receiver.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<OfferItemComponent>(receiver.Comp.ReceivingFrom, out var offererComponent) ||
|
||||||
|
offererComponent.Hand == null ||
|
||||||
|
receiver.Comp.ReceivingFrom is not {} sender ||
|
||||||
|
!TryComp<HandsComponent>(receiver, out var hands))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (offererComponent.Item != null)
|
||||||
|
{
|
||||||
|
// Floof - check if there's something else handling it first
|
||||||
|
var realItem = offererComponent.GetRealEntity(EntityManager);
|
||||||
|
if (!TryHandleExtendedTransfer(sender, receiver, offererComponent.Item.Value, realItem)
|
||||||
|
&& !_hands.TryPickup(receiver, offererComponent.Item.Value, handsComp: hands))
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("offer-item-full-hand"), receiver, receiver);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-give",
|
||||||
|
("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
|
||||||
|
("target", Identity.Entity(receiver, EntityManager))),
|
||||||
|
sender,
|
||||||
|
sender);
|
||||||
|
_popup.PopupEntity(
|
||||||
|
Loc.GetString("offer-item-give-other",
|
||||||
|
("user", Identity.Entity(receiver.Comp.ReceivingFrom.Value, EntityManager)),
|
||||||
|
("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
|
||||||
|
("target", Identity.Entity(receiver, EntityManager))),
|
||||||
|
sender,
|
||||||
|
Filter.PvsExcept(sender, entityManager: EntityManager),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
offererComponent.Item = null;
|
||||||
|
UnReceive(receiver, receiver.Comp, offererComponent);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if <see cref="OfferItemComponent.IsInOfferMode"/> = true
|
||||||
|
/// </summary>
|
||||||
|
protected bool IsInOfferMode(Entity<OfferItemComponent?> ent)
|
||||||
|
{
|
||||||
|
return Resolve(ent, ref ent.Comp, false) && ent.Comp.IsInOfferMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryHandleExtendedTransfer(EntityUid user, EntityUid target, EntityUid offeredItem, EntityUid realItem)
|
||||||
|
{
|
||||||
|
var ev = new ItemTransferredEvent
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
Target = target,
|
||||||
|
PassedItem = offeredItem,
|
||||||
|
RealItem = realItem,
|
||||||
|
};
|
||||||
|
RaiseLocalEvent(realItem, ref ev);
|
||||||
|
return ev.Handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on the entity that was transferred via item offering.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public sealed class ItemTransferredEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid User;
|
||||||
|
public EntityUid Target;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The actual item being passed around. Can be a virtual item.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid PassedItem;
|
||||||
|
/// <summary>
|
||||||
|
/// If <see cref="PassedItem"/> is a virtual item, this field contains the real item that was transferred.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid? RealItem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Clothing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds examine text to the entity that wears item, for making things obvious.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(WearerGetsExamineTextSystem))]
|
||||||
|
public sealed partial class WearerGetsExamineTextComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The LocId that specifies what category of object this is.
|
||||||
|
/// i.e. "pin" or "scarf"
|
||||||
|
/// Should be redefined on a per-category basis, naturally.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("thing")]
|
||||||
|
public LocId Category = "obvious-thing-default";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The LocId that specifies what member of the category this is.
|
||||||
|
/// i.e. "lesbian pride"
|
||||||
|
/// Can be used to define text colors that are copied to all things
|
||||||
|
/// which share this specifier (i.e. the other items of the same pride).
|
||||||
|
/// (And summarily, makes accessibility-based changes for these colors a cinch.)
|
||||||
|
/// Should be defined by each thing that has this component.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("thingType")]
|
||||||
|
public LocId Specifier = "obvious-type-default";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The LocId that will be added to any wearing entity's examination.
|
||||||
|
/// Typically only needs redefining on a per-category basis,
|
||||||
|
/// but items that should have totally-unique obvious text can simply specify them here.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("examineText", required: true)]
|
||||||
|
public LocId ExamineOnWearer = "obvious-desc-default";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to the entity wearing this clothing.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? Wearer;
|
||||||
|
/// <summary>
|
||||||
|
/// The string that is attached to this item's ExamineOnWearer.
|
||||||
|
/// Typically doesn't need to be redefined.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId PrefixExamineOnWearer = "obvious-prefix-wearing";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, an entity with this item in any slot (i.e. in pockets) will gain the examine text,
|
||||||
|
/// instead of when just equipped as clothing.
|
||||||
|
/// Should be used sparingly only when truly appropriate; this is effectively a half-measure for lack of a special pin slot.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool PocketEvident;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the entity's description will inform examiners what others will see on the wearer (before they equip it).
|
||||||
|
/// If the item is contraband, the item will also warn that displaying it may cause undue attention.
|
||||||
|
/// Keep this false for good-natured jokes (i.e. the pride cloaks having funny, non-pride names)
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool WarnExamine = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using Content.Shared.Clothing.Components;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Content.Shared.Contraband;
|
||||||
|
using Content.Shared._Impstation.Examine;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Clothing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds examine text to the entity that wears item, for making things obvious.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class WearerGetsExamineTextSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<WearerGetsExamineTextComponent, GotEquippedEvent>(OnEquipped);
|
||||||
|
SubscribeLocalEvent<WearerGetsExamineTextComponent, GotUnequippedEvent>(OnUnequipped);
|
||||||
|
SubscribeLocalEvent<WearerGetsExamineTextComponent, ExaminedEvent>(OnExamine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEquipped(Entity<WearerGetsExamineTextComponent> entity, ref GotEquippedEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp(entity, out ClothingComponent? clothing))
|
||||||
|
return;
|
||||||
|
var isCorrectSlot = (clothing.Slots & args.SlotFlags) != Inventory.SlotFlags.NONE;
|
||||||
|
if (!entity.Comp.PocketEvident) //if it can't be evident in our pockets
|
||||||
|
{
|
||||||
|
// Make sure the clothing item was equipped to the right slot, and not just held in a hand.
|
||||||
|
if (!isCorrectSlot)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Comp.Wearer = args.Equipee;
|
||||||
|
Dirty(entity);
|
||||||
|
|
||||||
|
//GIVE THEM INSPECT TEXT
|
||||||
|
var obviousExamine = EnsureComp<ExtraExamineTextComponent>(args.Equipee);
|
||||||
|
obviousExamine.Lines.TryAdd(entity.Owner, //using try so that we don't cause an error if we move something from slot to slot
|
||||||
|
ConstructExamineText(entity, !isCorrectSlot, args.Equipee));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string ConstructExamineText(Entity<WearerGetsExamineTextComponent> entity, bool prefixFallback, EntityUid affecting)
|
||||||
|
{
|
||||||
|
//parameters (these are the same between both constructions)
|
||||||
|
var user = Identity.Entity(affecting, EntityManager);
|
||||||
|
var nomen = Identity.Name(affecting, EntityManager);
|
||||||
|
var thing = Loc.GetString(entity.Comp.Category);
|
||||||
|
var type = Loc.GetString(entity.Comp.Specifier);
|
||||||
|
var stringSpec = entity.Comp.Specifier.ToString();
|
||||||
|
var shortType = stringSpec.Substring(stringSpec.LastIndexOf('-')); // necessary for working with colored text...
|
||||||
|
|
||||||
|
var prefix = Loc.GetString(prefixFallback ? "obvious-prefix-default" : entity.Comp.PrefixExamineOnWearer, // uses a different prefix if worn / displayed
|
||||||
|
("user", user),
|
||||||
|
("name", nomen),
|
||||||
|
("thing", thing),
|
||||||
|
("type", type));
|
||||||
|
var suffix = Loc.GetString(entity.Comp.ExamineOnWearer,
|
||||||
|
("user", user),
|
||||||
|
("name", nomen),
|
||||||
|
("thing", thing),
|
||||||
|
("type", type),
|
||||||
|
("short-type", shortType));
|
||||||
|
return prefix + " " + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnequipped(Entity<WearerGetsExamineTextComponent> entity, ref GotUnequippedEvent args)
|
||||||
|
{
|
||||||
|
if (entity.Comp.Wearer is not { } wearer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp(wearer, out ExtraExamineTextComponent? obviousExamine))
|
||||||
|
{
|
||||||
|
obviousExamine.Lines.Remove(entity.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Comp.Wearer = null;
|
||||||
|
Dirty(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(Entity<WearerGetsExamineTextComponent> entity, ref ExaminedEvent args)
|
||||||
|
{
|
||||||
|
var currentlyWorn = entity.Comp.Wearer != null;
|
||||||
|
var outString = new StringBuilder(Loc.GetString(currentlyWorn ? "obvious-on-item-currently" : "obvious-on-item",
|
||||||
|
("used", Loc.GetString(entity.Comp.PocketEvident ? "obvious-reveal-pockets" : "obvious-reveal-default")),
|
||||||
|
("thing", entity.Comp.Category),
|
||||||
|
("me", Identity.Entity(entity, EntityManager))));
|
||||||
|
|
||||||
|
if (entity.Comp.WarnExamine)
|
||||||
|
{
|
||||||
|
if (!currentlyWorn && TryComp(entity, out ContrabandComponent? contra)) // if the item's contra and we're not wearing it yet
|
||||||
|
{
|
||||||
|
var contraLocId = "obvious-on-item-contra-" + contra.Severity; // apply additional text if the item is contraband to note that displaying it might be really bad
|
||||||
|
if (Loc.HasString(contraLocId)) // saves us the trouble of making a switch block for this
|
||||||
|
outString.Append(" " + Loc.GetString(contraLocId));
|
||||||
|
}
|
||||||
|
var affecting = currentlyWorn ? entity.Comp.Wearer.GetValueOrDefault() : args.Examiner;
|
||||||
|
var testOut = ConstructExamineText(entity, false, affecting);
|
||||||
|
|
||||||
|
outString.Append("\n" + Loc.GetString("obvious-on-item-for-others",
|
||||||
|
("will", currentlyWorn ? "can" : "will"), // i love hardcoding strings it's my favorite thing ever
|
||||||
|
("output", testOut)));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.PushMarkup(outString.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Examine;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class DetailedInspectComponent : Component
|
||||||
|
{
|
||||||
|
[DataField]
|
||||||
|
public LocId VerbText = "verbs-detailed-inspect";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public LocId VerbMessage = "verbs-detailed-inspect-message";
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public List<LocId> ExamineText;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the entries in ExamineText are separated by linebreaks.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool LineBreak = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the entries in ExamineText are preceded by ticks.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool TickEntries = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not entries in the list are numbered.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool NumberedEntries = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rooted directory of the icon for the verb.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string Icon = "/Textures/Interface/VerbIcons/dot.svg.192dpi.png";
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Examine;
|
||||||
|
|
||||||
|
public sealed partial class DetailedInspectSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
|
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DetailedInspectComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGetVerb(Entity<DetailedInspectComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanInteract || !args.CanAccess || !_net.IsServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var msg = new FormattedMessage();
|
||||||
|
var numberedIndex = 1;
|
||||||
|
|
||||||
|
foreach (var locId in ent.Comp.ExamineText)
|
||||||
|
{
|
||||||
|
if (ent.Comp.TickEntries)
|
||||||
|
msg.AddMarkupOrThrow("- ");
|
||||||
|
|
||||||
|
if (ent.Comp.NumberedEntries)
|
||||||
|
{
|
||||||
|
msg.AddMarkupOrThrow($"{numberedIndex}. ");
|
||||||
|
numberedIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.AddMarkupOrThrow(Loc.GetString(locId));
|
||||||
|
|
||||||
|
if (ent.Comp.LineBreak)
|
||||||
|
msg.PushNewline();
|
||||||
|
else
|
||||||
|
msg.AddMarkupOrThrow(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_examine.AddDetailedExamineVerb(args, ent.Comp, msg, Loc.GetString(ent.Comp.VerbText), ent.Comp.Icon, Loc.GetString(ent.Comp.VerbMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Content.Shared._Impstation.Clothing;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Examine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds examine text to the entity, intentionally "obvious details".
|
||||||
|
/// Like, that's it. It's basic -- all it does is add the lines to the attached entity.
|
||||||
|
/// This is particularly used for assigning players unique examine text.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(ExtraExamineTextSystem), typeof(WearerGetsExamineTextSystem))]
|
||||||
|
public sealed partial class ExtraExamineTextComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The LocIds that will be added to the attached entity's examination.
|
||||||
|
///
|
||||||
|
/// The key is the source of the line, and the value is the text
|
||||||
|
/// (built by the component that creates this one).
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Dictionary<EntityUid, LocId> Lines { get; set; } = new();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
|
||||||
|
namespace Content.Shared._Impstation.Examine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds examine text to the entity, intentionally "obvious details".
|
||||||
|
/// Like, that's it. It's basic -- all it does is add the line to the attached entity.
|
||||||
|
/// This is particularly used for assigning players unique examine text.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ExtraExamineTextSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ExtraExamineTextComponent, ExaminedEvent>(OnExamine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(Entity<ExtraExamineTextComponent> entity, ref ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (entity.Comp.Lines.Count == 0)
|
||||||
|
{
|
||||||
|
RemCompDeferred<ExtraExamineTextComponent>(entity); // no more need for me!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var l in entity.Comp.Lines)
|
||||||
|
{
|
||||||
|
args.PushMarkup(l.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Content.Shared._Starlight.Flash.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class FlashModifierComponent : Component
|
||||||
|
{
|
||||||
|
[DataField]
|
||||||
|
public float Modifier = 1f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
namespace Content.Shared.Humanoid;
|
||||||
|
|
||||||
|
public static class EyeColor
|
||||||
|
{
|
||||||
|
public const float ShadekinBrightness = 0.251f;
|
||||||
|
|
||||||
|
public static bool VerifyShadekin(Color color)
|
||||||
|
{
|
||||||
|
var colorHsv = Color.ToHsv(color);
|
||||||
|
|
||||||
|
if (colorHsv.Z > ShadekinBrightness)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color MakeShadekinValid(Color color)
|
||||||
|
{
|
||||||
|
var hsv = Color.ToHsv(color);
|
||||||
|
|
||||||
|
hsv.Z = Math.Clamp(hsv.Z, 0, ShadekinBrightness);
|
||||||
|
|
||||||
|
return Color.FromHsv(hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool VerifyEyeColor(HumanoidEyeColor type, Color color)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
HumanoidEyeColor.Shadekin => VerifyShadekin(color),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color ValidEyeColor(HumanoidEyeColor type, Color color)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
HumanoidEyeColor.Shadekin => MakeShadekinValid(color),
|
||||||
|
_ => color
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HumanoidEyeColor : byte
|
||||||
|
{
|
||||||
|
Shadekin,
|
||||||
|
}
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct EyeColorInitEvent();
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared._Starlight;
|
||||||
|
|
||||||
|
#region Shadekin
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause, AutoGenerateComponentState]
|
||||||
|
public sealed partial class ShadekinComponent : Component
|
||||||
|
{
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<AlertPrototype> ShadekinAlert = "Shadekin";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly), AutoPausedField]
|
||||||
|
public TimeSpan NextUpdate = TimeSpan.Zero;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan UpdateCooldown = TimeSpan.FromSeconds(1f);
|
||||||
|
|
||||||
|
[AutoNetworkedField, ViewVariables]
|
||||||
|
public ShadekinState CurrentState { get; set; } = ShadekinState.Dark;
|
||||||
|
|
||||||
|
[DataField("thresholds", required: true)]
|
||||||
|
public SortedDictionary<FixedPoint2, ShadekinState> Thresholds = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// whether to flicker lights or not. default on
|
||||||
|
/// </summary>
|
||||||
|
[DataField] public bool DoLightFlicker = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum ShadekinState : byte
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
Dark = 1,
|
||||||
|
Low = 2,
|
||||||
|
Annoying = 3,
|
||||||
|
High = 4,
|
||||||
|
Extreme = 5
|
||||||
|
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
- files: ["beep_500.ogg"]
|
||||||
|
license: "CC0-1.0"
|
||||||
|
copyright: "Synthesized in Audacity by BasedUser."
|
||||||
|
source: "https://github.com/ekrixi-14/ekrixi"
|
||||||
|
|
||||||
|
- files: ["whirr1.ogg", "whirr2.ogg", "whirr3.ogg"]
|
||||||
|
license: "CC0-1.0"
|
||||||
|
copyright: "Taken from source, spectrally modified and clipped"
|
||||||
|
source: "https://freesound.org/people/sad3d/sounds/500168/"
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,29 @@
|
|||||||
|
- files: ["wurble.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/wurble.ogg"
|
||||||
|
|
||||||
|
- files: ["mar.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/mar.ogg"
|
||||||
|
|
||||||
|
- files: ["scream_f1.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken and remixed from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f1.ogg"
|
||||||
|
|
||||||
|
- files: ["scream_f2.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken and remixed from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f2.ogg"
|
||||||
|
|
||||||
|
- files: ["scream_m1.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken and remixed from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_m1.ogg"
|
||||||
|
|
||||||
|
- files: ["scream_m2.ogg"]
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken and remixed from CHOMPStation"
|
||||||
|
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f2.ogg"
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -332,5 +332,21 @@ Entries:
|
|||||||
id: 36
|
id: 36
|
||||||
time: '2026-06-16T20:02:18.0000000+00:00'
|
time: '2026-06-16T20:02:18.0000000+00:00'
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6006
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6006
|
||||||
|
- author: einknusprigestoast
|
||||||
|
changes:
|
||||||
|
- message: Changed SRT loadouts
|
||||||
|
type: Tweak
|
||||||
|
- message: Added the eviscerator, a ERT-/SRT-issued heavy plasma rifle.
|
||||||
|
type: Add
|
||||||
|
id: 37
|
||||||
|
time: '2026-07-13T13:44:06.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6233
|
||||||
|
- author: einknusprigestoast
|
||||||
|
changes:
|
||||||
|
- message: The white dragon has been spotted in the sector.
|
||||||
|
type: Add
|
||||||
|
id: 38
|
||||||
|
time: '2026-07-19T16:18:47.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6317
|
||||||
Name: DeltaVAdmin
|
Name: DeltaVAdmin
|
||||||
Order: 5
|
Order: 5
|
||||||
|
|||||||
@@ -1,452 +1,4 @@
|
|||||||
Entries:
|
Entries:
|
||||||
- author: kotobdev
|
|
||||||
changes:
|
|
||||||
- message: Flashlights will now always point towards your cursor in combat mode.
|
|
||||||
type: Add
|
|
||||||
id: 2034
|
|
||||||
time: '2026-01-08T17:11:25.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5163
|
|
||||||
- author: ShepardToTheStars
|
|
||||||
changes:
|
|
||||||
- message: Redrock spawns a bit further out until we can figure out why its spawning
|
|
||||||
inside the station.
|
|
||||||
type: Tweak
|
|
||||||
id: 2035
|
|
||||||
time: '2026-01-08T20:53:31.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5166
|
|
||||||
- author: PureBreadBagel
|
|
||||||
changes:
|
|
||||||
- message: You are now able to craft the makeshift and forged varient of the omnitool!
|
|
||||||
type: Fix
|
|
||||||
- message: The makeshift/forged varient of the omnitool should no longer display
|
|
||||||
"verb-categories-switch" in its right click menu.
|
|
||||||
type: Fix
|
|
||||||
id: 2036
|
|
||||||
time: '2026-01-09T16:34:26.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5165
|
|
||||||
- author: MilonPL
|
|
||||||
changes:
|
|
||||||
- message: Picking senior PDAs in the loadout will now change your job name accordingly
|
|
||||||
once again.
|
|
||||||
type: Fix
|
|
||||||
id: 2037
|
|
||||||
time: '2026-01-10T16:48:59.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5176
|
|
||||||
- author: Eternally-Confused
|
|
||||||
changes:
|
|
||||||
- message: The announcement for the Spare Captain's ID no longer references crimes
|
|
||||||
that don't exist
|
|
||||||
type: Fix
|
|
||||||
id: 2038
|
|
||||||
time: '2026-01-10T21:42:58.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5177
|
|
||||||
- author: Eternally-Confused
|
|
||||||
changes:
|
|
||||||
- message: Feroxi nukies now recieve actual syndicate survival boxes.
|
|
||||||
type: Fix
|
|
||||||
id: 2039
|
|
||||||
time: '2026-01-10T21:43:51.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5179
|
|
||||||
- author: FaintSpeaker
|
|
||||||
changes:
|
|
||||||
- message: Fix for one error possibly causing replays to fail to load. Continue
|
|
||||||
to report any broken replays after this fix!
|
|
||||||
type: Fix
|
|
||||||
id: 2040
|
|
||||||
time: '2026-01-10T21:44:55.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5173
|
|
||||||
- author: snowywinters
|
|
||||||
changes:
|
|
||||||
- message: The station AI is now better integrated into the station allowing use
|
|
||||||
of fabs and substations/SMES
|
|
||||||
type: Add
|
|
||||||
id: 2041
|
|
||||||
time: '2026-01-10T21:58:12.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5132
|
|
||||||
- author: FaintSpeaker
|
|
||||||
changes:
|
|
||||||
- message: Adv. Cleaning Cyborg Module now regenerates Space Cleaner.
|
|
||||||
type: Add
|
|
||||||
id: 2042
|
|
||||||
time: '2026-01-10T22:07:44.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5155
|
|
||||||
- author: ShepardToTheStars, Toby222
|
|
||||||
changes:
|
|
||||||
- message: Fixed feroxi paramedic and goliath hardsuit helmet sprites displaying
|
|
||||||
the incorrect sprite.
|
|
||||||
type: Fix
|
|
||||||
id: 2043
|
|
||||||
time: '2026-01-10T22:07:30.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5161
|
|
||||||
- author: keekee38
|
|
||||||
changes:
|
|
||||||
- message: Increased minimum player count for nukies to 20 ready and 40 total players.
|
|
||||||
type: Tweak
|
|
||||||
id: 2044
|
|
||||||
time: '2026-01-10T23:06:04.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5159
|
|
||||||
- author: MilonPL
|
|
||||||
changes:
|
|
||||||
- message: Fixed emergency jaws of life not draining their battery when prying doors.
|
|
||||||
type: Fix
|
|
||||||
id: 2045
|
|
||||||
time: '2026-01-11T15:34:44.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5189
|
|
||||||
- author: ShepardToTheStars
|
|
||||||
changes:
|
|
||||||
- message: Crawling or being knocked down no longer nerfs your melee damage by 75%.
|
|
||||||
You will do the normal amount of melee damage now.
|
|
||||||
type: Tweak
|
|
||||||
id: 2046
|
|
||||||
time: '2026-01-11T15:38:24.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5182
|
|
||||||
- author: ShepardToTheStars
|
|
||||||
changes:
|
|
||||||
- message: The spare ID will always unlock 15 seconds after nukies declare war,
|
|
||||||
even if there is a captain.
|
|
||||||
type: Tweak
|
|
||||||
id: 2047
|
|
||||||
time: '2026-01-11T15:40:02.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5104
|
|
||||||
- author: Pharaz4
|
|
||||||
changes:
|
|
||||||
- message: Added Skia to guidebook.
|
|
||||||
type: Add
|
|
||||||
- message: Fixed some typos and a page on guidebook.
|
|
||||||
type: Fix
|
|
||||||
id: 2048
|
|
||||||
time: '2026-01-11T16:27:06.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5178
|
|
||||||
- author: Minerva
|
|
||||||
changes:
|
|
||||||
- message: Crash carts can now be ordered from Logistics under the Medical category.
|
|
||||||
type: Add
|
|
||||||
id: 2049
|
|
||||||
time: '2026-01-11T16:43:30.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5190
|
|
||||||
- author: DisposableCrewmember42
|
|
||||||
changes:
|
|
||||||
- message: The revenant can use its Haunt ability again
|
|
||||||
type: Fix
|
|
||||||
id: 2050
|
|
||||||
time: '2026-01-11T19:48:58.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5124
|
|
||||||
- author: DisposableCrewmember42
|
|
||||||
changes:
|
|
||||||
- message: The Revenant can no longer be killed by spiking your own water bottle.
|
|
||||||
type: Fix
|
|
||||||
id: 2051
|
|
||||||
time: '2026-01-11T19:57:38.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5125
|
|
||||||
- author: Apachito
|
|
||||||
changes:
|
|
||||||
- message: Moved the craftable armor to the clothing tab in the crafting menu
|
|
||||||
type: Tweak
|
|
||||||
- message: Reduced firerate on the forged smg from 5 to 4.5
|
|
||||||
type: Tweak
|
|
||||||
- message: Made improvised ammo do 75% damage compared to their normal counterparts
|
|
||||||
type: Tweak
|
|
||||||
id: 2052
|
|
||||||
time: '2026-01-11T22:08:13.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5129
|
|
||||||
- author: Unkn0wnGh0st333
|
|
||||||
changes:
|
|
||||||
- message: Gulp Emote from Goob has been added... gulp...
|
|
||||||
type: Add
|
|
||||||
id: 2053
|
|
||||||
time: '2026-01-12T04:42:07.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5033
|
|
||||||
- author: Velcroboy
|
|
||||||
changes:
|
|
||||||
- message: Tanks of ammonia are now purchasable from logi for mixing more space
|
|
||||||
cleaner or making the station stinky
|
|
||||||
type: Add
|
|
||||||
id: 2054
|
|
||||||
time: '2026-01-13T05:00:57.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5167
|
|
||||||
- author: Pharaz4
|
|
||||||
changes:
|
|
||||||
- message: Syndicate Assault, Medical, and Saboteur borgs now get names.
|
|
||||||
type: Add
|
|
||||||
- message: Fixed SRN Saboteur borg not being able to fit Engineering module
|
|
||||||
type: Fix
|
|
||||||
id: 2055
|
|
||||||
time: '2026-01-14T13:23:22.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5197
|
|
||||||
- author: MilonPL
|
|
||||||
changes:
|
|
||||||
- message: Added a dynamic tip system that shows contextual tips to players based
|
|
||||||
on their job, playtime, and more.
|
|
||||||
type: Add
|
|
||||||
- message: Tips can be disabled or reset in the Options menu under DeltaV.
|
|
||||||
type: Add
|
|
||||||
id: 2056
|
|
||||||
time: '2026-01-14T20:23:40.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5199
|
|
||||||
- author: Velcroboy
|
|
||||||
changes:
|
|
||||||
- message: Fixed bomb and effigy targets being on grids off the station sometimes.
|
|
||||||
type: Fix
|
|
||||||
id: 2057
|
|
||||||
time: '2026-01-15T07:29:44.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5213
|
|
||||||
- author: Pharaz4
|
|
||||||
changes:
|
|
||||||
- message: Hard hats are now protective!
|
|
||||||
type: Tweak
|
|
||||||
id: 2058
|
|
||||||
time: '2026-01-15T15:44:57.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5175
|
|
||||||
- author: Halo3moth
|
|
||||||
changes:
|
|
||||||
- message: The hos locker will now spawn with a briefcase that allows them to pick
|
|
||||||
between sidearms.
|
|
||||||
type: Add
|
|
||||||
- message: The energy magnum now also works for the hos steal objective.
|
|
||||||
type: Tweak
|
|
||||||
- message: Energy magnum standard bolt from 20 heat to 24 and magnum bolt from 30
|
|
||||||
heat to 24 heat and 11 pierce.
|
|
||||||
type: Tweak
|
|
||||||
id: 2059
|
|
||||||
time: '2026-01-16T17:46:17.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5203
|
|
||||||
- author: mnva0
|
|
||||||
changes:
|
|
||||||
- message: Ovinia now start with a emergency survival box.
|
|
||||||
type: Fix
|
|
||||||
id: 2060
|
|
||||||
time: '2026-01-16T17:55:22.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5207
|
|
||||||
- author: Halo3moth
|
|
||||||
changes:
|
|
||||||
- message: Re-added the graytide stamp to maints lockers.
|
|
||||||
type: Add
|
|
||||||
- message: Tweak some of the spawn rates for meme items in maints lockers.
|
|
||||||
type: Tweak
|
|
||||||
id: 2061
|
|
||||||
time: '2026-01-16T17:58:01.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5221
|
|
||||||
- author: Pharaz4
|
|
||||||
changes:
|
|
||||||
- message: Fixed extra hardsuit that spawned in Suit storage lockers.
|
|
||||||
type: Fix
|
|
||||||
- message: Fixed free Epistemics access for HoP in pTech.
|
|
||||||
type: Fix
|
|
||||||
id: 2062
|
|
||||||
time: '2026-01-16T17:59:12.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5201
|
|
||||||
- author: BarryNorfolk
|
|
||||||
changes:
|
|
||||||
- message: Added new mapping command 'togglenetworklinks'
|
|
||||||
type: Add
|
|
||||||
id: 2063
|
|
||||||
time: '2026-01-16T18:09:53.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5188
|
|
||||||
- author: Halo3moth
|
|
||||||
changes:
|
|
||||||
- message: Devils will now role 2.5 times more often.
|
|
||||||
type: Tweak
|
|
||||||
id: 2064
|
|
||||||
time: '2026-01-16T18:13:00.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5225
|
|
||||||
- author: EmberAstra
|
|
||||||
changes:
|
|
||||||
- message: Added the microwave emitter! Epistemics has a radiation gun to shoot
|
|
||||||
artifacts with now!
|
|
||||||
type: Add
|
|
||||||
id: 2065
|
|
||||||
time: '2026-01-16T18:19:04.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5205
|
|
||||||
- author: DisposableCrewmember42
|
|
||||||
changes:
|
|
||||||
- message: Lord Singuloth rises.
|
|
||||||
type: Tweak
|
|
||||||
id: 2066
|
|
||||||
time: '2026-01-16T18:26:06.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5209
|
|
||||||
- author: BunglesnortBoss
|
|
||||||
changes:
|
|
||||||
- message: Made AI Nanites a good option. Heals 50 HP with a shorter cooldown
|
|
||||||
type: Tweak
|
|
||||||
id: 2067
|
|
||||||
time: '2026-01-16T18:27:22.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5210
|
|
||||||
- author: pootslap
|
|
||||||
changes:
|
|
||||||
- message: Carpy has acquired a fancy new pen and stamp and is ready to dispense
|
|
||||||
legal advice.
|
|
||||||
type: Tweak
|
|
||||||
- message: Removed the duplicate chaplain stamp from the listening post
|
|
||||||
type: Fix
|
|
||||||
id: 2068
|
|
||||||
time: '2026-01-16T18:29:14.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5169
|
|
||||||
- author: cmorley191
|
|
||||||
changes:
|
|
||||||
- message: Harpies are now reliably more sensitive to pollutant gases than other
|
|
||||||
species. For example, 0.4% of CO2 will make harpies start gasping, while humans
|
|
||||||
are okay up to 1.1% CO2
|
|
||||||
type: Add
|
|
||||||
id: 2069
|
|
||||||
time: '2026-01-16T18:32:20.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5158
|
|
||||||
- author: ShepardToTheStars
|
|
||||||
changes:
|
|
||||||
- message: Added CentComm Shipyard to order free ships with CentComm access.
|
|
||||||
type: Add
|
|
||||||
id: 2070
|
|
||||||
time: '2026-01-16T18:37:33.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5172
|
|
||||||
- author: EmberAstra
|
|
||||||
changes:
|
|
||||||
- message: Made the Engineering Void Suit printable!
|
|
||||||
type: Tweak
|
|
||||||
id: 2071
|
|
||||||
time: '2026-01-16T18:41:11.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5222
|
|
||||||
- author: cmorley191
|
|
||||||
changes:
|
|
||||||
- message: The Oracle will no longer request items that are "very" far away from
|
|
||||||
being researched.
|
|
||||||
type: Tweak
|
|
||||||
id: 2072
|
|
||||||
time: '2026-01-16T18:58:51.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4430
|
|
||||||
- author: Proxysseia
|
|
||||||
changes:
|
|
||||||
- message: Prison Knives no longer spawn in Prison Lockers
|
|
||||||
type: Remove
|
|
||||||
id: 2073
|
|
||||||
time: '2026-01-16T18:59:31.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4934
|
|
||||||
- author: Toby222
|
|
||||||
changes:
|
|
||||||
- message: Removed footprint prediction (for now)
|
|
||||||
type: Remove
|
|
||||||
id: 2074
|
|
||||||
time: '2026-01-16T19:07:45.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5224
|
|
||||||
- author: Velcroboy
|
|
||||||
changes:
|
|
||||||
- message: Prisoners can find dull bread knives in the ChefVend.
|
|
||||||
type: Tweak
|
|
||||||
id: 2075
|
|
||||||
time: '2026-01-17T21:13:59.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5234
|
|
||||||
- author: Halo3moth
|
|
||||||
changes:
|
|
||||||
- message: The T1 armored vest (slim) can now once again be picked in security loadouts.
|
|
||||||
type: Add
|
|
||||||
id: 2076
|
|
||||||
time: '2026-01-17T21:36:45.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5220
|
|
||||||
- author: biddygelson
|
|
||||||
changes:
|
|
||||||
- message: 'Academy: added anti-meteor zones and anti-anomaly zone, AI restoration
|
|
||||||
console in Mystagogue, Robotics Console in robo, fishing hole added to park,
|
|
||||||
materials is cargo at roundstart.'
|
|
||||||
type: Add
|
|
||||||
- message: 'Academy: station starts with distro and waste enabled, spare atmos chambers
|
|
||||||
start as vacuums, split artifacts'' APCs for power management, botany has more
|
|
||||||
trays and is slightly larger, department-front holopads in the department.'
|
|
||||||
type: Tweak
|
|
||||||
id: 2077
|
|
||||||
time: '2026-01-18T01:54:56.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5130
|
|
||||||
- author: DisposableCrewmember42
|
|
||||||
changes:
|
|
||||||
- message: You can no longer drink the deep fryer.
|
|
||||||
type: Fix
|
|
||||||
id: 2078
|
|
||||||
time: '2026-01-18T04:40:48.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5238
|
|
||||||
- author: snowywinters
|
|
||||||
changes:
|
|
||||||
- message: Reinforced cameras can now be built! They have additional HP and are
|
|
||||||
more resistant to explosions and meteors.
|
|
||||||
type: Add
|
|
||||||
- message: The AI has its own section in the security cameras console.
|
|
||||||
type: Add
|
|
||||||
id: 2079
|
|
||||||
time: '2026-01-18T17:18:45.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5027
|
|
||||||
- author: Dorragon
|
|
||||||
changes:
|
|
||||||
- message: Ready Manifest added to the lobby
|
|
||||||
type: Add
|
|
||||||
id: 2080
|
|
||||||
time: '2026-01-18T18:47:07.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5187
|
|
||||||
- author: MilonPL
|
|
||||||
changes:
|
|
||||||
- message: Added a new traits system, supporting conditions and new effects. Make
|
|
||||||
sure to check out the Traits tab in the character editor!
|
|
||||||
type: Add
|
|
||||||
- message: All character traits have been reset.
|
|
||||||
type: Remove
|
|
||||||
id: 2081
|
|
||||||
time: '2026-01-20T11:49:59.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5208
|
|
||||||
- author: pootslap
|
|
||||||
changes:
|
|
||||||
- message: You can now examine character descriptions from much further away.
|
|
||||||
type: Tweak
|
|
||||||
id: 2082
|
|
||||||
time: '2026-01-20T11:49:48.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5219
|
|
||||||
- author: Eternally-Confused
|
|
||||||
changes:
|
|
||||||
- message: (TEST MERGE) Space pens now contain a chemical called Stabilizine instead
|
|
||||||
of Leporazine, which is better at stabilizing body temperature.
|
|
||||||
type: Tweak
|
|
||||||
- message: Avali no longer die from space pens.
|
|
||||||
type: Tweak
|
|
||||||
id: 2083
|
|
||||||
time: '2026-01-20T21:15:21.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5181
|
|
||||||
- author: turtlemutt
|
|
||||||
changes:
|
|
||||||
- message: Added more names for ghost role spawns.
|
|
||||||
type: Add
|
|
||||||
id: 2084
|
|
||||||
time: '2026-01-21T05:17:05.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5254
|
|
||||||
- author: Cepelinas1
|
|
||||||
changes:
|
|
||||||
- message: Logistics Officers can now use the shipyard to buy shuttles. No need
|
|
||||||
to beg Captain to buy it anymore!
|
|
||||||
type: Add
|
|
||||||
id: 2085
|
|
||||||
time: '2026-01-21T05:52:10.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5251
|
|
||||||
- author: Colin-Tel
|
|
||||||
changes:
|
|
||||||
- message: Eked the Anglish tung tie. In other words, added a trait that lets you
|
|
||||||
talk like an Anglo Saxon with over 1,100 word replacements.
|
|
||||||
type: Add
|
|
||||||
id: 2086
|
|
||||||
time: '2026-01-21T09:37:07.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4092
|
|
||||||
- author: ShepardToTheStars
|
|
||||||
changes:
|
|
||||||
- message: The ninja is now revealed with hit with attacks, projectiles, explosions,
|
|
||||||
and grenades that do damage.
|
|
||||||
type: Tweak
|
|
||||||
- message: The ninja is now revealed with hit with attacks, projectiles, explosions,
|
|
||||||
and grenades that do damage.
|
|
||||||
type: Fix
|
|
||||||
id: 2087
|
|
||||||
time: '2026-01-21T14:18:56.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5217
|
|
||||||
- author: Toby222
|
|
||||||
changes:
|
|
||||||
- message: FTL times have been adjusted. Startup is shorter, travel is longer.
|
|
||||||
type: Tweak
|
|
||||||
- message: The FTL startup sound now lines up with the duration of startup again!!!
|
|
||||||
type: Fix
|
|
||||||
id: 2088
|
|
||||||
time: '2026-01-21T14:50:49.0000000+00:00'
|
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5257
|
|
||||||
- author: ShepardToTheStars, foxcumberland
|
- author: ShepardToTheStars, foxcumberland
|
||||||
changes:
|
changes:
|
||||||
- message: Added fashionable longcoats for command, security, and crew. Find them
|
- message: Added fashionable longcoats for command, security, and crew. Find them
|
||||||
@@ -4339,4 +3891,478 @@
|
|||||||
id: 2534
|
id: 2534
|
||||||
time: '2026-07-07T18:40:15.0000000+00:00'
|
time: '2026-07-07T18:40:15.0000000+00:00'
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6055
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6055
|
||||||
|
- author: jessiscah23
|
||||||
|
changes:
|
||||||
|
- message: Nanotrasen has fixed issues with salvage magnet calibration. Ore seams
|
||||||
|
can now be found on asteroid pulls!
|
||||||
|
type: Fix
|
||||||
|
id: 2535
|
||||||
|
time: '2026-07-09T01:24:45.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5973
|
||||||
|
- author: rebe83
|
||||||
|
changes:
|
||||||
|
- message: The syndicate saboteur cyborg no longer comes with weapons or an advanced
|
||||||
|
tool module. Cybersun stocks are down 13%.
|
||||||
|
type: Tweak
|
||||||
|
id: 2536
|
||||||
|
time: '2026-07-09T03:53:55.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6080
|
||||||
|
- author: keekee38
|
||||||
|
changes:
|
||||||
|
- message: after years of testing, NT managed to make more bullets fit into the
|
||||||
|
magnum cartridge boxes
|
||||||
|
type: Tweak
|
||||||
|
id: 2537
|
||||||
|
time: '2026-07-09T04:42:44.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6226
|
||||||
|
- author: rebe83
|
||||||
|
changes:
|
||||||
|
- message: Revenant can be grinded... ground...grounded up in a grinder without
|
||||||
|
salt to be killed WITHOUT exploding!
|
||||||
|
type: Tweak
|
||||||
|
- message: Revenant stasis time increased from 60 seconds to 100 seconds.
|
||||||
|
type: Tweak
|
||||||
|
- message: Skia takes a bit less damage from light sources.
|
||||||
|
type: Tweak
|
||||||
|
id: 2538
|
||||||
|
time: '2026-07-09T11:38:49.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5981
|
||||||
|
- author: Eternally-Confused
|
||||||
|
changes:
|
||||||
|
- message: The "Sentencing" and "Crime Modifiers" sections of Space Law have been
|
||||||
|
added to the in-game guidebook.
|
||||||
|
type: Fix
|
||||||
|
id: 2539
|
||||||
|
time: '2026-07-09T13:29:07.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6223
|
||||||
|
- author: Halo3moth
|
||||||
|
changes:
|
||||||
|
- message: Antagonist Guidelines have been updated please re-review them!
|
||||||
|
type: Tweak
|
||||||
|
id: 2540
|
||||||
|
time: '2026-07-09T18:03:20.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5929
|
||||||
|
- author: CarolCuchara
|
||||||
|
changes:
|
||||||
|
- message: Secure cabinets now need to be unlocked to be able to insert items!
|
||||||
|
type: Tweak
|
||||||
|
id: 2541
|
||||||
|
time: '2026-07-10T13:59:29.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6269
|
||||||
|
- author: Radezolid
|
||||||
|
changes:
|
||||||
|
- message: Seismic charges cost increased from 1250 mining points to 6250 mining
|
||||||
|
points.
|
||||||
|
type: Tweak
|
||||||
|
id: 2542
|
||||||
|
time: '2026-07-10T14:05:18.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6245
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: Advanced cleaning is now a T3 civilian services research.
|
||||||
|
type: Tweak
|
||||||
|
id: 2543
|
||||||
|
time: '2026-07-10T15:03:13.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6271
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: You can no longer see your own health bar with the medical hud (or similar
|
||||||
|
eyewear).
|
||||||
|
type: Tweak
|
||||||
|
id: 2544
|
||||||
|
time: '2026-07-10T17:22:38.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6241
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: New death implanters have been added to the syndicate uplink for those
|
||||||
|
to get the objective to die a glorious death - the true death implanter (free),
|
||||||
|
death acidifier implanter (free), and microbomb implanter (2TC). Choose wisely
|
||||||
|
because you only get one.
|
||||||
|
type: Add
|
||||||
|
id: 2545
|
||||||
|
time: '2026-07-10T19:58:17.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6221
|
||||||
|
- author: CheddaCheez
|
||||||
|
changes:
|
||||||
|
- message: Rodentia can now have whiskers and ears at the same time. Cheek fluff
|
||||||
|
too.
|
||||||
|
type: Tweak
|
||||||
|
id: 2546
|
||||||
|
time: '2026-07-10T20:08:32.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6273
|
||||||
|
- author: stormyatt
|
||||||
|
changes:
|
||||||
|
- message: Added welding mask and multitool to utility belt for MG and salvagers.
|
||||||
|
type: Add
|
||||||
|
- message: Removed network configurator from utility belt for MG and salvagers.
|
||||||
|
type: Remove
|
||||||
|
id: 2547
|
||||||
|
time: '2026-07-10T20:20:09.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6217
|
||||||
|
- author: ArionGekkota
|
||||||
|
changes:
|
||||||
|
- message: Allulalo can now fit inside bags!
|
||||||
|
type: Add
|
||||||
|
id: 2548
|
||||||
|
time: '2026-07-10T20:21:42.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6248
|
||||||
|
- author: Radezolid
|
||||||
|
changes:
|
||||||
|
- message: The LO's knuckledusters are back in, get them at your closest Logistics
|
||||||
|
Officer's locker.
|
||||||
|
type: Tweak
|
||||||
|
id: 2549
|
||||||
|
time: '2026-07-11T08:29:20.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6243
|
||||||
|
- author: Radezolid
|
||||||
|
changes:
|
||||||
|
- message: Engineering tool belts now come with a nanite applicator.
|
||||||
|
type: Tweak
|
||||||
|
id: 2550
|
||||||
|
time: '2026-07-11T16:09:23.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6261
|
||||||
|
- author: ollyoaner
|
||||||
|
changes:
|
||||||
|
- message: "Slime people can now add elf ear customization markings! \U0001F9DD"
|
||||||
|
type: Add
|
||||||
|
id: 2551
|
||||||
|
time: '2026-07-11T16:30:08.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6265
|
||||||
|
- author: rebe83
|
||||||
|
changes:
|
||||||
|
- message: Ion damage has been removed.
|
||||||
|
type: Remove
|
||||||
|
id: 2552
|
||||||
|
time: '2026-07-11T16:34:56.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5960
|
||||||
|
- author: rebe83, mousesweater
|
||||||
|
changes:
|
||||||
|
- message: Command members now have learner PAIs in their locker ready to absorb
|
||||||
|
knowledge!
|
||||||
|
type: Add
|
||||||
|
id: 2553
|
||||||
|
time: '2026-07-11T17:25:07.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5924
|
||||||
|
- author: Coryler
|
||||||
|
changes:
|
||||||
|
- message: Avali Preened Feather Color are now correct again
|
||||||
|
type: Fix
|
||||||
|
id: 2554
|
||||||
|
time: '2026-07-13T13:32:05.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6285
|
||||||
|
- author: pootslap
|
||||||
|
changes:
|
||||||
|
- message: Starlight forged weapons/armour/ammo are no longer craftable.
|
||||||
|
type: Remove
|
||||||
|
id: 2555
|
||||||
|
time: '2026-07-13T13:46:25.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6250
|
||||||
|
- author: ArionGekkota
|
||||||
|
changes:
|
||||||
|
- message: Added the small arms mining kit to the mining voucher. It contains a
|
||||||
|
crusher dagger and mining drill!
|
||||||
|
type: Add
|
||||||
|
id: 2556
|
||||||
|
time: '2026-07-13T13:51:12.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6260
|
||||||
|
- author: jessiscah23
|
||||||
|
changes:
|
||||||
|
- message: Due to the growing influence of the Cargo Pilots' Employee Advocacy Group,
|
||||||
|
cargo telepads are no longer available to be researched.
|
||||||
|
type: Remove
|
||||||
|
id: 2557
|
||||||
|
time: '2026-07-13T14:24:25.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6266
|
||||||
|
- author: Velitation
|
||||||
|
changes:
|
||||||
|
- message: Added 2 new outfits and a mantle to the mime's loadout. The outfits can
|
||||||
|
also be printed out at a uniform printer.
|
||||||
|
type: Add
|
||||||
|
id: 2558
|
||||||
|
time: '2026-07-13T16:16:20.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6264
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: Derelict borgs no longer have access to heads' rooms.
|
||||||
|
type: Fix
|
||||||
|
id: 2559
|
||||||
|
time: '2026-07-13T17:38:08.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6284
|
||||||
|
- author: Coryler
|
||||||
|
changes:
|
||||||
|
- message: Character height should be correctly applied for clones and paradox clones.
|
||||||
|
type: Fix
|
||||||
|
id: 2560
|
||||||
|
time: '2026-07-13T19:58:26.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6205
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: Objects animated by glimmer, revenants, or magic cannot be turned into
|
||||||
|
zombies anymore.
|
||||||
|
type: Fix
|
||||||
|
id: 2561
|
||||||
|
time: '2026-07-13T20:36:52.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6291
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: Xenoborg ID chip slots are no longer compatible with crew ID chips or
|
||||||
|
IDs.
|
||||||
|
type: Tweak
|
||||||
|
- message: Only the Xenoborg Mothership Core can talk over binary. All xenoborgs
|
||||||
|
can still listen.
|
||||||
|
type: Tweak
|
||||||
|
- message: Xenoborgs now have EMP resistant batteries and will only take drain around
|
||||||
|
40% of battery.
|
||||||
|
type: Tweak
|
||||||
|
- message: Xenoborgs will only be disabled for 6 seconds when hit by an EMP, instead
|
||||||
|
of 60 seconds.
|
||||||
|
type: Tweak
|
||||||
|
- message: The Xenoborg mothership core now has a magnet for materials.
|
||||||
|
type: Tweak
|
||||||
|
- message: The Xenoborg silicon storage square now has a toggleable magnet.
|
||||||
|
type: Fix
|
||||||
|
id: 2562
|
||||||
|
time: '2026-07-13T21:26:01.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6278
|
||||||
|
- author: Cepelinas1
|
||||||
|
changes:
|
||||||
|
- message: Certain fauna, like space dragons or mice can now see in the dark!
|
||||||
|
type: Add
|
||||||
|
- message: Dragons can now smell blood.
|
||||||
|
type: Add
|
||||||
|
id: 2563
|
||||||
|
time: '2026-07-14T01:38:28.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5902
|
||||||
|
- author: Velitation
|
||||||
|
changes:
|
||||||
|
- message: Mime PDAs once again start with the NanoTask, NoteKeeper, and NanoChat
|
||||||
|
apps.
|
||||||
|
type: Tweak
|
||||||
|
id: 2564
|
||||||
|
time: '2026-07-15T00:43:20.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6252
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: The airlock access override now breaks accesses on the door. You can
|
||||||
|
see if accesses on doors have been broken with the Diagnostic HUD.
|
||||||
|
type: Tweak
|
||||||
|
- message: Added access configurators to engineer lockers, engineering techfab,
|
||||||
|
and the EngiVend. Engineers are now allowed to repair access around the station!
|
||||||
|
type: Add
|
||||||
|
- message: The AI and engineering borgs can now see if a door's accesses have been
|
||||||
|
modified.
|
||||||
|
type: Add
|
||||||
|
id: 2565
|
||||||
|
time: '2026-07-15T01:58:05.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6263
|
||||||
|
- author: MantasDab360
|
||||||
|
changes:
|
||||||
|
- message: Wanted Fugitive paper is no longer clustered.
|
||||||
|
type: Fix
|
||||||
|
id: 2566
|
||||||
|
time: '2026-07-15T18:42:52.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6308
|
||||||
|
- author: AppleSmithWorks
|
||||||
|
changes:
|
||||||
|
- message: New nuclear scientist PDA in the Engineer loadout.
|
||||||
|
type: Add
|
||||||
|
id: 2567
|
||||||
|
time: '2026-07-16T20:24:27.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6283
|
||||||
|
- author: ollyoaner
|
||||||
|
changes:
|
||||||
|
- message: Slime people upgrades! (Incl. ports from Impstation). Some slimeperson
|
||||||
|
characters might need their eye marking(s) fix due to them being eyeless by
|
||||||
|
default!
|
||||||
|
type: Add
|
||||||
|
id: 2568
|
||||||
|
time: '2026-07-17T03:50:51.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6288
|
||||||
|
- author: Velitation
|
||||||
|
changes:
|
||||||
|
- message: Added 2 new hats, 3 new neck items, 1 new coat and, 1 pair of shoes to
|
||||||
|
the mime loadout.
|
||||||
|
type: Add
|
||||||
|
- message: Mimes can now select which shoes they start with.
|
||||||
|
type: Tweak
|
||||||
|
id: 2569
|
||||||
|
time: '2026-07-17T04:31:23.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6307
|
||||||
|
- author: ArionGekkota
|
||||||
|
changes:
|
||||||
|
- message: 'Hitman: Added the ninja kit, for those who want a melee-oriented fight,
|
||||||
|
as well as its brand new medium-frequency blade!'
|
||||||
|
type: Add
|
||||||
|
- message: 'Hitman: Gave some extra goodies to the sharpshooter and poisoner kit.'
|
||||||
|
type: Tweak
|
||||||
|
- message: 'Hitman: Revamped the tracker kit to include way more tools to spy on
|
||||||
|
the crew.'
|
||||||
|
type: Tweak
|
||||||
|
- message: 'Hitman: Reworked the loud kit into the bounty hunter kit, now equipped
|
||||||
|
with a repeater and more cowboy attire'
|
||||||
|
type: Tweak
|
||||||
|
- message: 'Hitman: Merged the disguise and assassin kit into one kit, combining
|
||||||
|
stealth and the ability to blend in anywhere'
|
||||||
|
type: Tweak
|
||||||
|
- message: 'Hitman: Reworked the infiltrator kit into the saboteur kit, a kit more
|
||||||
|
focused on sabotage and setting up traps'
|
||||||
|
type: Tweak
|
||||||
|
- message: 'Hitman: Removed the escapist kit. The new ninja kit was given a scram
|
||||||
|
implant to compensate.'
|
||||||
|
type: Remove
|
||||||
|
id: 2570
|
||||||
|
time: '2026-07-17T04:40:05.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6270
|
||||||
|
- author: SumofThreeParts
|
||||||
|
changes:
|
||||||
|
- message: Traitors are now less likely to have the escape to Midpoint objective.
|
||||||
|
type: Tweak
|
||||||
|
id: 2571
|
||||||
|
time: '2026-07-19T16:19:30.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6323
|
||||||
|
- author: GooeyPancake
|
||||||
|
changes:
|
||||||
|
- message: Pills now have taste again! Sorry Lexorin-pilled people.
|
||||||
|
type: Add
|
||||||
|
id: 2572
|
||||||
|
time: '2026-07-19T16:38:26.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6299
|
||||||
|
- author: BriBrooo
|
||||||
|
changes:
|
||||||
|
- message: Added new kimono and sandals loadout options for the chef.
|
||||||
|
type: Add
|
||||||
|
id: 2573
|
||||||
|
time: '2026-07-20T00:12:52.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6341
|
||||||
|
- author: Eternally-Confused
|
||||||
|
changes:
|
||||||
|
- message: Cyborgs are once again able to "boop" and "whirr"
|
||||||
|
type: Add
|
||||||
|
id: 2574
|
||||||
|
time: '2026-07-20T00:24:43.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6310
|
||||||
|
- author: kotobdev
|
||||||
|
changes:
|
||||||
|
- message: The Ardent Censer no longer requires fuel for deconversions.
|
||||||
|
type: Tweak
|
||||||
|
id: 2575
|
||||||
|
time: '2026-07-20T17:38:51.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5016
|
||||||
|
- author: Halo3rat, kotobdev
|
||||||
|
changes:
|
||||||
|
- message: The Freighter Crew's Jumpsuit is now available in the AutoDrobe, for
|
||||||
|
those who value their dental hygiene.
|
||||||
|
type: Add
|
||||||
|
id: 2576
|
||||||
|
time: '2026-07-20T20:06:59.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6331
|
||||||
|
- author: Mnemotechnician, kotobdev, ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: You can now offer items to other players by pressing F, and then clicking
|
||||||
|
on them! They can accept by clicking on the alert on the side of their screen.
|
||||||
|
type: Add
|
||||||
|
id: 2577
|
||||||
|
time: '2026-07-20T20:13:58.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5597
|
||||||
|
- author: ShepardToTheStars
|
||||||
|
changes:
|
||||||
|
- message: Glimmer probers can once again turn on and lock into place when glimmer
|
||||||
|
is over 750.
|
||||||
|
type: Add
|
||||||
|
- message: Glimmer prober explosions are 1.5x bigger if glimmer is over 900. You
|
||||||
|
better build drainers! :)
|
||||||
|
type: Tweak
|
||||||
|
- message: The oracle can now give normality crystals when completing her requests.
|
||||||
|
type: Tweak
|
||||||
|
id: 2578
|
||||||
|
time: '2026-07-20T20:29:02.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6292
|
||||||
|
- author: keekee38
|
||||||
|
changes:
|
||||||
|
- message: Added the novice mark, to help show that you're new! It is on intern
|
||||||
|
roles by default, and optional for everyone
|
||||||
|
type: Add
|
||||||
|
- message: Some clothes now have examine text, in particular pride clothes.
|
||||||
|
type: Tweak
|
||||||
|
id: 2579
|
||||||
|
time: '2026-07-20T22:08:57.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6118
|
||||||
|
- author: Coryler
|
||||||
|
changes:
|
||||||
|
- message: Shadekin has arrived in the DeltaV sector.
|
||||||
|
type: Add
|
||||||
|
id: 2580
|
||||||
|
time: '2026-07-20T22:10:50.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5481
|
||||||
|
- author: sowelipililimute
|
||||||
|
changes:
|
||||||
|
- message: The crew monitor now reports global coordinate positions.
|
||||||
|
type: Tweak
|
||||||
|
id: 2581
|
||||||
|
time: '2026-07-20T22:20:12.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6326
|
||||||
|
- author: keekee38
|
||||||
|
changes:
|
||||||
|
- message: Vulpkanins can yip now.
|
||||||
|
type: Tweak
|
||||||
|
id: 2582
|
||||||
|
time: '2026-07-20T22:21:24.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6301
|
||||||
|
- author: pootslap
|
||||||
|
changes:
|
||||||
|
- message: Improvised shotgun shells use the old upstream crafting recipe.
|
||||||
|
type: Tweak
|
||||||
|
- message: The improvised shotgun is craftable once again.
|
||||||
|
type: Fix
|
||||||
|
id: 2583
|
||||||
|
time: '2026-07-20T22:22:59.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6327
|
||||||
|
- author: kotobdev
|
||||||
|
changes:
|
||||||
|
- message: Security cold weather ponchos are gone from loadouts and the SecDrobe.
|
||||||
|
type: Remove
|
||||||
|
id: 2584
|
||||||
|
time: '2026-07-20T22:44:01.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6332
|
||||||
|
- author: sowelipililimute
|
||||||
|
changes:
|
||||||
|
- message: Security now has access to evidence bags, for storing all the illegal
|
||||||
|
things that can be stored.
|
||||||
|
type: Add
|
||||||
|
id: 2585
|
||||||
|
time: '2026-07-20T23:17:53.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6280
|
||||||
|
- author: jessiscah23
|
||||||
|
changes:
|
||||||
|
- message: Added organizational capabilities to the cargo bounty computer.
|
||||||
|
type: Add
|
||||||
|
id: 2586
|
||||||
|
time: '2026-07-20T23:23:28.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6306
|
||||||
|
- author: Proxysseia
|
||||||
|
changes:
|
||||||
|
- message: (TEST MERGE) Increased traitor starting telecrystal balance from 20 to
|
||||||
|
30.
|
||||||
|
type: Tweak
|
||||||
|
id: 2587
|
||||||
|
time: '2026-07-20T23:37:07.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6275
|
||||||
|
- author: ArionGekkota
|
||||||
|
changes:
|
||||||
|
- message: reintroduced researchable PKA modkits
|
||||||
|
type: Add
|
||||||
|
- message: Changed the PKA to its current upstream state
|
||||||
|
type: Tweak
|
||||||
|
- message: Reduced the health of some salvage mobs
|
||||||
|
type: Tweak
|
||||||
|
id: 2588
|
||||||
|
time: '2026-07-20T23:46:11.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6258
|
||||||
|
- author: nlaky
|
||||||
|
changes:
|
||||||
|
- message: Fixed incorrect Vulpkanin mask sprites.
|
||||||
|
type: Fix
|
||||||
|
id: 2589
|
||||||
|
time: '2026-07-21T00:05:09.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6201
|
||||||
Order: 1
|
Order: 1
|
||||||
|
|||||||
@@ -1071,4 +1071,20 @@
|
|||||||
id: 123
|
id: 123
|
||||||
time: '2026-06-12T17:16:00.0000000+00:00'
|
time: '2026-06-12T17:16:00.0000000+00:00'
|
||||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5940
|
url: https://github.com/DeltaV-Station/Delta-v/pull/5940
|
||||||
|
- author: FieldCommand
|
||||||
|
changes:
|
||||||
|
- message: 'Mothership: Turrets have been constructed on the Xenoborg mothership!'
|
||||||
|
type: Add
|
||||||
|
id: 124
|
||||||
|
time: '2026-07-13T13:16:26.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6244
|
||||||
|
- author: FieldCommand
|
||||||
|
changes:
|
||||||
|
- message: 'Midpoint: Added a pool area to Midpoint.'
|
||||||
|
type: Add
|
||||||
|
- message: 'Midpoint: Securety on Midpoint is now blue!'
|
||||||
|
type: Tweak
|
||||||
|
id: 125
|
||||||
|
time: '2026-07-14T00:30:06.0000000+00:00'
|
||||||
|
url: https://github.com/DeltaV-Station/Delta-v/pull/6242
|
||||||
Order: 3
|
Order: 3
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[game]
|
||||||
|
hostname = "[EN][MRP] Delta-v (Ψ) | Meridian [EU West]"
|
||||||
|
soft_max_players = 40
|
||||||
|
|
||||||
|
[hub]
|
||||||
|
tags = "lang:en-US,region:eu_w,rp:med,no_tag_infer"
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
pow3r_disable_parallel = false
|
||||||
File diff suppressed because one or more lines are too long
@@ -16,3 +16,5 @@ delta-chat-emote-name-harpysquish = Squish
|
|||||||
delta-chat-emote-name-quack = Quack
|
delta-chat-emote-name-quack = Quack
|
||||||
delta-chat-emote-name-squawk = Squawk
|
delta-chat-emote-name-squawk = Squawk
|
||||||
delta-chat-emote-name-horn = Horn
|
delta-chat-emote-name-horn = Horn
|
||||||
|
delta-chat-emote-name-yip = Yip
|
||||||
|
delta-chat-emote-msg-yip = yips.
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
damage-group-electronic = Electronic
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
dv-seen-inserted-item-name-modifier = {$baseName} with { INDEFINITE($contained) } { $contained }
|
||||||
|
dv-seen-inserted-item-examined =
|
||||||
|
.full = { CAPITALIZE(SUBJECT($container)) } has [color=paleturquoise]{ INDEFINITE($contained) } { $contained }[/color] in { SUBJECT($container) }.
|
||||||
|
.empty = { CAPITALIZE(SUBJECT($container)) } has nothing in { SUBJECT($container) }.
|
||||||
@@ -1 +1,5 @@
|
|||||||
deltav-ghost-role-information-space-dragon-description = Call in 3 carp rifts and take over this quadrant! You must place a rift every 10 minutes or suffer the consequences!
|
deltav-ghost-role-information-space-dragon-description = Call in 3 carp rifts and take over this quadrant! You must place a rift every 10 minutes or suffer the consequences!
|
||||||
|
|
||||||
|
ghost-role-information-space-dragon-matriarch-description = You are the space dragon matriarch. The crew is food, consume them all.
|
||||||
|
ghost-role-information-space-dragon-matriarch-name = Space Dragon Matriarch
|
||||||
|
ghost-role-information-space-dragon-matriarch-rules = Kill people, listen to the curator that spawned you in, kill people, dont die and kill people.
|
||||||
|
|||||||
@@ -1,45 +1,44 @@
|
|||||||
hitman-sharpshooter-kit-name = Sharpshooter kit
|
hitman-sharpshooter-kit-name = Sharpshooter kit
|
||||||
hitman-sharpshooter-kit-description =
|
hitman-sharpshooter-kit-description =
|
||||||
A kit for those who prefer killing from afar.
|
A kit for those who prefer killing from afar.
|
||||||
Provides a Hristov with ammo along with an outfit in a briefcase.
|
Provides a Hristov with ammo, thermal goggles and binoculars to spot
|
||||||
it also provides thermal goggles to find your targets.
|
your target, and a stealth box and cigarettes to ease the nerves.
|
||||||
|
|
||||||
hitman-loud-kit-name = Loud kit
|
hitman-bounty-hunter-kit-name = Bounty Hunter kit
|
||||||
hitman-loud-kit-description =
|
hitman-bounty-hunter-kit-description =
|
||||||
A kit for those who like a direct method.
|
A kit for those who like a direct method.
|
||||||
Provides a Python with Armor-Piercing rounds and two speedloaders.
|
Provides a SKL93 and a python loaded with armor-piercing rounds, as well
|
||||||
Alongside an extra of an armor vest and no-slip shoes.
|
as an extra speedloader and a cowboy outfit, armor vest included.
|
||||||
|
|
||||||
hitman-assassin-kit-name = Assassin kit
|
hitman-assassin-kit-name = Assassin kit
|
||||||
hitman-assassin-kit-description =
|
hitman-assassin-kit-description =
|
||||||
A kit for the quiet killers.
|
A kit for those who want to blend in.
|
||||||
Provides a Cobra with an extra magazine and armor piercing throwing knives.
|
Provides a Cobra with toxin and tranquilizer magazines, plus a set of
|
||||||
alongside night vision goggles and a radio jammer.
|
chameleon clothing, agent ID, fake mindshield and an identity mask implant.
|
||||||
|
|
||||||
|
hitman-ninja-kit-name = Ninja kit
|
||||||
|
hitman-ninja-kit-description =
|
||||||
|
A kit for those who want to fight up close.
|
||||||
|
Provides a medium frequency blade, throwing knives and a scram implant.
|
||||||
|
Plus no-slip shoes, smoke bombs and a combat medkit.
|
||||||
|
|
||||||
hitman-poisoner-kit-name = Poisoner kit
|
hitman-poisoner-kit-name = Poisoner kit
|
||||||
hitman-poisoner-kit-description =
|
hitman-poisoner-kit-description =
|
||||||
A kit for those who enjoy chemicals.
|
A kit for those who enjoy chemicals.
|
||||||
Provides a syringe to use with a bottle of pax, toxin, mute toxin, and Nocturine.
|
Provides an advanced jet injector along with bottles of of Pax, Toxin,
|
||||||
A chemical synthesis kit is also provided.
|
Mute Toxin, and Nocturine. A chemical synthesis kit is also provided.
|
||||||
|
|
||||||
hitman-infiltration-kit-name = Infiltration kit
|
hitman-saboteur-kit-name = Saboteur kit
|
||||||
hitman-infiltration-kit-description =
|
hitman-saboteur-kit-description =
|
||||||
A kit for those who want to get anywhere.
|
A kit for those who want to get anywhere.
|
||||||
Provides a cryptographic sequencer, syndicate jaws of life and stealth box.
|
Provides a cryptographic sequencer, airlock access override and a
|
||||||
|
rapid construction device with extra compressed matter.
|
||||||
hitman-disguise-kit-name = Disguise kit
|
Plus a set of tools and a dead man's signaller perfect for laying down traps.
|
||||||
hitman-disguise-kit-description =
|
|
||||||
A kit for those who want to be anyone.
|
|
||||||
Provides an Agent ID, chameleon clothing.
|
|
||||||
Plus a fake MindShield and voice mask implanter.
|
|
||||||
|
|
||||||
hitman-escapist-kit-name = Escapist kit
|
|
||||||
hitman-escapist-kit-description =
|
|
||||||
A kit for those who want to get out of anything.
|
|
||||||
Provides a DNA, freedom and scram implanter.
|
|
||||||
|
|
||||||
hitman-tracker-kit-name = Tracker kit
|
hitman-tracker-kit-name = Tracker kit
|
||||||
hitman-tracker-kit-description =
|
hitman-tracker-kit-description =
|
||||||
A kit for those who wish to know everything.
|
A kit for those who wish to know everything.
|
||||||
Provides a station master encryption key and universal pinpointer.
|
Provides a station master encryption key and binary encryption key,
|
||||||
Plus a spy monitor.
|
a spy monitor, a camera bug, an AI detector disguised as a multitool,
|
||||||
|
and a security hud disguised as sunglasses.
|
||||||
|
Plus a modified station map that can access crew records and universal pinpointer.
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ job-alt-title-plasma-scientist = Plasma Scientist
|
|||||||
job-alt-title-senior-engineer = Engineering Mentor
|
job-alt-title-senior-engineer = Engineering Mentor
|
||||||
job-alt-title-electrician = Electrician
|
job-alt-title-electrician = Electrician
|
||||||
job-alt-title-mechanic = Mechanic
|
job-alt-title-mechanic = Mechanic
|
||||||
|
job-alt-title-nuclear-scientist = Nuclear Scientist
|
||||||
|
|
||||||
job-alt-title-deck-worker = Deck Worker
|
job-alt-title-deck-worker = Deck Worker
|
||||||
job-alt-title-inventory-associate = Inventory Associate
|
job-alt-title-inventory-associate = Inventory Associate
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# Ears
|
||||||
|
marking-EarsShadekinMotley = Motley Ears
|
||||||
|
marking-EarsShadekinMotley-shadowkin = Ears
|
||||||
|
marking-EarsShadekinMotley-motley_secondary = Pattern
|
||||||
|
marking-EarsShadekinShady = Dark Ears
|
||||||
|
marking-EarsShadekinShady-shady = Ears
|
||||||
|
marking-EarsShadekinStriped = Striped Ears
|
||||||
|
marking-EarsShadowkinStriped-shadowkin = Ears
|
||||||
|
marking-EarsShadowkinStriped-shadowkin_stripes = Stripes
|
||||||
|
marking-EarsShadekinPiercingAll = Ears with Piercings
|
||||||
|
marking-EarsShadekinPiercingAll-shadowkin = Ears
|
||||||
|
marking-EarsShadekinPiercingAll-piercing_all = Piercings
|
||||||
|
marking-EarsShadekinPiercingLeft = Ears with Piercing (L)
|
||||||
|
marking-EarsShadekinPiercingLeft-shadowkin = Ears
|
||||||
|
marking-EarsShadekinPiercingLeft-piercing_left = Piercing
|
||||||
|
marking-EarsShadekinPiercingRight = Ears with Piercing (R)
|
||||||
|
marking-EarsShadekinPiercingRight-shadowkin = Ears
|
||||||
|
marking-EarsShadekinPiercingRight-piercing_right = Piercing
|
||||||
|
marking-EarsShadekinRingedAll = Ears with Rings
|
||||||
|
marking-EarsShadekinRingedAll-shadowkin = Ears
|
||||||
|
marking-EarsShadekinRingedAll-ringed_all_secondary = Rings
|
||||||
|
marking-EarsShadekinRingedLeft = Ears with Ring (L)
|
||||||
|
marking-EarsShadekinRingedLeft-shadowkin = Ears
|
||||||
|
marking-EarsShadekinRingedLeft-ringed_left_secondary = Ring
|
||||||
|
marking-EarsShadekinRingedRight = Ears with Ring (R)
|
||||||
|
marking-EarsShadekinRingedRight-shadowkin = Ears
|
||||||
|
marking-EarsShadekinRingedRight-ringed_right_secondary = Ring
|
||||||
|
marking-EarsShadekinGauzedAll = Gauzed Ears
|
||||||
|
marking-EarsShadekinGauzedAll-shadowkin = Ears
|
||||||
|
marking-EarsShadekinGauzedAll-gauze_ear_all_default = Gauze
|
||||||
|
marking-EarsShadekinGauzedLeft = Ear Bandage (L)
|
||||||
|
marking-EarsShadekinGauzedLeft-shadowkin = Ears
|
||||||
|
marking-EarsShadekinGauzedLeft-gauze_ear_l_default = Bandage
|
||||||
|
marking-EarsShadekinGauzedRight = Ear Bandage (R)
|
||||||
|
marking-EarsShadekinGauzedRight-shadowkin = Ears
|
||||||
|
marking-EarsShadekinGauzedRight-gauze_ear_r_default = Bandage
|
||||||
|
marking-EarsShadekinFluffy = Fluffy Ears
|
||||||
|
marking-EarsShadekinFluffy-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyButterfly = Fluffy Ears, Butterfly
|
||||||
|
marking-EarsShadekinFluffyButterfly-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyButterfly-fluffy_butterfly = Pattern
|
||||||
|
marking-EarsShadekinFluffyCowling = Fluffy Ears, Spotted
|
||||||
|
marking-EarsShadekinFluffyCowling-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyCowling-fluffy_cowling = Pattern
|
||||||
|
marking-EarsShadekinFluffyCrow = Fluffy Ears, Crow
|
||||||
|
marking-EarsShadekinFluffyCrow-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyCrow-fluffy_crow = Pattern
|
||||||
|
marking-EarsShadekinFluffyMotley = Fluffy Ears, Bright
|
||||||
|
marking-EarsShadekinFluffyMotley-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyMotley-fluffy_motley = Pattern
|
||||||
|
marking-EarsShadekinFluffySpidy = Fluffy Ears, Spidy
|
||||||
|
marking-EarsShadekinFluffySpidy-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffySpidy-fluffy_spidy = Pattern
|
||||||
|
marking-EarsShadekinFluffyRingedAll = Fluffy Ears, with Rings
|
||||||
|
marking-EarsShadekinFluffyRingedAll-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyRingedAll-fluffy_ringed_all = Rings
|
||||||
|
marking-EarsShadekinFluffyRingedLeft = Fluffy Ears, with Ring (L)
|
||||||
|
marking-EarsShadekinFluffyRingedLeft-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyRingedLeft-fluffy_ringed_left = Ring
|
||||||
|
marking-EarsShadekinFluffyRingedRight = Fluffy Ears, with Ring (R)
|
||||||
|
marking-EarsShadekinFluffyRingedRight-fluffy_default = Ears
|
||||||
|
marking-EarsShadekinFluffyRingedRight-fluffy_ringed_right = Ring
|
||||||
|
marking-EarsShadekinSaggy = Drooping Ears
|
||||||
|
marking-EarsShadekinSaggy-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyBrawly = Drooping Ears, Patterned
|
||||||
|
marking-EarsShadekinSaggyBrawly-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyBrawly-saggy_brawly = Pattern
|
||||||
|
marking-EarsShadekinSaggyZebra = Drooping Ears, Striped
|
||||||
|
marking-EarsShadekinSaggyZebra-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyZebra-saggy_zebra = Stripes
|
||||||
|
marking-EarsShadekinSaggyGradient = Drooping Ears, Gradient
|
||||||
|
marking-EarsShadekinSaggyGradient-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyGradient-saggy_gradient = Gradient
|
||||||
|
marking-EarsShadekinSaggyGauzedAll = Drooping Ears, Gauzed
|
||||||
|
marking-EarsShadekinSaggyGauzedAll-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyGauzedAll-saggy_gauze_all = Gauze
|
||||||
|
marking-EarsShadekinSaggyGauzedLeft = Drooping Ears, Ear Bandage (L)
|
||||||
|
marking-EarsShadekinSaggyGauzedLeft-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyGauzedLeft-saggy_gauze_l = Bandage
|
||||||
|
marking-EarsShadekinSaggyGauzedRight = Drooping Ears, Ear Bandage (R)
|
||||||
|
marking-EarsShadekinSaggyGauzedRight-saggy_default = Ears
|
||||||
|
marking-EarsShadekinSaggyGauzedRight-saggy_gauze_r = Bandage
|
||||||
|
marking-EarsShadekinShort = Short Ears
|
||||||
|
marking-EarsShadekinShort-short_default = Ears
|
||||||
|
marking-EarsShadekinShortButterfly = Short Ears, Decorated
|
||||||
|
marking-EarsShadekinShortButterfly-short_default = Ears
|
||||||
|
marking-EarsShadekinShortButterfly-short_butterfly = Pattern
|
||||||
|
marking-EarsShadekinShortRingedAll = Short Ears, with Rings
|
||||||
|
marking-EarsShadekinShortRingedAll-short_default = Ears
|
||||||
|
marking-EarsShadekinShortRingedAll-short_ringed_all = Rings
|
||||||
|
marking-EarsShadekinShortRingedLeft = Short Ears, with Ring (L)
|
||||||
|
marking-EarsShadekinShortRingedLeft-short_default = Ears
|
||||||
|
marking-EarsShadekinShortRingedLeft-short_ringed_left = Ring
|
||||||
|
marking-EarsShadekinShortRingedRight = Short Ears, with Ring (R)
|
||||||
|
marking-EarsShadekinShortRingedRight-short_default = Ears
|
||||||
|
marking-EarsShadekinShortRingedRight-short_ringed_right = Ring
|
||||||
|
marking-EarsShadekinBull = Straight Ears
|
||||||
|
marking-EarsShadekinBull-bull_default = Ears
|
||||||
|
marking-EarsShadekinBullSmooth = Straight Ears, Outlined
|
||||||
|
marking-EarsShadekinBullSmooth-bull_default = Ears
|
||||||
|
marking-EarsShadekinBullSmooth-bull_smooth = Inner ears
|
||||||
|
marking-EarsShadekinAqua = Aqua Ears
|
||||||
|
marking-EarsShadekinAqua-aqua_default = Ears
|
||||||
|
marking-EarsShadekinAquaIncolor = Aqua Ears, Colored
|
||||||
|
marking-EarsShadekinAquaIncolor-aqua_default = Ears
|
||||||
|
marking-EarsShadekinAquaIncolor-aqua_incolor = Inner ears
|
||||||
|
|
||||||
|
# Tails
|
||||||
|
marking-TailShadekin = Long Tail
|
||||||
|
marking-TailShadekinBig = Big Tail
|
||||||
|
marking-TailShadekinShorter = Short Tail
|
||||||
|
marking-TailShadekinShorter-shadekin_shorter_over = Tail
|
||||||
|
marking-TailShadekinShorterBrush = Short Tail, Furry
|
||||||
|
marking-TailShadekinShorterBrush-shadekin_shorter_over = Tail
|
||||||
|
marking-TailShadekinShorterBrush-shorter_brush_over = Tail tip
|
||||||
|
marking-TailShadekinMedium = Medium Tail
|
||||||
|
marking-TailShadekinMedium-shadekin_medium_front = Tail
|
||||||
|
marking-TailShadekinMediumTwoColored = Medium Tail, Two-Toned
|
||||||
|
marking-TailShadekinMediumTwoColored-shadekin_medium_front = Tail
|
||||||
|
marking-TailShadekinMediumTwoColored-medium_twocolored_over = Tail underside
|
||||||
|
|
||||||
|
# Overlays
|
||||||
|
marking-BodyShadekinArrow = Arrow Marking
|
||||||
|
marking-BodyShadekinArrow-body_arrow = Marking
|
||||||
|
marking-BodyShadekinBlackHole = Black Hole Marking
|
||||||
|
marking-BodyShadekinBlackHole-body_blackhole = Marking
|
||||||
|
marking-BodyShadekinBrace = Bracelet Marking
|
||||||
|
marking-BodyShadekinBrace-body_brace = Marking
|
||||||
|
marking-BodyShadekinBrawly = Combat Marking
|
||||||
|
marking-BodyShadekinBrawly-body_brawly = Marking
|
||||||
|
marking-BodyShadekinHeart = Heart Marking
|
||||||
|
marking-BodyShadekinHeart-body_heart = Marking
|
||||||
|
marking-BodyShadekinInk = Ink Marking
|
||||||
|
marking-BodyShadekinInk-body_ink = Marking
|
||||||
|
marking-BodyShadekinInk2 = Ink Marking 2
|
||||||
|
marking-BodyShadekinInk2-body_ink2 = Marking
|
||||||
|
marking-BodyShadekinInk3 = Ink Marking 3
|
||||||
|
marking-BodyShadekinInk3-body_ink3 = Marking
|
||||||
|
marking-BodyShadekinInk4 = Ink Marking 4
|
||||||
|
marking-BodyShadekinInk4-body_ink4 = Marking
|
||||||
|
marking-BodyShadekinInk5 = Ink Marking 5
|
||||||
|
marking-BodyShadekinInk5-body_ink5 = Marking
|
||||||
|
marking-BodyShadekinInk6 = Spiritual Ink Marking
|
||||||
|
marking-BodyShadekinInk6-body_ink6 = Marking
|
||||||
|
marking-BodyShadekinInkAnim = Spiral Ink Marking
|
||||||
|
marking-BodyShadekinInkAnim-body_ink_anim = Marking
|
||||||
|
marking-BodyShadekinLines = Lines Marking
|
||||||
|
marking-BodyShadekinLines-body_lines = Marking
|
||||||
|
marking-BodyShadekinNeck = Neck Marking
|
||||||
|
marking-BodyShadekinNeck-body_neck = Marking
|
||||||
|
marking-BodyShadekinShield = Protective Marking
|
||||||
|
marking-BodyShadekinShield-body_shield = Marking
|
||||||
|
marking-BodyShadekinVacuum = Open Marking
|
||||||
|
marking-BodyShadekinVacuum-body_vacuum = Marking
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Ears
|
||||||
|
marking-SlimeLongEars = Long Ears Standard
|
||||||
|
marking-SlimeLongEars-slime_ears_standard = Long Ears Standard
|
||||||
|
|
||||||
|
marking-SlimeEarsWide = Long Ears Wide
|
||||||
|
marking-SlimeEarsWide-slime_ears_wide = Long Ears Wide
|
||||||
|
|
||||||
|
marking-SlimeEarsSmall = Long Ears Small
|
||||||
|
marking-SlimeEarsSmall-slime_ears_small = Long Ears Small
|
||||||
|
|
||||||
|
marking-SlimeEarsUpwards = Long Ears Upwards
|
||||||
|
marking-SlimeEarsUpwards-slime_ears_upwards = Long Ears Upwards
|
||||||
|
|
||||||
|
marking-SlimeEarsTall = Long Ears Tall
|
||||||
|
marking-SlimeEarsTall-slime_ears_tall = Long Ears Tall
|
||||||
|
|
||||||
|
marking-SlimeEarsThin = Long Ears Thin
|
||||||
|
marking-SlimeEarsThin-slime_ears_thin = Long Ears Thin
|
||||||
|
|
||||||
|
# Eyes
|
||||||
|
marking-SlimeEyesDroopyRight = Droopy Eyes (Right)
|
||||||
|
marking-SlimeEyesDroopyRight-droopyR = Droopy Eyes (Right)
|
||||||
|
|
||||||
|
marking-SlimeEyesFourEyes = 4 Eyes
|
||||||
|
marking-SlimeEyesFourEyes-foureyes = 4 Eyes
|
||||||
|
|
||||||
|
marking-SlimeEyesLEyeLower = Left Eye (Lower)
|
||||||
|
marking-SlimeEyesLEyeLower-lefteye_lower = Left Eye (Lower)
|
||||||
|
|
||||||
|
marking-SlimeEyesREyeLower = Right Eye (Lower)
|
||||||
|
marking-SlimeEyesREyeLower-righteye_lower = Right Eye (Lower)
|
||||||
|
|
||||||
|
# Makeup
|
||||||
|
marking-MakeupFoureyesEyeshadow-foureyes_eyeshadow = Eyeshadow Foureyes
|
||||||
|
marking-MakeupFoureyesEyeshadow = Eyeshadow Foureyes
|
||||||
|
|
||||||
|
marking-MakeupDroopyLEyeshadowUpper = Eyeshadow Droopy Upper (Left)
|
||||||
|
marking-MakeupDroopyLEyeshadowUpper-droopyL_eyeshadow_upper = Eyeshadow Droopy Upper (Left)
|
||||||
|
|
||||||
|
marking-MakeupDroopyLEyeshadowLower = Eyeshadow Droopy Lower (Left)
|
||||||
|
marking-MakeupDroopyLEyeshadowLower-droopyL_eyeshadow_lower = Eyeshadow Droopy Lower (Left)
|
||||||
|
|
||||||
|
marking-MakeupDroopyREyeshadowUpper = Eyeshadow Droopy Upper (Right)
|
||||||
|
marking-MakeupDroopyREyeshadowUpper-droopyR_eyeshadow_upper = Eyeshadow Droopy Upper (Right)
|
||||||
|
|
||||||
|
marking-MakeupDroopyREyeshadowLower = Eyeshadow Droopy Lower (Right)
|
||||||
|
marking-MakeupDroopyREyeshadowLower-droopyR_eyeshadow_lower = Eyeshadow Droopy Lower (Right)
|
||||||
|
|
||||||
|
# Chest
|
||||||
|
marking-TorsoBitsF = Torso Bits
|
||||||
|
marking-TorsoBitsF-torsobits_f = Torso Bits
|
||||||
|
|
||||||
|
marking-TorsoBitsM = Torso Bits
|
||||||
|
marking-TorsoBitsM-torsobits_m = Torso Bits
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user