Merge branch 'master' into offmed-staging
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
MinSize="650 290">
|
MinSize="650 290">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
|
<!-- Privileged and target IDs, crew manifest button. -->
|
||||||
<GridContainer Columns="2">
|
<GridContainer Columns="2">
|
||||||
<GridContainer Columns="3" HorizontalExpand="True">
|
<GridContainer Columns="3" HorizontalExpand="True">
|
||||||
<Label Text="{Loc 'id-card-console-window-privileged-id'}" />
|
<Label Text="{Loc 'id-card-console-window-privileged-id'}" />
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
<Control MinSize="0 8" />
|
<Control MinSize="0 8" />
|
||||||
|
<!-- Full name and job title editing. -->
|
||||||
<GridContainer Columns="3" HSeparationOverride="4">
|
<GridContainer Columns="3" HSeparationOverride="4">
|
||||||
<Label Name="FullNameLabel" Text="{Loc 'id-card-console-window-full-name-label'}" />
|
<Label Name="FullNameLabel" Text="{Loc 'id-card-console-window-full-name-label'}" />
|
||||||
<LineEdit Name="FullNameLineEdit" HorizontalExpand="True" />
|
<LineEdit Name="FullNameLineEdit" HorizontalExpand="True" />
|
||||||
@@ -26,10 +28,19 @@
|
|||||||
<Button Name="JobTitleSaveButton" Text="{Loc 'id-card-console-window-save-button'}" Disabled="True" />
|
<Button Name="JobTitleSaveButton" Text="{Loc 'id-card-console-window-save-button'}" Disabled="True" />
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
<Control MinSize="0 8" />
|
<Control MinSize="0 8" />
|
||||||
<GridContainer Columns="2">
|
<!-- Job preset selection, grant/revoke all access buttons. -->
|
||||||
<Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
|
<BoxContainer Margin="0 8 0 4">
|
||||||
<OptionButton Name="JobPresetOptionButton" />
|
<BoxContainer>
|
||||||
</GridContainer>
|
<Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
|
||||||
|
<OptionButton Name="JobPresetOptionButton" />
|
||||||
|
</BoxContainer>
|
||||||
|
<Control HorizontalExpand="True"/>
|
||||||
|
<BoxContainer>
|
||||||
|
<Button Name="SelectAllButton" Text="{Loc 'id-card-console-window-select-all-button'}" />
|
||||||
|
<Button Name="DeselectAllButton" Text="{Loc 'id-card-console-window-deselect-all-button'}" />
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
<!-- Individual access buttons -->
|
||||||
<Control Name="AccessLevelControlContainer" />
|
<Control Name="AccessLevelControlContainer" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</DefaultWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -79,6 +79,18 @@ namespace Content.Client.Access.UI
|
|||||||
JobPresetOptionButton.AddItem(Loc.GetString(job.Name), _jobPrototypeIds.Count - 1);
|
JobPresetOptionButton.AddItem(Loc.GetString(job.Name), _jobPrototypeIds.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SelectAllButton.OnPressed += _ =>
|
||||||
|
{
|
||||||
|
SetAllAccess(true);
|
||||||
|
SubmitData();
|
||||||
|
};
|
||||||
|
|
||||||
|
DeselectAllButton.OnPressed += _ =>
|
||||||
|
{
|
||||||
|
SetAllAccess(false);
|
||||||
|
SubmitData();
|
||||||
|
};
|
||||||
|
|
||||||
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
|
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
|
||||||
_accessButtons.Populate(accessLevels, prototypeManager);
|
_accessButtons.Populate(accessLevels, prototypeManager);
|
||||||
AccessLevelControlContainer.AddChild(_accessButtons);
|
AccessLevelControlContainer.AddChild(_accessButtons);
|
||||||
@@ -89,14 +101,13 @@ namespace Content.Client.Access.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearAllAccess()
|
/// <param name="enabled">If true, every individual access button will be pressed. If false, each will be depressed.</param>
|
||||||
|
private void SetAllAccess(bool enabled)
|
||||||
{
|
{
|
||||||
foreach (var button in _accessButtons.ButtonsList.Values)
|
foreach (var button in _accessButtons.ButtonsList.Values)
|
||||||
{
|
{
|
||||||
if (button.Pressed)
|
if (!button.Disabled && button.Pressed != enabled)
|
||||||
{
|
button.Pressed = enabled;
|
||||||
button.Pressed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +121,7 @@ namespace Content.Client.Access.UI
|
|||||||
JobTitleLineEdit.Text = Loc.GetString(job.Name);
|
JobTitleLineEdit.Text = Loc.GetString(job.Name);
|
||||||
args.Button.SelectId(args.Id);
|
args.Button.SelectId(args.Id);
|
||||||
|
|
||||||
ClearAllAccess();
|
SetAllAccess(false);
|
||||||
|
|
||||||
// this is a sussy way to do this
|
// this is a sussy way to do this
|
||||||
foreach (var access in job.Access)
|
foreach (var access in job.Access)
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ public sealed partial class BanPanel : DefaultWindow
|
|||||||
var roleGroupCheckbox = new Button
|
var roleGroupCheckbox = new Button
|
||||||
{
|
{
|
||||||
Name = $"{groupName}GroupCheckbox",
|
Name = $"{groupName}GroupCheckbox",
|
||||||
Text = "Ban all",
|
Text = Loc.GetString("role-bans-ban-group"),
|
||||||
Margin = new Thickness(0, 0, 5, 0),
|
Margin = new Thickness(0, 0, 5, 0),
|
||||||
ToggleMode = true,
|
ToggleMode = true,
|
||||||
};
|
};
|
||||||
@@ -391,7 +391,7 @@ public sealed partial class BanPanel : DefaultWindow
|
|||||||
TimeLine.Text = args.Text;
|
TimeLine.Text = args.Text;
|
||||||
if (!double.TryParse(args.Text, out var result))
|
if (!double.TryParse(args.Text, out var result))
|
||||||
{
|
{
|
||||||
ExpiresLabel.Text = "err";
|
ExpiresLabel.Text = Loc.GetString("ban-panel-expiry-error");
|
||||||
ErrorLevel |= ErrorLevelEnum.Minutes;
|
ErrorLevel |= ErrorLevelEnum.Minutes;
|
||||||
TimeLine.ModulateSelfOverride = Color.Red;
|
TimeLine.ModulateSelfOverride = Color.Red;
|
||||||
UpdateSubmitEnabled();
|
UpdateSubmitEnabled();
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public sealed class AdminLogsEui : BaseEui
|
|||||||
ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
|
ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
|
||||||
{
|
{
|
||||||
Maximized = false,
|
Maximized = false,
|
||||||
Title = "Admin Logs",
|
Title = Loc.GetString("admin-logs-title"),
|
||||||
Monitor = monitor,
|
Monitor = monitor,
|
||||||
Width = 1100,
|
Width = 1100,
|
||||||
Height = 400
|
Height = 400
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
using Content.Shared.Crayon;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Client.Crayon
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class CrayonComponent : SharedCrayonComponent
|
|
||||||
{
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] public bool UIUpdateNeeded;
|
|
||||||
[ViewVariables] public int Charges { get; set; }
|
|
||||||
[ViewVariables] public int Capacity { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +1,52 @@
|
|||||||
using Content.Client.Items;
|
using Content.Client.Items;
|
||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
|
using Content.Shared.Charges.Components;
|
||||||
|
using Content.Shared.Charges.Systems;
|
||||||
using Content.Shared.Crayon;
|
using Content.Shared.Crayon;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Crayon;
|
namespace Content.Client.Crayon;
|
||||||
|
|
||||||
public sealed class CrayonSystem : SharedCrayonSystem
|
public sealed class CrayonSystem : SharedCrayonSystem
|
||||||
{
|
{
|
||||||
// Didn't do in shared because I don't think most of the server stuff can be predicted.
|
[Dependency] private readonly SharedChargesSystem _charges = default!;
|
||||||
|
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState);
|
|
||||||
Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnCrayonHandleState(EntityUid uid, CrayonComponent component, ref ComponentHandleState args)
|
Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent, _charges, _entityManager));
|
||||||
{
|
|
||||||
if (args.Current is not CrayonComponentState state) return;
|
|
||||||
|
|
||||||
component.Color = state.Color;
|
|
||||||
component.SelectedState = state.State;
|
|
||||||
component.Charges = state.Charges;
|
|
||||||
component.Capacity = state.Capacity;
|
|
||||||
|
|
||||||
component.UIUpdateNeeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class StatusControl : Control
|
private sealed class StatusControl : Control
|
||||||
{
|
{
|
||||||
private readonly CrayonComponent _parent;
|
private readonly Entity<CrayonComponent> _crayon;
|
||||||
|
private readonly SharedChargesSystem _charges;
|
||||||
private readonly RichTextLabel _label;
|
private readonly RichTextLabel _label;
|
||||||
|
private readonly int _capacity;
|
||||||
|
|
||||||
public StatusControl(CrayonComponent parent)
|
public StatusControl(Entity<CrayonComponent> crayon, SharedChargesSystem charges, EntityManager entityManage)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_crayon = crayon;
|
||||||
|
_charges = charges;
|
||||||
|
_capacity = entityManage.GetComponent<LimitedChargesComponent>(_crayon.Owner).MaxCharges;
|
||||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||||
AddChild(_label);
|
AddChild(_label);
|
||||||
|
|
||||||
parent.UIUpdateNeeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
{
|
{
|
||||||
base.FrameUpdate(args);
|
base.FrameUpdate(args);
|
||||||
|
|
||||||
if (!_parent.UIUpdateNeeded)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_parent.UIUpdateNeeded = false;
|
|
||||||
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label",
|
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label",
|
||||||
("color",_parent.Color),
|
("color",_crayon.Comp.Color),
|
||||||
("state",_parent.SelectedState),
|
("state",_crayon.Comp.SelectedState),
|
||||||
("charges", _parent.Charges),
|
("charges", _charges.GetCurrentCharges(_crayon.Owner)),
|
||||||
("capacity",_parent.Capacity)));
|
("capacity", _capacity)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,11 +100,11 @@ public sealed partial class CreditsWindow : DefaultWindow
|
|||||||
|
|
||||||
var container = new BoxContainer { Orientation = LayoutOrientation.Horizontal };
|
var container = new BoxContainer { Orientation = LayoutOrientation.Horizontal };
|
||||||
|
|
||||||
var previousPageButton = new Button { Text = "Previous Page" };
|
var previousPageButton = new Button { Text = Loc.GetString("credits-window-previous-page-button") };
|
||||||
previousPageButton.OnPressed +=
|
previousPageButton.OnPressed +=
|
||||||
_ => PopulateAttributions(attributionsContainer, count - AttributionsSourcesPerPage);
|
_ => PopulateAttributions(attributionsContainer, count - AttributionsSourcesPerPage);
|
||||||
|
|
||||||
var nextPageButton = new Button { Text = "Next Page" };
|
var nextPageButton = new Button { Text = Loc.GetString("credits-window-next-page-button") };
|
||||||
nextPageButton.OnPressed +=
|
nextPageButton.OnPressed +=
|
||||||
_ => PopulateAttributions(attributionsContainer, count + AttributionsSourcesPerPage);
|
_ => PopulateAttributions(attributionsContainer, count + AttributionsSourcesPerPage);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
StyleClasses="LabelBig" />
|
StyleClasses="LabelBig" />
|
||||||
<BoxContainer Orientation="Horizontal"
|
<BoxContainer Orientation="Horizontal"
|
||||||
Margin="0 0 0 5">
|
Margin="0 0 0 5">
|
||||||
<Label Text="{Loc 'crew-monitoring-user-interface-job'}"
|
<Label Text="{Loc 'crew-monitoring-ui-job-label'}"
|
||||||
FontColorOverride="DarkGray" />
|
FontColorOverride="DarkGray" />
|
||||||
<TextureRect Name="PersonJobIcon"
|
<TextureRect Name="PersonJobIcon"
|
||||||
TextureScale="2 2"
|
TextureScale="2 2"
|
||||||
|
|||||||
5
Content.Client/Damage/Systems/DamageOtherOnHitSystem.cs
Normal file
5
Content.Client/Damage/Systems/DamageOtherOnHitSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Damage.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Damage.Systems;
|
||||||
|
|
||||||
|
public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem;
|
||||||
@@ -4,11 +4,11 @@
|
|||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||||
<humanoid:MarkingPicker Name="MarkingPickerWidget" />
|
<humanoid:MarkingPicker Name="MarkingPickerWidget" />
|
||||||
<BoxContainer>
|
<BoxContainer>
|
||||||
<CheckBox Name="MarkingForced" Text="Force" Pressed="True" />
|
<CheckBox Name="MarkingForced" Text="{Loc humanoid-marking-modifier-force}" Pressed="True" />
|
||||||
<CheckBox Name="MarkingIgnoreSpecies" Text="Ignore Species" Pressed="True" />
|
<CheckBox Name="MarkingIgnoreSpecies" Text="{Loc humanoid-marking-modifier-ignore-species}" Pressed="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Collapsible HorizontalExpand="True">
|
<Collapsible HorizontalExpand="True">
|
||||||
<CollapsibleHeading Title="Base layers" />
|
<CollapsibleHeading Title="{Loc humanoid-marking-modifier-base-layers}" />
|
||||||
<CollapsibleBody HorizontalExpand="True">
|
<CollapsibleBody HorizontalExpand="True">
|
||||||
<BoxContainer Name="BaseLayersContainer" Orientation="Vertical" HorizontalExpand="True" />
|
<BoxContainer Name="BaseLayersContainer" Orientation="Vertical" HorizontalExpand="True" />
|
||||||
</CollapsibleBody>
|
</CollapsibleBody>
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
|
|||||||
});
|
});
|
||||||
_enable = new CheckBox
|
_enable = new CheckBox
|
||||||
{
|
{
|
||||||
Text = "Enable",
|
Text = Loc.GetString("humanoid-marking-modifier-enable"),
|
||||||
HorizontalAlignment = HAlignment.Right
|
HorizontalAlignment = HAlignment.Right
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -134,8 +134,8 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
|
|||||||
OnStateChanged!();
|
OnStateChanged!();
|
||||||
};
|
};
|
||||||
|
|
||||||
var lineEditBox = new BoxContainer();
|
var lineEditBox = new BoxContainer { SeparationOverride = 4 };
|
||||||
lineEditBox.AddChild(new Label { Text = "Prototype id: "});
|
lineEditBox.AddChild(new Label { Text = Loc.GetString("humanoid-marking-modifier-prototype-id") });
|
||||||
|
|
||||||
// TODO: This line edit should really be an options / dropdown selector, not text.
|
// TODO: This line edit should really be an options / dropdown selector, not text.
|
||||||
_lineEdit = new() { MinWidth = 200 };
|
_lineEdit = new() { MinWidth = 200 };
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
||||||
name = "Unknown";
|
name = Loc.GetString("navmap-unknown-entity");
|
||||||
|
|
||||||
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(blip.Coordinates.X)),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:ui="clr-namespace:Content.Client.Medical.CrewMonitoring"
|
xmlns:ui="clr-namespace:Content.Client.Medical.CrewMonitoring"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'crew-monitoring-user-interface-title'}"
|
Title="{Loc crew-monitoring-ui-title}"
|
||||||
Resizable="False"
|
Resizable="False"
|
||||||
SetSize="1310 700"
|
SetSize="1310 700"
|
||||||
MinSize="1310 700">
|
MinSize="1310 700">
|
||||||
@@ -11,12 +11,12 @@
|
|||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="3" Margin="0 0 10 0">
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="3" Margin="0 0 10 0">
|
||||||
<controls:StripeBack>
|
<controls:StripeBack>
|
||||||
<PanelContainer>
|
<PanelContainer>
|
||||||
<Label Name="StationName" Text="Unknown station" Align="Center" Margin="0 5 0 3"/>
|
<Label Name="StationName" Text="{Loc crew-monitoring-ui-no-station-label}" Align="Center" Margin="0 5 0 3"/>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
</controls:StripeBack>
|
</controls:StripeBack>
|
||||||
|
|
||||||
<LineEdit Name="SearchLineEdit" HorizontalExpand="True"
|
<LineEdit Name="SearchLineEdit" HorizontalExpand="True"
|
||||||
PlaceHolder="{Loc crew-monitor-filter-line-placeholder}" />
|
PlaceHolder="{Loc crew-monitoring-ui-filter-line-placeholder}" />
|
||||||
|
|
||||||
<ScrollContainer Name="SensorScroller"
|
<ScrollContainer Name="SensorScroller"
|
||||||
VerticalExpand="True"
|
VerticalExpand="True"
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<!-- Table rows are filled by code -->
|
<!-- Table rows are filled by code -->
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Label Name="NoServerLabel"
|
<Label Name="NoServerLabel"
|
||||||
Text="{Loc 'crew-monitoring-user-interface-no-server'}"
|
Text="{Loc crew-monitoring-ui-no-server-label}"
|
||||||
StyleClasses="LabelHeading"
|
StyleClasses="LabelHeading"
|
||||||
FontColorOverride="Red"
|
FontColorOverride="Red"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
<PanelContainer StyleClasses="LowDivider" />
|
||||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
||||||
<Label Text="{Loc 'crew-monitoring-user-interface-flavor-left'}" StyleClasses="WindowFooterText" />
|
<Label Text="{Loc crew-monitoring-ui-flavor-left-label}" StyleClasses="WindowFooterText" />
|
||||||
<Label Text="{Loc 'crew-monitoring-user-interface-flavor-right'}" StyleClasses="WindowFooterText"
|
<Label Text="{Loc crew-monitoring-ui-flavor-right-label}" StyleClasses="WindowFooterText"
|
||||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
||||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
||||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
|
|||||||
HorizontalExpand = true,
|
HorizontalExpand = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
deparmentLabel.SetMessage(Loc.GetString("crew-monitoring-user-interface-no-department"));
|
deparmentLabel.SetMessage(Loc.GetString("crew-monitoring-ui-no-department-label"));
|
||||||
deparmentLabel.StyleClasses.Add(StyleNano.StyleClassTooltipActionDescription);
|
deparmentLabel.StyleClasses.Add(StyleNano.StyleClassTooltipActionDescription);
|
||||||
|
|
||||||
SensorsTable.AddChild(deparmentLabel);
|
SensorsTable.AddChild(deparmentLabel);
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="NPC debug"
|
Title="{Loc npc-debug-overlay-window-title}"
|
||||||
MinSize="200 200">
|
MinSize="200 200">
|
||||||
<BoxContainer Name="Options" Orientation="Vertical" Margin="8 8">
|
<BoxContainer Name="Options" Orientation="Vertical" Margin="8 8">
|
||||||
<controls:StripeBack>
|
<controls:StripeBack>
|
||||||
<Label Text="NPC" HorizontalAlignment="Center"/>
|
<Label Text="{Loc npc-debug-overlay-window-section-npc-label}" HorizontalAlignment="Center"/>
|
||||||
</controls:StripeBack>
|
</controls:StripeBack>
|
||||||
<BoxContainer Name="NPCBox" Orientation="Vertical">
|
<BoxContainer Name="NPCBox" Orientation="Vertical">
|
||||||
<CheckBox Name="NPCThonk" Text="Thonk"/>
|
<CheckBox Name="NPCThonk" Text="{Loc npc-debug-overlay-window-show-htn-tree-checkbox}"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<controls:StripeBack>
|
<controls:StripeBack>
|
||||||
<Label Text="Pathfinder" HorizontalAlignment="Center"/>
|
<Label Text="{Loc npc-debug-overlay-window-section-pathfinder-label}" HorizontalAlignment="Center"/>
|
||||||
</controls:StripeBack>
|
</controls:StripeBack>
|
||||||
<BoxContainer Name="PathfinderBox" Orientation="Vertical">
|
<BoxContainer Name="PathfinderBox" Orientation="Vertical">
|
||||||
<CheckBox Name="PathCrumbs" Text="Breadcrumbs"/>
|
<CheckBox Name="PathCrumbs" Text="{Loc npc-debug-overlay-window-path-breadcrumbs-checkbox}"/>
|
||||||
<CheckBox Name="PathPolys" Text="Polygons"/>
|
<CheckBox Name="PathPolys" Text="{Loc npc-debug-overlay-window-path-polygons-checkbox}"/>
|
||||||
<CheckBox Name="PathNeighbors" Text="Neighbors"/>
|
<CheckBox Name="PathNeighbors" Text="{Loc npc-debug-overlay-window-path-neighbors-checkbox}"/>
|
||||||
<CheckBox Name="PathRouteCosts" Text="Route costs"/>
|
<CheckBox Name="PathRouteCosts" Text="{Loc npc-debug-overlay-window-path-route-costs-checkbox}"/>
|
||||||
<CheckBox Name="PathRoutes" Text="Routes"/>
|
<CheckBox Name="PathRoutes" Text="{Loc npc-debug-overlay-window-path-routes-checkbox}"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</controls:FancyWindow>
|
</controls:FancyWindow>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public sealed class JointVisualsOverlay : Overlay
|
|||||||
if (xform.MapID != args.MapId)
|
if (xform.MapID != args.MapId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var other = _entManager.GetEntity(visuals.Target);
|
var other = visuals.Target;
|
||||||
|
|
||||||
if (!xformQuery.TryGetComponent(other, out var otherXform))
|
if (!xformQuery.TryGetComponent(other, out var otherXform))
|
||||||
continue;
|
continue;
|
||||||
@@ -45,7 +45,7 @@ public sealed class JointVisualsOverlay : Overlay
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var texture = spriteSystem.Frame0(visuals.Sprite);
|
var texture = spriteSystem.Frame0(visuals.Sprite);
|
||||||
var width = texture.Width / (float) EyeManager.PixelsPerMeter;
|
var width = texture.Width / (float)EyeManager.PixelsPerMeter;
|
||||||
|
|
||||||
var coordsA = xform.Coordinates;
|
var coordsA = xform.Coordinates;
|
||||||
var coordsB = otherXform.Coordinates;
|
var coordsB = otherXform.Coordinates;
|
||||||
@@ -58,7 +58,7 @@ public sealed class JointVisualsOverlay : Overlay
|
|||||||
|
|
||||||
var posA = xformSystem.ToMapCoordinates(coordsA).Position;
|
var posA = xformSystem.ToMapCoordinates(coordsA).Position;
|
||||||
var posB = xformSystem.ToMapCoordinates(coordsB).Position;
|
var posB = xformSystem.ToMapCoordinates(coordsB).Position;
|
||||||
var diff = (posB - posA);
|
var diff = posB - posA;
|
||||||
var length = diff.Length();
|
var length = diff.Length();
|
||||||
|
|
||||||
var midPoint = diff / 2f + posA;
|
var midPoint = diff / 2f + posA;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<!-- Station name -->
|
<!-- Station name -->
|
||||||
<controls:StripeBack>
|
<controls:StripeBack>
|
||||||
<PanelContainer>
|
<PanelContainer>
|
||||||
<Label Name="StationName" Text="Unknown station" StyleClasses="LabelBig" Align="Center"/>
|
<Label Name="StationName" Text="{Loc 'station-map-unknown-station'}" StyleClasses="LabelBig" Align="Center"/>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
</controls:StripeBack>
|
</controls:StripeBack>
|
||||||
|
|
||||||
|
|||||||
@@ -58,25 +58,6 @@ public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prototype.SpriteBodyMovementState is { } movementState)
|
|
||||||
{
|
|
||||||
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
|
|
||||||
spriteMovement.NoMovementLayers.Clear();
|
|
||||||
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
|
|
||||||
{
|
|
||||||
State = prototype.SpriteBodyState,
|
|
||||||
};
|
|
||||||
spriteMovement.MovementLayers.Clear();
|
|
||||||
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
|
|
||||||
{
|
|
||||||
State = movementState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RemComp<SpriteMovementComponent>(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.UpdateEntityAppearance(entity, prototype);
|
base.UpdateEntityAppearance(entity, prototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
Content.Client/Silicons/Bots/HugBotSystem.cs
Normal file
5
Content.Client/Silicons/Bots/HugBotSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Silicons.Bots;
|
||||||
|
|
||||||
|
namespace Content.Client.Silicons.Bots;
|
||||||
|
|
||||||
|
public sealed partial class HugBotSystem : SharedHugBotSystem;
|
||||||
@@ -11,7 +11,7 @@ public sealed class StatValuesEui : BaseEui
|
|||||||
public StatValuesEui()
|
public StatValuesEui()
|
||||||
{
|
{
|
||||||
_window = new StatsWindow();
|
_window = new StatsWindow();
|
||||||
_window.Title = "Melee stats";
|
_window.Title = Loc.GetString("stat-values-ui-title");
|
||||||
_window.OpenCentered();
|
_window.OpenCentered();
|
||||||
_window.OnClose += Closed;
|
_window.OnClose += Closed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ public sealed class AHelpUIController: UIController, IOnSystemChanged<BwoinkSyst
|
|||||||
helper.ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
|
helper.ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
|
||||||
{
|
{
|
||||||
Maximized = false,
|
Maximized = false,
|
||||||
Title = "Admin Help",
|
Title = Loc.GetString("bwoink-admin-title"),
|
||||||
Monitor = monitor,
|
Monitor = monitor,
|
||||||
Width = 900,
|
Width = 900,
|
||||||
Height = 500
|
Height = 500
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
<DefaultWindow Title="{Loc Make Ghost Role}"
|
<DefaultWindow Title="{Loc make-ghost-roles-window-title}"
|
||||||
xmlns="https://spacestation14.io">
|
xmlns="https://spacestation14.io">
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RoleEntityLabel" Text="Entity" />
|
<Label Name="RoleEntityLabel" Text="{Loc make-ghost-roles-window-entity-label}" />
|
||||||
<Label Name="RoleEntity" Text="" />
|
<Label Name="RoleEntity" Text="" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RoleNameLabel" Text="Role Name" />
|
<Label Name="RoleNameLabel" Text="{Loc make-ghost-roles-window-role-name-label}" />
|
||||||
<LineEdit Name="RoleName" HorizontalExpand="True" />
|
<LineEdit Name="RoleName" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RoleDescriptionLabel" Text="Role Description" />
|
<Label Name="RoleDescriptionLabel" Text="{Loc make-ghost-roles-window-role-description-label}" />
|
||||||
<LineEdit Name="RoleDescription" HorizontalExpand="True" />
|
<LineEdit Name="RoleDescription" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RoleRulesLabel" Text="Role Rules" />
|
<Label Name="RoleRulesLabel" Text="{Loc make-ghost-roles-window-role-rules-label}" />
|
||||||
<LineEdit Name="RoleRules" HorizontalExpand="True" Text="{Loc ghost-role-component-default-rules}" />
|
<LineEdit Name="RoleRules" HorizontalExpand="True" Text="{Loc ghost-role-component-default-rules}" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="MakeSentientLabel" Text="Make Sentient" />
|
<Label Name="MakeSentientLabel" Text="{Loc make-ghost-roles-window-make-sentient-label}" />
|
||||||
<CheckBox Name="MakeSentientCheckbox" />
|
<CheckBox Name="MakeSentientCheckbox" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RaffleLabel" Text="Raffle Role?" />
|
<Label Name="RaffleLabel" Text="{Loc make-ghost-roles-window-raffle-role-label}" />
|
||||||
<OptionButton Name="RaffleButton" />
|
<OptionButton Name="RaffleButton" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Name="RaffleCustomSettingsContainer" Orientation="Vertical" Visible="False">
|
<BoxContainer Name="RaffleCustomSettingsContainer" Orientation="Vertical" Visible="False">
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RaffleInitialDurationLabel" Text="Initial Duration (s)" />
|
<Label Name="RaffleInitialDurationLabel" Text="{Loc make-ghost-roles-window-initial-duration-label}" />
|
||||||
<SpinBox Name="RaffleInitialDuration" HorizontalExpand="True" />
|
<SpinBox Name="RaffleInitialDuration" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RaffleJoinExtendsDurationByLabel" Text="Joins Extend By (s)" />
|
<Label Name="RaffleJoinExtendsDurationByLabel" Text="{Loc make-ghost-roles-window-join-extends-by-label}" />
|
||||||
<SpinBox Name="RaffleJoinExtendsDurationBy" HorizontalExpand="True" />
|
<SpinBox Name="RaffleJoinExtendsDurationBy" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Name="RaffleMaxDurationLabel" Text="Max Duration (s)" />
|
<Label Name="RaffleMaxDurationLabel" Text="{Loc make-ghost-roles-window-max-duration-label}" />
|
||||||
<SpinBox Name="RaffleMaxDuration" HorizontalExpand="True" />
|
<SpinBox Name="RaffleMaxDuration" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Button Name="MakeButton" Text="Make" />
|
<Button Name="MakeButton" Text="{Loc make-ghost-roles-window-make-button}" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
RaffleMaxDuration.ValueChanged += OnRaffleDurationChanged;
|
RaffleMaxDuration.ValueChanged += OnRaffleDurationChanged;
|
||||||
|
|
||||||
|
|
||||||
RaffleButton.AddItem("Don't raffle", RaffleDontRaffleId);
|
RaffleButton.AddItem(Loc.GetString("make-ghost-roles-window-raffle-not-button"), RaffleDontRaffleId);
|
||||||
RaffleButton.AddItem("Custom settings", RaffleCustomRaffleId);
|
RaffleButton.AddItem(Loc.GetString("make-ghost-roles-window-raffle-custom-settings-button"), RaffleCustomRaffleId);
|
||||||
|
|
||||||
var raffleProtos =
|
var raffleProtos =
|
||||||
_prototypeManager.EnumeratePrototypes<GhostRoleRaffleSettingsPrototype>();
|
_prototypeManager.EnumeratePrototypes<GhostRoleRaffleSettingsPrototype>();
|
||||||
@@ -74,7 +74,7 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
_rafflePrototypes.Add(raffleProto);
|
_rafflePrototypes.Add(raffleProto);
|
||||||
var s = raffleProto.Settings;
|
var s = raffleProto.Settings;
|
||||||
var label =
|
var label =
|
||||||
$"{raffleProto.ID} (initial {s.InitialDuration}s, max {s.MaxDuration}s, join adds {s.JoinExtendsDurationBy}s)";
|
Loc.GetString("make-ghost-roles-window-raffle-settings-label", ("id", raffleProto.ID), ("initialDuration", s.InitialDuration), ("maxDuration", s.MaxDuration), ("joinExtendsDurationBy", s.JoinExtendsDurationBy));
|
||||||
RaffleButton.AddItem(label, idx++);
|
RaffleButton.AddItem(label, idx++);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
if (RaffleInitialDuration.Value > RaffleMaxDuration.Value)
|
if (RaffleInitialDuration.Value > RaffleMaxDuration.Value)
|
||||||
{
|
{
|
||||||
MakeButton.Disabled = true;
|
MakeButton.Disabled = true;
|
||||||
MakeButton.ToolTip = "The initial duration must not exceed the maximum duration.";
|
MakeButton.ToolTip = Loc.GetString("make-ghost-roles-window-raffle-warning-tooltip");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public sealed class StorageWindow : BaseWindow
|
|||||||
HorizontalExpand = true,
|
HorizontalExpand = true,
|
||||||
Name = "StorageLabel",
|
Name = "StorageLabel",
|
||||||
ClipText = true,
|
ClipText = true,
|
||||||
Text = "Dummy",
|
Text = Loc.GetString("comp-storage-window-dummy"),
|
||||||
StyleClasses =
|
StyleClasses =
|
||||||
{
|
{
|
||||||
"FancyWindowTitle",
|
"FancyWindowTitle",
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb bolt = new()
|
Verb bolt = new()
|
||||||
{
|
{
|
||||||
Text = bolts.BoltsDown ? "Unbolt" : "Bolt",
|
Text = Loc.GetString(bolts.BoltsDown ? "admin-verbs-unbolt" : "admin-verbs-bolt"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = bolts.BoltsDown
|
Icon = bolts.BoltsDown
|
||||||
? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png"))
|
? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png"))
|
||||||
@@ -91,7 +91,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb emergencyAccess = new()
|
Verb emergencyAccess = new()
|
||||||
{
|
{
|
||||||
Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
|
Text = Loc.GetString(airlockComp.EmergencyAccess ? "admin-verbs-emergency-access-off" : "admin-verbs-emergency-access-on"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -111,7 +111,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb rejuvenate = new()
|
Verb rejuvenate = new()
|
||||||
{
|
{
|
||||||
Text = "Rejuvenate",
|
Text = Loc.GetString("admin-verbs-rejuvenate"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rejuvenate.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rejuvenate.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -129,7 +129,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb makeIndestructible = new()
|
Verb makeIndestructible = new()
|
||||||
{
|
{
|
||||||
Text = "Make Indestructible",
|
Text = Loc.GetString("admin-verbs-make-indestructible"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -146,7 +146,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb makeVulnerable = new()
|
Verb makeVulnerable = new()
|
||||||
{
|
{
|
||||||
Text = "Make Vulnerable",
|
Text = Loc.GetString("admin-verbs-make-vulnerable"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -164,7 +164,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb refillBattery = new()
|
Verb refillBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Battery",
|
Text = Loc.GetString("admin-verbs-refill-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -179,7 +179,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb drainBattery = new()
|
Verb drainBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Drain Battery",
|
Text = Loc.GetString("admin-verbs-drain-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -194,7 +194,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb infiniteBattery = new()
|
Verb infiniteBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Infinite Battery",
|
Text = Loc.GetString("admin-verbs-infinite-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -215,7 +215,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb blockUnanchor = new()
|
Verb blockUnanchor = new()
|
||||||
{
|
{
|
||||||
Text = "Block Unanchoring",
|
Text = Loc.GetString("admin-verbs-block-unanchoring"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -233,7 +233,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb refillInternalsO2 = new()
|
Verb refillInternalsO2 = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Oxygen",
|
Text = Loc.GetString("admin-verbs-refill-internals-oxygen"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -248,7 +248,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb refillInternalsN2 = new()
|
Verb refillInternalsN2 = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Nitrogen",
|
Text = Loc.GetString("admin-verbs-refill-internals-nitrogen"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -263,7 +263,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb refillInternalsPlasma = new()
|
Verb refillInternalsPlasma = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Plasma",
|
Text = Loc.GetString("admin-verbs-refill-internals-plasma"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -281,7 +281,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb refillInternalsO2 = new()
|
Verb refillInternalsO2 = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Oxygen",
|
Text = Loc.GetString("admin-verbs-refill-internals-oxygen"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||||
Act = () => RefillEquippedTanks(args.User, Gas.Oxygen),
|
Act = () => RefillEquippedTanks(args.User, Gas.Oxygen),
|
||||||
@@ -293,7 +293,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb refillInternalsN2 = new()
|
Verb refillInternalsN2 = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Nitrogen",
|
Text = Loc.GetString("admin-verbs-refill-internals-nitrogen"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||||
Act = () => RefillEquippedTanks(args.User, Gas.Nitrogen),
|
Act = () => RefillEquippedTanks(args.User, Gas.Nitrogen),
|
||||||
@@ -305,7 +305,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb refillInternalsPlasma = new()
|
Verb refillInternalsPlasma = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Internals Plasma",
|
Text = Loc.GetString("admin-verbs-refill-internals-plasma"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||||
Act = () => RefillEquippedTanks(args.User, Gas.Plasma),
|
Act = () => RefillEquippedTanks(args.User, Gas.Plasma),
|
||||||
@@ -318,7 +318,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb sendToTestArena = new()
|
Verb sendToTestArena = new()
|
||||||
{
|
{
|
||||||
Text = "Send to test arena",
|
Text = Loc.GetString("admin-verbs-send-to-test-arena"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb grantAllAccess = new()
|
Verb grantAllAccess = new()
|
||||||
{
|
{
|
||||||
Text = "Grant All Access",
|
Text = Loc.GetString("admin-verbs-grant-all-access"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -354,7 +354,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb revokeAllAccess = new()
|
Verb revokeAllAccess = new()
|
||||||
{
|
{
|
||||||
Text = "Revoke All Access",
|
Text = Loc.GetString("admin-verbs-revoke-all-access"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -372,7 +372,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb grantAllAccess = new()
|
Verb grantAllAccess = new()
|
||||||
{
|
{
|
||||||
Text = "Grant All Access",
|
Text = Loc.GetString("admin-verbs-grant-all-access"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -387,7 +387,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb revokeAllAccess = new()
|
Verb revokeAllAccess = new()
|
||||||
{
|
{
|
||||||
Text = "Revoke All Access",
|
Text = Loc.GetString("admin-verbs-revoke-all-access"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -405,13 +405,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb adjustStack = new()
|
Verb adjustStack = new()
|
||||||
{
|
{
|
||||||
Text = "Adjust Stack",
|
Text = Loc.GetString("admin-verbs-adjust-stack"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/adjust-stack.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/adjust-stack.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
// Unbounded intentionally.
|
// Unbounded intentionally.
|
||||||
_quickDialog.OpenDialog(player, "Adjust stack", $"Amount (max {_stackSystem.GetMaxCount(stack)})", (int newAmount) =>
|
_quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-adjust-stack"), Loc.GetString("admin-verbs-dialog-adjust-stack-amount", ("max", _stackSystem.GetMaxCount(stack))), (int newAmount) =>
|
||||||
{
|
{
|
||||||
_stackSystem.SetCount(args.Target, newAmount, stack);
|
_stackSystem.SetCount(args.Target, newAmount, stack);
|
||||||
});
|
});
|
||||||
@@ -424,7 +424,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb fillStack = new()
|
Verb fillStack = new()
|
||||||
{
|
{
|
||||||
Text = "Fill Stack",
|
Text = Loc.GetString("admin-verbs-fill-stack"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill-stack.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill-stack.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -440,12 +440,12 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb rename = new()
|
Verb rename = new()
|
||||||
{
|
{
|
||||||
Text = "Rename",
|
Text = Loc.GetString("admin-verbs-rename"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_quickDialog.OpenDialog(player, "Rename", "Name", (string newName) =>
|
_quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-rename-title"), Loc.GetString("admin-verbs-dialog-rename-name"), (string newName) =>
|
||||||
{
|
{
|
||||||
_metaSystem.SetEntityName(args.Target, newName);
|
_metaSystem.SetEntityName(args.Target, newName);
|
||||||
});
|
});
|
||||||
@@ -458,12 +458,12 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb redescribe = new()
|
Verb redescribe = new()
|
||||||
{
|
{
|
||||||
Text = "Redescribe",
|
Text = Loc.GetString("admin-verbs-redescribe"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/redescribe.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/redescribe.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_quickDialog.OpenDialog(player, "Redescribe", "Description", (LongString newDescription) =>
|
_quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-redescribe-title"), Loc.GetString("admin-verbs-dialog-redescribe-description"), (LongString newDescription) =>
|
||||||
{
|
{
|
||||||
_metaSystem.SetEntityDescription(args.Target, newDescription.String);
|
_metaSystem.SetEntityDescription(args.Target, newDescription.String);
|
||||||
});
|
});
|
||||||
@@ -476,12 +476,12 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb renameAndRedescribe = new()
|
Verb renameAndRedescribe = new()
|
||||||
{
|
{
|
||||||
Text = "Redescribe",
|
Text = Loc.GetString("admin-verbs-rename-and-redescribe"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_quickDialog.OpenDialog(player, "Rename & Redescribe", "Name", "Description",
|
_quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-rename-and-redescribe-title"), Loc.GetString("admin-verbs-dialog-rename-name"), Loc.GetString("admin-verbs-dialog-redescribe-description"),
|
||||||
(string newName, LongString newDescription) =>
|
(string newName, LongString newDescription) =>
|
||||||
{
|
{
|
||||||
var meta = MetaData(args.Target);
|
var meta = MetaData(args.Target);
|
||||||
@@ -501,7 +501,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb barJobSlots = new()
|
Verb barJobSlots = new()
|
||||||
{
|
{
|
||||||
Text = "Bar job slots",
|
Text = Loc.GetString("admin-verbs-bar-job-slots"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -520,7 +520,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb locateCargoShuttle = new()
|
Verb locateCargoShuttle = new()
|
||||||
{
|
{
|
||||||
Text = "Locate Cargo Shuttle",
|
Text = Loc.GetString("admin-verbs-locate-cargo-shuttle"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -543,7 +543,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb refillBattery = new()
|
Verb refillBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Refill Battery",
|
Text = Loc.GetString("admin-verbs-refill-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -564,7 +564,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb drainBattery = new()
|
Verb drainBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Drain Battery",
|
Text = Loc.GetString("admin-verbs-drain-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -585,7 +585,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
Verb infiniteBattery = new()
|
Verb infiniteBattery = new()
|
||||||
{
|
{
|
||||||
Text = "Infinite Battery",
|
Text = Loc.GetString("admin-verbs-infinite-battery"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -615,7 +615,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb haltMovement = new()
|
Verb haltMovement = new()
|
||||||
{
|
{
|
||||||
Text = "Halt Movement",
|
Text = Loc.GetString("admin-verbs-halt-movement"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/halt.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/halt.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -638,7 +638,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb unpauseMap = new()
|
Verb unpauseMap = new()
|
||||||
{
|
{
|
||||||
Text = "Unpause Map",
|
Text = Loc.GetString("admin-verbs-unpause-map"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -655,7 +655,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb pauseMap = new()
|
Verb pauseMap = new()
|
||||||
{
|
{
|
||||||
Text = "Pause Map",
|
Text = Loc.GetString("admin-verbs-pause-map"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -675,7 +675,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb snapJoints = new()
|
Verb snapJoints = new()
|
||||||
{
|
{
|
||||||
Text = "Snap Joints",
|
Text = Loc.GetString("admin-verbs-snap-joints"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/snap_joints.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/snap_joints.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -693,7 +693,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb minigunFire = new()
|
Verb minigunFire = new()
|
||||||
{
|
{
|
||||||
Text = "Make Minigun",
|
Text = Loc.GetString("admin-verbs-make-minigun"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -712,12 +712,12 @@ public sealed partial class AdminVerbSystem
|
|||||||
{
|
{
|
||||||
Verb setCapacity = new()
|
Verb setCapacity = new()
|
||||||
{
|
{
|
||||||
Text = "Set Bullet Amount",
|
Text = Loc.GetString("admin-verbs-set-bullet-amount"),
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_quickDialog.OpenDialog(player, "Set Bullet Amount", $"Amount (standard {ballisticAmmo.Capacity}):", (string amount) =>
|
_quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-set-bullet-amount-title"), Loc.GetString("admin-verbs-dialog-set-bullet-amount-amount", ("cap", ballisticAmmo.Capacity)), (string amount) =>
|
||||||
{
|
{
|
||||||
if (!int.TryParse(amount, out var result))
|
if (!int.TryParse(amount, out var result))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Shared.Access.Components;
|
|||||||
using Content.Shared.Clothing;
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Interaction.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
@@ -23,7 +24,7 @@ public sealed class OutfitSystem : EntitySystem
|
|||||||
[Dependency] private readonly InventorySystem _invSystem = default!;
|
[Dependency] private readonly InventorySystem _invSystem = default!;
|
||||||
[Dependency] private readonly SharedStationSpawningSystem _spawningSystem = default!;
|
[Dependency] private readonly SharedStationSpawningSystem _spawningSystem = default!;
|
||||||
|
|
||||||
public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null)
|
public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null, bool unremovable = false)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(target, out InventoryComponent? inventoryComponent))
|
if (!EntityManager.TryGetComponent(target, out InventoryComponent? inventoryComponent))
|
||||||
return false;
|
return false;
|
||||||
@@ -60,6 +61,8 @@ public sealed class OutfitSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
_invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
|
_invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
|
||||||
|
if (unremovable)
|
||||||
|
EnsureComp<UnremoveableComponent>(equipmentEntity);
|
||||||
|
|
||||||
onEquipped?.Invoke(target, equipmentEntity);
|
onEquipped?.Invoke(target, equipmentEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Content.Server.Clothing.Systems;
|
|||||||
using Content.Shared.Chat.Prototypes;
|
using Content.Shared.Chat.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
using Content.Shared.Damage.Prototypes;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Content.Server.Emoting.Systems;
|
using Content.Server.Emoting.Systems;
|
||||||
@@ -21,7 +20,6 @@ namespace Content.Server.Cluwne;
|
|||||||
|
|
||||||
public sealed class CluwneSystem : EntitySystem
|
public sealed class CluwneSystem : EntitySystem
|
||||||
{
|
{
|
||||||
private static readonly ProtoId<DamageGroupPrototype> GeneticDamageGroup = "Genetic";
|
|
||||||
|
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
@@ -48,15 +46,14 @@ public sealed class CluwneSystem : EntitySystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// On death removes active comps and gives genetic damage to prevent cloning, reduce this to allow cloning.
|
/// On death removes active comps and gives genetic damage to prevent cloning, reduce this to allow cloning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnMobState(EntityUid uid, CluwneComponent component, MobStateChangedEvent args)
|
private void OnMobState(Entity<CluwneComponent> ent, ref MobStateChangedEvent args)
|
||||||
{
|
{
|
||||||
if (args.NewMobState == MobState.Dead)
|
if (args.NewMobState == MobState.Dead)
|
||||||
{
|
{
|
||||||
RemComp<CluwneComponent>(uid);
|
RemComp<CluwneComponent>(ent.Owner);
|
||||||
RemComp<ClumsyComponent>(uid);
|
RemComp<ClumsyComponent>(ent.Owner);
|
||||||
RemComp<AutoEmoteComponent>(uid);
|
RemComp<AutoEmoteComponent>(ent.Owner);
|
||||||
var damageSpec = new DamageSpecifier(_prototypeManager.Index(GeneticDamageGroup), 300);
|
_damageableSystem.TryChangeDamage(ent.Owner, ent.Comp.RevertDamage);
|
||||||
_damageableSystem.TryChangeDamage(uid, damageSpec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,52 +62,65 @@ public sealed class CluwneSystem : EntitySystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
|
/// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnComponentStartup(EntityUid uid, CluwneComponent component, ComponentStartup args)
|
private void OnComponentStartup(Entity<CluwneComponent> ent, ref ComponentStartup args)
|
||||||
{
|
{
|
||||||
if (component.EmoteSoundsId == null)
|
if (ent.Comp.EmoteSoundsId == null)
|
||||||
return;
|
return;
|
||||||
_prototypeManager.TryIndex(component.EmoteSoundsId, out EmoteSounds);
|
|
||||||
|
|
||||||
EnsureComp<AutoEmoteComponent>(uid);
|
_prototypeManager.TryIndex(ent.Comp.EmoteSoundsId, out EmoteSounds);
|
||||||
_autoEmote.AddEmote(uid, "CluwneGiggle");
|
|
||||||
EnsureComp<ClumsyComponent>(uid);
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("cluwne-transform", ("target", uid)), uid, PopupType.LargeCaution);
|
|
||||||
_audio.PlayPvs(component.SpawnSound, uid);
|
|
||||||
|
|
||||||
_nameMod.RefreshNameModifiers(uid);
|
if (ent.Comp.RandomEmote && ent.Comp.AutoEmoteId != null)
|
||||||
|
{
|
||||||
|
EnsureComp<AutoEmoteComponent>(ent.Owner);
|
||||||
|
_autoEmote.AddEmote(ent.Owner, ent.Comp.AutoEmoteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureComp<ClumsyComponent>(ent.Owner);
|
||||||
|
|
||||||
_outfitSystem.SetOutfit(uid, "CluwneGear");
|
var transformMessage = Loc.GetString(ent.Comp.TransformMessage, ("target", ent.Owner));
|
||||||
|
|
||||||
|
_popupSystem.PopupEntity(transformMessage, ent.Owner, PopupType.LargeCaution);
|
||||||
|
_audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
|
||||||
|
|
||||||
|
_nameMod.RefreshNameModifiers(ent.Owner);
|
||||||
|
|
||||||
|
|
||||||
|
_outfitSystem.SetOutfit(ent.Owner, ent.Comp.OutfitId, unremovable: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the timing on autoemote as well as falling over and honking.
|
/// Handles the timing on autoemote as well as falling over and honking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnEmote(EntityUid uid, CluwneComponent component, ref EmoteEvent args)
|
private void OnEmote(Entity<CluwneComponent> ent, ref EmoteEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
args.Handled = _chat.TryPlayEmoteSound(uid, EmoteSounds, args.Emote);
|
|
||||||
|
|
||||||
if (_robustRandom.Prob(component.GiggleRandomChance))
|
if (!ent.Comp.RandomEmote)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = _chat.TryPlayEmoteSound(ent.Owner, EmoteSounds, args.Emote);
|
||||||
|
|
||||||
|
if (_robustRandom.Prob(ent.Comp.GiggleRandomChance))
|
||||||
{
|
{
|
||||||
_audio.PlayPvs(component.SpawnSound, uid);
|
_audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
|
||||||
_chat.TrySendInGameICMessage(uid, "honks", InGameICChatType.Emote, ChatTransmitRange.Normal);
|
_chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.GiggleEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (_robustRandom.Prob(component.KnockChance))
|
else if (_robustRandom.Prob(ent.Comp.KnockChance))
|
||||||
{
|
{
|
||||||
_audio.PlayPvs(component.KnockSound, uid);
|
_audio.PlayPvs(ent.Comp.KnockSound, ent.Owner);
|
||||||
_stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(component.ParalyzeTime));
|
_stunSystem.TryUpdateParalyzeDuration(ent.Owner, TimeSpan.FromSeconds(ent.Comp.ParalyzeTime));
|
||||||
_chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
|
_chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.KnockEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies "Cluwnified" prefix
|
/// Applies "Cluwnified" prefix
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnRefreshNameModifiers(Entity<CluwneComponent> entity, ref RefreshNameModifiersEvent args)
|
private void OnRefreshNameModifiers(Entity<CluwneComponent> ent, ref RefreshNameModifiersEvent args)
|
||||||
{
|
{
|
||||||
args.AddModifier("cluwne-name-prefix");
|
args.AddModifier(ent.Comp.NamePrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
using Content.Server.UserInterface;
|
|
||||||
using Content.Shared.Crayon;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Server.Crayon
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class CrayonComponent : SharedCrayonComponent
|
|
||||||
{
|
|
||||||
[DataField("useSound")] public SoundSpecifier? UseSound;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("selectableColor")]
|
|
||||||
public bool SelectableColor { get; set; }
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public int Charges { get; set; }
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("capacity")]
|
|
||||||
public int Capacity { get; set; } = 30;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("deleteEmpty")]
|
|
||||||
public bool DeleteEmpty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ using System.Numerics;
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Decals;
|
using Content.Server.Decals;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Shared.Charges.Systems;
|
||||||
using Content.Shared.Crayon;
|
using Content.Shared.Crayon;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Decals;
|
using Content.Shared.Decals;
|
||||||
@@ -12,7 +13,6 @@ using Content.Shared.Nutrition.EntitySystems;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Crayon;
|
namespace Content.Server.Crayon;
|
||||||
@@ -24,23 +24,27 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
|||||||
[Dependency] private readonly DecalSystem _decals = default!;
|
[Dependency] private readonly DecalSystem _decals = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedChargesSystem _charges = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<CrayonComponent, ComponentInit>(OnCrayonInit);
|
|
||||||
|
SubscribeLocalEvent<CrayonComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI);
|
SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI);
|
||||||
SubscribeLocalEvent<CrayonComponent, CrayonColorMessage>(OnCrayonBoundUIColor);
|
SubscribeLocalEvent<CrayonComponent, CrayonColorMessage>(OnCrayonBoundUIColor);
|
||||||
SubscribeLocalEvent<CrayonComponent, UseInHandEvent>(OnCrayonUse, before: new[] { typeof(FoodSystem) });
|
SubscribeLocalEvent<CrayonComponent, UseInHandEvent>(OnCrayonUse, before: new[] { typeof(FoodSystem) });
|
||||||
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(OnCrayonAfterInteract, after: new[] { typeof(FoodSystem) });
|
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(OnCrayonAfterInteract, after: new[] { typeof(FoodSystem) });
|
||||||
SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped);
|
SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped);
|
||||||
SubscribeLocalEvent<CrayonComponent, ComponentGetState>(OnCrayonGetState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnCrayonGetState(EntityUid uid, CrayonComponent component, ref ComponentGetState args)
|
private void OnMapInit(Entity<CrayonComponent> ent, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
args.State = new CrayonComponentState(component.Color, component.SelectedState, component.Charges, component.Capacity);
|
// Get the first one from the catalog and set it as default
|
||||||
|
var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
|
||||||
|
ent.Comp.SelectedState = decal?.ID ?? string.Empty;
|
||||||
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, AfterInteractEvent args)
|
private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, AfterInteractEvent args)
|
||||||
@@ -48,7 +52,7 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
|||||||
if (args.Handled || !args.CanReach)
|
if (args.Handled || !args.CanReach)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (component.Charges <= 0)
|
if (_charges.IsEmpty(uid))
|
||||||
{
|
{
|
||||||
if (component.DeleteEmpty)
|
if (component.DeleteEmpty)
|
||||||
UseUpCrayon(uid, args.User);
|
UseUpCrayon(uid, args.User);
|
||||||
@@ -72,17 +76,15 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
|||||||
if (component.UseSound != null)
|
if (component.UseSound != null)
|
||||||
_audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f));
|
_audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f));
|
||||||
|
|
||||||
// Decrease "Ammo"
|
_charges.TryUseCharge(uid);
|
||||||
component.Charges--;
|
|
||||||
Dirty(uid, component);
|
|
||||||
|
|
||||||
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
|
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
|
|
||||||
if (component.DeleteEmpty && component.Charges <= 0)
|
if (component.DeleteEmpty && _charges.IsEmpty(uid))
|
||||||
UseUpCrayon(uid, args.User);
|
UseUpCrayon(uid, args.User);
|
||||||
else
|
else
|
||||||
_uiSystem.ServerSendUiMessage(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
|
_uiSystem.ServerSendUiMessage(uid, CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
|
private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
|
||||||
@@ -91,14 +93,12 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
|||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_uiSystem.HasUi(uid, SharedCrayonComponent.CrayonUiKey.Key))
|
if (!_uiSystem.HasUi(uid, CrayonUiKey.Key))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
_uiSystem.TryToggleUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
|
_uiSystem.TryToggleUi(uid, CrayonUiKey.Key, args.User);
|
||||||
|
|
||||||
_uiSystem.SetUiState(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color));
|
_uiSystem.SetUiState(uid, CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color));
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,35 +109,23 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
component.SelectedState = args.State;
|
component.SelectedState = args.State;
|
||||||
|
|
||||||
Dirty(uid, component);
|
Dirty(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCrayonBoundUIColor(EntityUid uid, CrayonComponent component, CrayonColorMessage args)
|
private void OnCrayonBoundUIColor(EntityUid uid, CrayonComponent component, CrayonColorMessage args)
|
||||||
{
|
{
|
||||||
// you still need to ensure that the given color is a valid color
|
// Ensure that the given color can be changed or already matches
|
||||||
if (!component.SelectableColor || args.Color == component.Color)
|
if (!component.SelectableColor || args.Color == component.Color)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
component.Color = args.Color;
|
component.Color = args.Color;
|
||||||
Dirty(uid, component);
|
Dirty(uid, component);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
component.Charges = component.Capacity;
|
|
||||||
|
|
||||||
// Get the first one from the catalog and set it as default
|
|
||||||
var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
|
|
||||||
component.SelectedState = decal?.ID ?? string.Empty;
|
|
||||||
Dirty(uid, component);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args)
|
private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args)
|
||||||
{
|
{
|
||||||
// TODO: Use the existing event.
|
// TODO: Use the existing event.
|
||||||
_uiSystem.CloseUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
|
_uiSystem.CloseUi(uid, CrayonUiKey.Key, args.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UseUpCrayon(EntityUid uid, EntityUid user)
|
private void UseUpCrayon(EntityUid uid, EntityUid user)
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
using Content.Server.Damage.Systems;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
|
|
||||||
namespace Content.Server.Damage.Components
|
|
||||||
{
|
|
||||||
[Access(typeof(DamageOtherOnHitSystem))]
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class DamageOtherOnHitComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("ignoreResistances")]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool IgnoreResistances = false;
|
|
||||||
|
|
||||||
[DataField("damage", required: true)]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public DamageSpecifier Damage = default!;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +1,54 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Damage.Components;
|
|
||||||
using Content.Server.Weapons.Ranged.Systems;
|
using Content.Server.Weapons.Ranged.Systems;
|
||||||
using Content.Shared.CombatMode.Pacification;
|
|
||||||
using Content.Shared.Camera;
|
using Content.Shared.Camera;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Events;
|
using Content.Shared.Damage.Components;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Effects;
|
using Content.Shared.Effects;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Content.Shared.Wires;
|
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Damage.Systems
|
namespace Content.Server.Damage.Systems;
|
||||||
|
|
||||||
|
public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem
|
||||||
{
|
{
|
||||||
public sealed class DamageOtherOnHitSystem : EntitySystem
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] private readonly GunSystem _guns = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
[Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
|
||||||
|
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
base.Initialize();
|
||||||
[Dependency] private readonly GunSystem _guns = default!;
|
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
||||||
[Dependency] private readonly DamageExamineSystem _damageExamine = default!;
|
|
||||||
[Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
|
|
||||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
|
||||||
|
{
|
||||||
|
if (TerminatingOrDeleted(args.Target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
|
||||||
|
|
||||||
|
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
|
||||||
|
if (dmg != null && HasComp<MobStateComponent>(args.Target))
|
||||||
|
_adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
|
||||||
|
|
||||||
|
if (dmg is { Empty: false })
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
|
_color.RaiseEffect(Color.Red, [args.Target], Filter.Pvs(args.Target, entityManager: EntityManager));
|
||||||
SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
|
|
||||||
SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
|
_guns.PlayImpactSound(args.Target, dmg, null, false);
|
||||||
|
if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
|
||||||
{
|
{
|
||||||
if (TerminatingOrDeleted(args.Target))
|
var direction = body.LinearVelocity.Normalized();
|
||||||
return;
|
_sharedCameraRecoil.KickCamera(args.Target, direction);
|
||||||
|
|
||||||
var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
|
|
||||||
|
|
||||||
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
|
|
||||||
if (dmg != null && HasComp<MobStateComponent>(args.Target))
|
|
||||||
_adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
|
|
||||||
|
|
||||||
if (dmg is { Empty: false })
|
|
||||||
{
|
|
||||||
_color.RaiseEffect(Color.Red, new List<EntityUid>() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager));
|
|
||||||
}
|
|
||||||
|
|
||||||
_guns.PlayImpactSound(args.Target, dmg, null, false);
|
|
||||||
if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
|
|
||||||
{
|
|
||||||
var direction = body.LinearVelocity.Normalized();
|
|
||||||
_sharedCameraRecoil.KickCamera(args.Target, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDamageExamine(EntityUid uid, DamageOtherOnHitComponent component, ref DamageExamineEvent args)
|
|
||||||
{
|
|
||||||
_damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(component.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prevent players with the Pacified status effect from throwing things that deal damage.
|
|
||||||
/// </summary>
|
|
||||||
private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
|
|
||||||
{
|
|
||||||
args.Cancel("pacified-cannot-throw");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,6 +404,9 @@ public sealed class HolopadSystem : SharedHolopadSystem
|
|||||||
if (!this.IsPowered(entity, EntityManager))
|
if (!this.IsPowered(entity, EntityManager))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (HasComp<StationAiCoreComponent>(entity))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!TryComp<TelephoneComponent>(entity, out var entityTelephone) ||
|
if (!TryComp<TelephoneComponent>(entity, out var entityTelephone) ||
|
||||||
_telephoneSystem.IsTelephoneEngaged((entity, entityTelephone)))
|
_telephoneSystem.IsTelephoneEngaged((entity, entityTelephone)))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Shared.Emag.Systems;
|
||||||
|
|
||||||
|
namespace Content.Server.NPC.HTN.Preconditions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A precondition which is met if the NPC is emagged with <see cref="EmagType"/>, as computed by
|
||||||
|
/// <see cref="EmagSystem.CheckFlag"/>. This is useful for changing NPC behavior in the case that the NPC is emagged,
|
||||||
|
/// eg. like a helper NPC bot turning evil.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class IsEmaggedPrecondition : HTNPrecondition
|
||||||
|
{
|
||||||
|
private EmagSystem _emag;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of emagging to check for.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EmagType EmagType = EmagType.Interaction;
|
||||||
|
|
||||||
|
public override void Initialize(IEntitySystemManager sysManager)
|
||||||
|
{
|
||||||
|
base.Initialize(sysManager);
|
||||||
|
_emag = sysManager.GetEntitySystem<EmagSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsMet(NPCBlackboard blackboard)
|
||||||
|
{
|
||||||
|
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||||
|
return _emag.CheckFlag(owner, EmagType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Interactions;
|
||||||
|
using Content.Shared.CombatMode;
|
||||||
|
using Content.Shared.Weapons.Melee;
|
||||||
|
|
||||||
|
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Something between <see cref="MeleeOperator"/> and <see cref="InteractWithOperator"/>, this operator causes the NPC
|
||||||
|
/// to attempt a SINGLE <see cref="SharedMeleeWeaponSystem.AttemptLightAttack">melee attack</see> on the specified
|
||||||
|
/// <see cref="TargetKey">target</see>.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class MeleeAttackOperator : HTNOperator
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
private SharedMeleeWeaponSystem _melee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key that contains the target entity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string TargetKey = default!;
|
||||||
|
|
||||||
|
public override void Initialize(IEntitySystemManager sysManager)
|
||||||
|
{
|
||||||
|
base.Initialize(sysManager);
|
||||||
|
_melee = sysManager.GetEntitySystem<SharedMeleeWeaponSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
|
||||||
|
{
|
||||||
|
base.TaskShutdown(blackboard, status);
|
||||||
|
|
||||||
|
ExitCombatMode(blackboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PlanShutdown(NPCBlackboard blackboard)
|
||||||
|
{
|
||||||
|
base.PlanShutdown(blackboard);
|
||||||
|
|
||||||
|
ExitCombatMode(blackboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
||||||
|
{
|
||||||
|
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||||
|
|
||||||
|
if (!_entManager.TryGetComponent<CombatModeComponent>(owner, out var combatMode) ||
|
||||||
|
!_melee.TryGetWeapon(owner, out var weaponUid, out var weapon))
|
||||||
|
{
|
||||||
|
return HTNOperatorStatus.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
_entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, true, combatMode);
|
||||||
|
|
||||||
|
|
||||||
|
if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager) ||
|
||||||
|
!_melee.AttemptLightAttack(owner, weaponUid, weapon, target))
|
||||||
|
{
|
||||||
|
return HTNOperatorStatus.Continuing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HTNOperatorStatus.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExitCombatMode(NPCBlackboard blackboard)
|
||||||
|
{
|
||||||
|
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||||
|
_entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
|
using Content.Shared.Dataset;
|
||||||
|
using Content.Shared.Random.Helpers;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using static Content.Server.NPC.HTN.PrimitiveTasks.Operators.SpeakOperator.SpeakOperatorSpeech;
|
||||||
|
|
||||||
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
|
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
|
||||||
|
|
||||||
public sealed partial class SpeakOperator : HTNOperator
|
public sealed partial class SpeakOperator : HTNOperator
|
||||||
{
|
{
|
||||||
private ChatSystem _chat = default!;
|
private ChatSystem _chat = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
|
||||||
[DataField(required: true)]
|
[DataField(required: true)]
|
||||||
public string Speech = string.Empty;
|
public SpeakOperatorSpeech Speech;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to hide message from chat window and logs.
|
/// Whether to hide message from chat window and logs.
|
||||||
@@ -18,15 +26,51 @@ public sealed partial class SpeakOperator : HTNOperator
|
|||||||
public override void Initialize(IEntitySystemManager sysManager)
|
public override void Initialize(IEntitySystemManager sysManager)
|
||||||
{
|
{
|
||||||
base.Initialize(sysManager);
|
base.Initialize(sysManager);
|
||||||
|
|
||||||
_chat = sysManager.GetEntitySystem<ChatSystem>();
|
_chat = sysManager.GetEntitySystem<ChatSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
||||||
{
|
{
|
||||||
|
LocId speechLocId;
|
||||||
|
switch (Speech)
|
||||||
|
{
|
||||||
|
case LocalizedSetSpeakOperatorSpeech localizedDataSet:
|
||||||
|
if (!_proto.TryIndex(localizedDataSet.LineSet, out var speechSet))
|
||||||
|
return HTNOperatorStatus.Failed;
|
||||||
|
speechLocId = _random.Pick(speechSet);
|
||||||
|
break;
|
||||||
|
case SingleSpeakOperatorSpeech single:
|
||||||
|
speechLocId = single.Line;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(Speech));
|
||||||
|
}
|
||||||
|
|
||||||
var speaker = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
var speaker = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||||
_chat.TrySendInGameICMessage(speaker, Loc.GetString(Speech), InGameICChatType.Speak, hideChat: Hidden, hideLog: Hidden);
|
_chat.TrySendInGameICMessage(
|
||||||
|
speaker,
|
||||||
|
Loc.GetString(speechLocId),
|
||||||
|
InGameICChatType.Speak,
|
||||||
|
hideChat: Hidden,
|
||||||
|
hideLog: Hidden
|
||||||
|
);
|
||||||
|
|
||||||
return base.Update(blackboard, frameTime);
|
return base.Update(blackboard, frameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ImplicitDataDefinitionForInheritors, MeansImplicitUse]
|
||||||
|
public abstract partial class SpeakOperatorSpeech
|
||||||
|
{
|
||||||
|
public sealed partial class SingleSpeakOperatorSpeech : SpeakOperatorSpeech
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class LocalizedSetSpeakOperatorSpeech : SpeakOperatorSpeech
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public ProtoId<LocalizedDatasetPrototype> LineSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises an <see cref="HTNRaisedEvent"/> on the <see cref="NPCBlackboard.Owner">owner</see>. The event will contain
|
||||||
|
/// the specified <see cref="Args"/>, and if not null, the value of <see cref="TargetKey"/>.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class RaiseEventForOwnerOperator : HTNOperator
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The conceptual "target" of this event. Note that this is NOT the entity for which the event is raised. If null,
|
||||||
|
/// <see cref="HTNRaisedEvent.Target"/> will be null.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string? TargetKey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data contained in the raised event. Since <see cref="HTNRaisedEvent"/> is itself pretty meaningless, this is
|
||||||
|
/// included to give some context of what the event is actually supposed to mean.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public EntityEventArgs Args;
|
||||||
|
|
||||||
|
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
||||||
|
{
|
||||||
|
_entMan.EventBus.RaiseLocalEvent(
|
||||||
|
blackboard.GetValue<EntityUid>(NPCBlackboard.Owner),
|
||||||
|
new HTNRaisedEvent(
|
||||||
|
blackboard.GetValue<EntityUid>(NPCBlackboard.Owner),
|
||||||
|
TargetKey is { } targetKey ? blackboard.GetValue<EntityUid>(targetKey) : null,
|
||||||
|
Args
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return HTNOperatorStatus.Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class HTNRaisedEvent(EntityUid owner, EntityUid? target, EntityEventArgs args) : EntityEventArgs
|
||||||
|
{
|
||||||
|
// Owner and target are both included here in case we want to add a "RaiseEventForTargetOperator" in the future
|
||||||
|
// while reusing this event.
|
||||||
|
public EntityUid Owner = owner;
|
||||||
|
public EntityUid? Target = target;
|
||||||
|
public EntityEventArgs Args = args;
|
||||||
|
}
|
||||||
@@ -9,4 +9,11 @@ public sealed partial class ComponentFilter : UtilityQueryFilter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("components", required: true)]
|
[DataField("components", required: true)]
|
||||||
public ComponentRegistry Components = new();
|
public ComponentRegistry Components = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, this filter retains entities with ALL of the specified components. If false, this filter removes
|
||||||
|
/// entities with ANY of the specified components.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool RetainWithComp = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,11 +516,12 @@ public sealed class NPCUtilitySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
foreach (var comp in compFilter.Components)
|
foreach (var comp in compFilter.Components)
|
||||||
{
|
{
|
||||||
if (HasComp(ent, comp.Value.Component.GetType()))
|
var hasComp = HasComp(ent, comp.Value.Component.GetType());
|
||||||
continue;
|
if (!compFilter.RetainWithComp == hasComp)
|
||||||
|
{
|
||||||
_entityList.Add(ent);
|
_entityList.Add(ent);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Ninja.Systems;
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Objectives.Systems;
|
using Content.Server.Objectives.Systems;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Components;
|
namespace Content.Server.Objectives.Components;
|
||||||
|
|
||||||
@@ -14,4 +15,11 @@ public sealed partial class SpiderChargeConditionComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
public EntityUid? Target;
|
public EntityUid? Target;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tags that should be used to exclude Warp Points
|
||||||
|
/// from the list of valid bombing targets
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityWhitelist? Blacklist;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Content.Server.Objectives.Components;
|
using Content.Server.Objectives.Components;
|
||||||
using Content.Shared.Objectives.Components;
|
using Content.Shared.Objectives.Components;
|
||||||
using Content.Shared.Ninja.Components;
|
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Roles.Components;
|
using Content.Shared.Roles.Components;
|
||||||
using Content.Shared.Warps;
|
using Content.Shared.Warps;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Systems;
|
namespace Content.Server.Objectives.Systems;
|
||||||
@@ -14,6 +14,7 @@ namespace Content.Server.Objectives.Systems;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class NinjaConditionsSystem : EntitySystem
|
public sealed class NinjaConditionsSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||||
[Dependency] private readonly NumberObjectiveSystem _number = default!;
|
[Dependency] private readonly NumberObjectiveSystem _number = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
@@ -53,10 +54,13 @@ public sealed class NinjaConditionsSystem : EntitySystem
|
|||||||
|
|
||||||
// choose spider charge detonation point
|
// choose spider charge detonation point
|
||||||
var warps = new List<EntityUid>();
|
var warps = new List<EntityUid>();
|
||||||
var query = EntityQueryEnumerator<BombingTargetComponent, WarpPointComponent>();
|
var allEnts = EntityQueryEnumerator<WarpPointComponent>();
|
||||||
while (query.MoveNext(out var warpUid, out _, out var warp))
|
var bombingBlacklist = comp.Blacklist;
|
||||||
|
|
||||||
|
while (allEnts.MoveNext(out var warpUid, out var warp))
|
||||||
{
|
{
|
||||||
if (warp.Location != null)
|
if (_whitelist.IsBlacklistFail(bombingBlacklist, warpUid)
|
||||||
|
&& !string.IsNullOrWhiteSpace(warp.Location))
|
||||||
{
|
{
|
||||||
warps.Add(warpUid);
|
warps.Add(warpUid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
if (!Resolve(uid, ref battery))
|
if (!Resolve(uid, ref battery))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var newValue = Math.Clamp(0, battery.CurrentCharge + value, battery.MaxCharge);
|
var newValue = Math.Clamp(battery.CurrentCharge + value, 0, battery.MaxCharge);
|
||||||
var delta = newValue - battery.CurrentCharge;
|
var delta = newValue - battery.CurrentCharge;
|
||||||
battery.CurrentCharge = newValue;
|
battery.CurrentCharge = newValue;
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Content.Server.PowerSink
|
|||||||
if (!transform.Anchored)
|
if (!transform.Anchored)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_battery.SetCharge(entity, battery.CurrentCharge + networkLoad.NetworkLoad.ReceivingPower / 1000, battery);
|
_battery.ChangeCharge(entity, networkLoad.NetworkLoad.ReceivingPower * frameTime, battery);
|
||||||
|
|
||||||
var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
|
var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
|
||||||
|
|
||||||
|
|||||||
65
Content.Server/Silicons/Bots/HugBotSystem.cs
Normal file
65
Content.Server/Silicons/Bots/HugBotSystem.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
|
||||||
|
using Content.Shared.Silicons.Bots;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.Silicons.Bots;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Beyond what <see cref="SharedHugBotSystem"/> does, this system manages the "lifecycle" of
|
||||||
|
/// <see cref="RecentlyHuggedByHugBotComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HugBotSystem : SharedHugBotSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<HugBotComponent, HTNRaisedEvent>(OnHtnRaisedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHtnRaisedEvent(Entity<HugBotComponent> entity, ref HTNRaisedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Args is not HugBotDidHugEvent ||
|
||||||
|
args.Target is not {} target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ev = new HugBotHugEvent(GetNetEntity(entity));
|
||||||
|
RaiseLocalEvent(target, ev);
|
||||||
|
|
||||||
|
ApplyHugBotCooldown(entity, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies <see cref="RecentlyHuggedByHugBotComponent"/> to <paramref name="target"/> based on the configuration of
|
||||||
|
/// <paramref name="hugBot"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void ApplyHugBotCooldown(Entity<HugBotComponent> hugBot, EntityUid target)
|
||||||
|
{
|
||||||
|
var hugged = EnsureComp<RecentlyHuggedByHugBotComponent>(target);
|
||||||
|
hugged.CooldownCompleteAfter = _gameTiming.CurTime + hugBot.Comp.HugCooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
// Iterate through all RecentlyHuggedByHugBot entities...
|
||||||
|
var huggedEntities = AllEntityQuery<RecentlyHuggedByHugBotComponent>();
|
||||||
|
while (huggedEntities.MoveNext(out var huggedEnt, out var huggedComp))
|
||||||
|
{
|
||||||
|
// ... and if their cooldown is complete...
|
||||||
|
if (huggedComp.CooldownCompleteAfter <= _gameTiming.CurTime)
|
||||||
|
{
|
||||||
|
// ... remove it, allowing them to receive the blessing of hugs once more.
|
||||||
|
RemCompDeferred<RecentlyHuggedByHugBotComponent>(huggedEnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is indirectly raised (by being <see cref="HTNRaisedEvent.Args"/>) on a HugBot when it hugs (or emaggedly
|
||||||
|
/// punches) an entity.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, DataDefinition]
|
||||||
|
public sealed partial class HugBotDidHugEvent : EntityEventArgs;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Content.Shared.Silicons.Bots;
|
||||||
|
|
||||||
|
namespace Content.Server.Silicons.Bots;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This marker component indicates that its entity has been recently hugged by a HugBot and should not be hugged again
|
||||||
|
/// before <see cref="CooldownCompleteAfter">a cooldown period</see> in order to prevent hug spam.
|
||||||
|
/// </summary>
|
||||||
|
/// <see cref="SharedHugBotSystem"/>
|
||||||
|
[RegisterComponent, AutoGenerateComponentPause]
|
||||||
|
public sealed partial class RecentlyHuggedByHugBotComponent : Component
|
||||||
|
{
|
||||||
|
[DataField, AutoPausedField]
|
||||||
|
public TimeSpan CooldownCompleteAfter = TimeSpan.MinValue;
|
||||||
|
}
|
||||||
@@ -176,9 +176,10 @@ public sealed class SingularityGeneratorSystem : SharedSingularityGeneratorSyste
|
|||||||
|
|
||||||
foreach (var result in rayCastResults)
|
foreach (var result in rayCastResults)
|
||||||
{
|
{
|
||||||
if (genQuery.HasComponent(result.HitEntity))
|
if (!genQuery.HasComponent(result.HitEntity))
|
||||||
closestResult = result;
|
continue;
|
||||||
|
|
||||||
|
closestResult = result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Movement.Systems;
|
using Content.Server.Movement.Systems;
|
||||||
using Content.Shared.Damage.Events;
|
|
||||||
using Content.Shared.Damage.Systems;
|
|
||||||
using Content.Shared.Effects;
|
using Content.Shared.Effects;
|
||||||
using Content.Shared.Speech.Components;
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
@@ -16,28 +14,14 @@ namespace Content.Server.Weapons.Melee;
|
|||||||
public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ChatSystem _chat = default!;
|
[Dependency] private readonly ChatSystem _chat = default!;
|
||||||
[Dependency] private readonly DamageExamineSystem _damageExamine = default!;
|
|
||||||
[Dependency] private readonly LagCompensationSystem _lag = default!;
|
[Dependency] private readonly LagCompensationSystem _lag = default!;
|
||||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
|
SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
|
||||||
SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
|
|
||||||
{
|
|
||||||
if (component.Hidden)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var damageSpec = GetDamage(uid, args.User, component);
|
|
||||||
|
|
||||||
if (damageSpec.Empty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ArcRaySuccessful(EntityUid targetUid,
|
protected override bool ArcRaySuccessful(EntityUid targetUid,
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Damage.Events;
|
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.PowerCell.Components;
|
using Content.Shared.PowerCell.Components;
|
||||||
using Content.Shared.Projectiles;
|
|
||||||
using Content.Shared.Weapons.Ranged;
|
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Content.Shared.Weapons.Ranged.Events;
|
using Content.Shared.Weapons.Ranged.Events;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Weapons.Ranged.Systems;
|
namespace Content.Server.Weapons.Ranged.Systems;
|
||||||
|
|
||||||
@@ -19,13 +14,11 @@ public sealed partial class GunSystem
|
|||||||
// Hitscan
|
// Hitscan
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
||||||
|
|
||||||
// Projectile
|
// Projectile
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,50 +66,6 @@ public sealed partial class GunSystem
|
|||||||
RaiseLocalEvent(uid, ref updateAmmoEv);
|
RaiseLocalEvent(uid, ref updateAmmoEv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
|
|
||||||
{
|
|
||||||
var damageSpec = GetDamage(entity.Comp);
|
|
||||||
|
|
||||||
if (damageSpec == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var damageType = entity.Comp switch
|
|
||||||
{
|
|
||||||
HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
|
|
||||||
ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
|
|
||||||
_ => throw new ArgumentOutOfRangeException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
|
|
||||||
{
|
|
||||||
if (component is ProjectileBatteryAmmoProviderComponent battery)
|
|
||||||
{
|
|
||||||
if (ProtoManager.Index<EntityPrototype>(battery.Prototype).Components
|
|
||||||
.TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
|
|
||||||
{
|
|
||||||
var p = (ProjectileComponent) projectile.Component;
|
|
||||||
|
|
||||||
if (!p.Damage.Empty)
|
|
||||||
{
|
|
||||||
return p.Damage * Damageable.UniversalProjectileDamageModifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component is HitscanBatteryAmmoProviderComponent hitscan)
|
|
||||||
{
|
|
||||||
var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
|
|
||||||
return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
|
protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
|
||||||
{
|
{
|
||||||
var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
|
var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
|
||||||
|
|||||||
@@ -1,87 +1,25 @@
|
|||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Popups;
|
|
||||||
using Content.Server.Power.EntitySystems;
|
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Power;
|
|
||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Content.Shared.Xenoarchaeology.Equipment;
|
using Content.Shared.Xenoarchaeology.Equipment;
|
||||||
using Content.Shared.Xenoarchaeology.Equipment.Components;
|
using Content.Shared.Xenoarchaeology.Equipment.Components;
|
||||||
using Robust.Shared.Collections;
|
using Robust.Shared.Collections;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
|
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
|
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly BodySystem _body = default!;
|
[Dependency] private readonly BodySystem _body = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
||||||
[Dependency] private readonly StackSystem _stack = default!;
|
[Dependency] private readonly StackSystem _stack = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
// TODO: Move to shared once StackSystem spawning is in Shared and we have RandomPredicted
|
||||||
public override void Initialize()
|
public override void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ArtifactCrusherComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
|
|
||||||
SubscribeLocalEvent<ArtifactCrusherComponent, PowerChangedEvent>(OnPowerChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGetVerbs(Entity<ArtifactCrusherComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp<EntityStorageComponent>(ent, out var entityStorageComp) ||
|
|
||||||
entityStorageComp.Contents.ContainedEntities.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!this.IsPowered(ent, EntityManager))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var verb = new AlternativeVerb
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
|
|
||||||
Priority = 2,
|
|
||||||
Act = () => StartCrushing((ent, ent.Comp, entityStorageComp))
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPowerChanged(Entity<ArtifactCrusherComponent> ent, ref PowerChangedEvent args)
|
|
||||||
{
|
|
||||||
if (!args.Powered)
|
|
||||||
StopCrushing(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
|
|
||||||
{
|
|
||||||
var (uid, crusher, _) = ent;
|
|
||||||
|
|
||||||
if (crusher.Crushing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (crusher.AutoLock)
|
|
||||||
_popup.PopupEntity(Loc.GetString("artifact-crusher-autolocks-enable"), uid);
|
|
||||||
|
|
||||||
crusher.Crushing = true;
|
|
||||||
crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
|
|
||||||
crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
|
|
||||||
crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent);
|
|
||||||
Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
|
|
||||||
Dirty(ent, ent.Comp1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
|
|
||||||
{
|
{
|
||||||
var (_, crusher, storage) = ent;
|
var (_, crusher, storage) = ent;
|
||||||
StopCrushing((ent, ent.Comp1), false);
|
StopCrushing((ent, ent.Comp1), false);
|
||||||
@@ -113,32 +51,4 @@ public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<ArtifactCrusherComponent, EntityStorageComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var crusher, out var storage))
|
|
||||||
{
|
|
||||||
if (!crusher.Crushing)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (crusher.NextSecond < _timing.CurTime)
|
|
||||||
{
|
|
||||||
var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
|
|
||||||
foreach (var contained in contents)
|
|
||||||
{
|
|
||||||
_damageable.TryChangeDamage(contained, crusher.CrushingDamage);
|
|
||||||
}
|
|
||||||
crusher.NextSecond += TimeSpan.FromSeconds(1);
|
|
||||||
Dirty(uid, crusher);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crusher.CrushEndTime < _timing.CurTime)
|
|
||||||
{
|
|
||||||
FinishCrushing((uid, crusher, storage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Content.Shared.Chat.Prototypes;
|
using Content.Shared.Chat.Prototypes;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Roles;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Shared.Cluwne;
|
namespace Content.Shared.Cluwne;
|
||||||
@@ -12,22 +15,74 @@ public sealed partial class CluwneComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// timings for giggles and knocks.
|
/// timings for giggles and knocks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField]
|
||||||
public TimeSpan DamageGiggleCooldown = TimeSpan.FromSeconds(2);
|
public TimeSpan DamageGiggleCooldown = TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
|
/// Amount of genetic damage dealt when they revert
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public DamageSpecifier RevertDamage = new()
|
||||||
|
{
|
||||||
|
DamageDict = new()
|
||||||
|
{
|
||||||
|
{ "Genetic", 300.0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Chance that the Cluwne will be knocked over and paralyzed.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public float KnockChance = 0.05f;
|
public float KnockChance = 0.05f;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
|
/// Chance that the Cluwne will randomly giggle
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public float GiggleRandomChance = 0.1f;
|
public float GiggleRandomChance = 0.1f;
|
||||||
|
|
||||||
[DataField("emoteId", customTypeSerializer: typeof(PrototypeIdSerializer<EmoteSoundsPrototype>))]
|
/// <summary>
|
||||||
public string? EmoteSoundsId = "Cluwne";
|
/// Enable random emoting?
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool RandomEmote = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emote sound collection that the Cluwne should use.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("emoteId")]
|
||||||
|
public ProtoId<EmoteSoundsPrototype>? EmoteSoundsId = "Cluwne";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emote to use for the Cluwne Giggling
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<AutoEmotePrototype>? AutoEmoteId = "CluwneGiggle";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message to popup when the Cluwne is transformed
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId TransformMessage = "cluwne-transform";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name prefix for the Cluwne.
|
||||||
|
/// Example "Urist McHuman" will be "Cluwned Urist McHuman"
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId NamePrefix = "cluwne-name-prefix";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outfit ID that the cluwne will spawn with.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<StartingGearPrototype> OutfitId = "CluwneGear";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Amount of time cluwne is paralyzed for when falling over.
|
/// Amount of time cluwne is paralyzed for when falling over.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField]
|
||||||
public float ParalyzeTime = 2f;
|
public float ParalyzeTime = 2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,6 +91,21 @@ public sealed partial class CluwneComponent : Component
|
|||||||
[DataField("spawnsound")]
|
[DataField("spawnsound")]
|
||||||
public SoundSpecifier SpawnSound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
|
public SoundSpecifier SpawnSound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
|
||||||
|
|
||||||
[DataField("knocksound")]
|
/// <summary>
|
||||||
|
/// Emote to use for the cluwne giggling
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId GiggleEmote = "cluwne-giggle-emote";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sound to play when the Cluwne is knocked over and paralyzed
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Items/airhorn.ogg");
|
public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Items/airhorn.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emote thats used when the cluwne getting knocked over
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId KnockEmote = "cluwne-knock-emote";
|
||||||
}
|
}
|
||||||
|
|||||||
119
Content.Shared/Crayon/CrayonComponent.cs
Normal file
119
Content.Shared/Crayon/CrayonComponent.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Crayon;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component holding the state of a crayon-like component
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(SharedCrayonSystem))]
|
||||||
|
public sealed partial class CrayonComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of currently selected decal prototype that will be placed when the crayon is used.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public string SelectedState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Color with which the crayon will draw.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Color Color;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Play a sound when drawing if specified.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public SoundSpecifier? UseSound;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can the color can be changed?
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool SelectableColor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the crayon be deleted when all charges are consumed?
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool DeleteEmpty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the crayon window for decal and color selection.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum CrayonUiKey : byte
|
||||||
|
{
|
||||||
|
Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used by the client to notify the server about the selected decal ID
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly string State;
|
||||||
|
public CrayonSelectMessage(string selected)
|
||||||
|
{
|
||||||
|
State = selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the color of the crayon, used by Rainbow Crayon
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class CrayonColorMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly Color Color;
|
||||||
|
public CrayonColorMessage(Color color)
|
||||||
|
{
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
|
||||||
|
/// Allows the client UI to advance forward in the client-only ephemeral queue,
|
||||||
|
/// preventing the crayon from becoming a magic text storage device.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly string DrawnDecal;
|
||||||
|
|
||||||
|
public CrayonUsedMessage(string drawn)
|
||||||
|
{
|
||||||
|
DrawnDecal = drawn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The state of the crayon UI as sent by the server
|
||||||
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// TODO: Delete this and use component states and predict the UI.
|
||||||
|
/// This info is already networked on its own.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public string Selected;
|
||||||
|
/// <summary>
|
||||||
|
/// Can the color can be changed
|
||||||
|
/// </summary>
|
||||||
|
public bool SelectableColor;
|
||||||
|
public Color Color;
|
||||||
|
|
||||||
|
public CrayonBoundUserInterfaceState(string selected, bool selectableColor, Color color)
|
||||||
|
{
|
||||||
|
Selected = selected;
|
||||||
|
SelectableColor = selectableColor;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.Crayon
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Component holding the state of a crayon-like component
|
|
||||||
/// </summary>
|
|
||||||
[NetworkedComponent, ComponentProtoName("Crayon"), Access(typeof(SharedCrayonSystem))]
|
|
||||||
public abstract partial class SharedCrayonComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of currently selected decal prototype that will be placed when the crayon is used
|
|
||||||
/// </summary>
|
|
||||||
public string SelectedState { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Color with which the crayon will draw
|
|
||||||
/// </summary>
|
|
||||||
[DataField("color")]
|
|
||||||
public Color Color;
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum CrayonUiKey : byte
|
|
||||||
{
|
|
||||||
Key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used by the client to notify the server about the selected decal ID
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public readonly string State;
|
|
||||||
public CrayonSelectMessage(string selected)
|
|
||||||
{
|
|
||||||
State = selected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the color of the crayon, used by Rainbow Crayon
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class CrayonColorMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public readonly Color Color;
|
|
||||||
public CrayonColorMessage(Color color)
|
|
||||||
{
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
|
|
||||||
/// Allows the client UI to advance forward in the client-only ephemeral queue,
|
|
||||||
/// preventing the crayon from becoming a magic text storage device.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public readonly string DrawnDecal;
|
|
||||||
|
|
||||||
public CrayonUsedMessage(string drawn)
|
|
||||||
{
|
|
||||||
DrawnDecal = drawn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Component state, describes how many charges are left in the crayon in the near-hand UI
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class CrayonComponentState : ComponentState
|
|
||||||
{
|
|
||||||
public readonly Color Color;
|
|
||||||
public readonly string State;
|
|
||||||
public readonly int Charges;
|
|
||||||
public readonly int Capacity;
|
|
||||||
|
|
||||||
public CrayonComponentState(Color color, string state, int charges, int capacity)
|
|
||||||
{
|
|
||||||
Color = color;
|
|
||||||
State = state;
|
|
||||||
Charges = charges;
|
|
||||||
Capacity = capacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The state of the crayon UI as sent by the server
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
|
|
||||||
{
|
|
||||||
public string Selected;
|
|
||||||
/// <summary>
|
|
||||||
/// Whether or not the color can be selected
|
|
||||||
/// </summary>
|
|
||||||
public bool SelectableColor;
|
|
||||||
public Color Color;
|
|
||||||
|
|
||||||
public CrayonBoundUserInterfaceState(string selected, bool selectableColor, Color color)
|
|
||||||
{
|
|
||||||
Selected = selected;
|
|
||||||
SelectableColor = selectableColor;
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,8 @@ using Robust.Shared.GameStates;
|
|||||||
|
|
||||||
namespace Content.Shared.Damage.Components;
|
namespace Content.Shared.Damage.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a detailed examine window with this entity's damage stats when examined.
|
||||||
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class DamageExaminableComponent : Component
|
public sealed partial class DamageExaminableComponent : Component;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Content.Shared.Damage.Systems;
|
||||||
|
|
||||||
|
namespace Content.Shared.Damage.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes this entity deal damage when thrown at something.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[Access(typeof(SharedDamageOtherOnHitSystem))]
|
||||||
|
public sealed partial class DamageOtherOnHitComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to ignore damage modifiers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool IgnoreResistances = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The damage amount to deal on hit.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public DamageSpecifier Damage = default!;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
|
using Content.Shared.Damage.Components;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Damage.Events;
|
namespace Content.Shared.Damage.Events;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity with <see cref="DamageExaminableComponent"/> when examined to get the damage values displayed in the examine window.
|
||||||
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public readonly record struct DamageExamineEvent(FormattedMessage Message, EntityUid User);
|
public readonly record struct DamageExamineEvent(FormattedMessage Message, EntityUid User);
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Shared.CombatMode.Pacification;
|
||||||
|
using Content.Shared.Damage.Components;
|
||||||
|
using Content.Shared.Damage.Events;
|
||||||
|
|
||||||
|
namespace Content.Shared.Damage.Systems;
|
||||||
|
|
||||||
|
public abstract class SharedDamageOtherOnHitSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
[Dependency] private readonly DamageExamineSystem _damageExamine = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
|
||||||
|
SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDamageExamine(Entity<DamageOtherOnHitComponent> ent, ref DamageExamineEvent args)
|
||||||
|
{
|
||||||
|
_damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(ent.Comp.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevent players with the Pacified status effect from throwing things that deal damage.
|
||||||
|
/// </summary>
|
||||||
|
private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
|
||||||
|
{
|
||||||
|
args.Cancel("pacified-cannot-throw");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -214,6 +214,17 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
|||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the entities linked to a specific source port.
|
||||||
|
/// </summary>
|
||||||
|
public HashSet<EntityUid> GetLinkedSinks(Entity<DeviceLinkSourceComponent?> source, ProtoId<SourcePortPrototype> port)
|
||||||
|
{
|
||||||
|
if (!Resolve(source, ref source.Comp) || !source.Comp.Outputs.TryGetValue(port, out var linked))
|
||||||
|
return new HashSet<EntityUid>(); // not a source or not linked
|
||||||
|
|
||||||
|
return new HashSet<EntityUid>(linked); // clone to prevent modifying the original
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the default links for the given list of source port prototypes
|
/// Returns the default links for the given list of source port prototypes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Shared.Ninja.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes this warp point a valid bombing target for ninja's spider charge.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class BombingTargetComponent : Component;
|
|
||||||
@@ -10,21 +10,30 @@ namespace Content.Shared.Physics;
|
|||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class JointVisualsComponent : Component
|
public sealed partial class JointVisualsComponent : Component
|
||||||
{
|
{
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("sprite", required: true), AutoNetworkedField]
|
/// <summary>
|
||||||
|
/// The sprite to use for the line.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true), AutoNetworkedField]
|
||||||
public SpriteSpecifier Sprite = default!;
|
public SpriteSpecifier Sprite = default!;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("target"), AutoNetworkedField]
|
/// <summary>
|
||||||
public NetEntity? Target;
|
/// The line is drawn between this target and the entity owning the component.
|
||||||
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// TODO: WeakEntityReference.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? Target;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Offset from Body A.
|
/// Offset from Body A.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("offsetA"), AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public Vector2 OffsetA;
|
public Vector2 OffsetA;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Offset from Body B.
|
/// Offset from Body B.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("offsetB"), AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public Vector2 OffsetB;
|
public Vector2 OffsetB;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,19 @@ namespace Content.Shared.Roles
|
|||||||
[IdDataField]
|
[IdDataField]
|
||||||
public string ID { get; private set; } = default!;
|
public string ID { get; private set; } = default!;
|
||||||
|
|
||||||
[DataField("playTimeTracker", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
|
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
|
||||||
public string PlayTimeTracker { get; private set; } = string.Empty;
|
public string PlayTimeTracker { get; private set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Who is the supervisor for this job.
|
/// Who is the supervisor for this job.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("supervisors")]
|
[DataField]
|
||||||
public string Supervisors { get; private set; } = "nobody";
|
public LocId Supervisors = "job-supervisors-nobody";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of this job as displayed to players.
|
/// The name of this job as displayed to players.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("name")]
|
[DataField]
|
||||||
public string Name { get; private set; } = string.Empty;
|
public string Name { get; private set; } = string.Empty;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
@@ -38,7 +38,7 @@ namespace Content.Shared.Roles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of this job as displayed to players.
|
/// The name of this job as displayed to players.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("description")]
|
[DataField]
|
||||||
public string? Description { get; private set; }
|
public string? Description { get; private set; }
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
@@ -53,19 +53,19 @@ namespace Content.Shared.Roles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// When true - the station will have anouncement about arrival of this player.
|
/// When true - the station will have anouncement about arrival of this player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("joinNotifyCrew")]
|
[DataField]
|
||||||
public bool JoinNotifyCrew { get; private set; } = false;
|
public bool JoinNotifyCrew { get; private set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When true - the player will recieve a message about importancy of their job.
|
/// When true - the player will recieve a message about importancy of their job.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("requireAdminNotify")]
|
[DataField]
|
||||||
public bool RequireAdminNotify { get; private set; } = false;
|
public bool RequireAdminNotify { get; private set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should this job appear in preferences menu?
|
/// Should this job appear in preferences menu?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("setPreference")]
|
[DataField]
|
||||||
public bool SetPreference { get; private set; } = true;
|
public bool SetPreference { get; private set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -81,14 +81,14 @@ namespace Content.Shared.Roles
|
|||||||
[DataField]
|
[DataField]
|
||||||
public bool? OverrideConsoleVisibility { get; private set; } = null;
|
public bool? OverrideConsoleVisibility { get; private set; } = null;
|
||||||
|
|
||||||
[DataField("canBeAntag")]
|
[DataField]
|
||||||
public bool CanBeAntag { get; private set; } = true;
|
public bool CanBeAntag { get; private set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The "weight" or importance of this job. If this number is large, the job system will assign this job
|
/// The "weight" or importance of this job. If this number is large, the job system will assign this job
|
||||||
/// before assigning other jobs.
|
/// before assigning other jobs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("weight")]
|
[DataField]
|
||||||
public int Weight { get; private set; }
|
public int Weight { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -105,7 +105,7 @@ namespace Content.Shared.Roles
|
|||||||
/// A numerical score for how much easier this job is for antagonists.
|
/// A numerical score for how much easier this job is for antagonists.
|
||||||
/// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting.
|
/// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("antagAdvantage")]
|
[DataField]
|
||||||
public int AntagAdvantage = 0;
|
public int AntagAdvantage = 0;
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
@@ -116,7 +116,7 @@ namespace Content.Shared.Roles
|
|||||||
/// Starting gear will be ignored.
|
/// Starting gear will be ignored.
|
||||||
/// If you want to just add special attributes to a humanoid, use AddComponentSpecial instead.
|
/// If you want to just add special attributes to a humanoid, use AddComponentSpecial instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("jobEntity", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
public string? JobEntity = null;
|
public string? JobEntity = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -129,19 +129,19 @@ namespace Content.Shared.Roles
|
|||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<JobIconPrototype> Icon { get; private set; } = "JobIconUnknown";
|
public ProtoId<JobIconPrototype> Icon { get; private set; } = "JobIconUnknown";
|
||||||
|
|
||||||
[DataField("special", serverOnly: true)]
|
[DataField(serverOnly: true)]
|
||||||
public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
|
public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
|
||||||
|
|
||||||
[DataField("access")]
|
[DataField]
|
||||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||||
|
|
||||||
[DataField("accessGroups")]
|
[DataField]
|
||||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||||
|
|
||||||
[DataField("extendedAccess")]
|
[DataField]
|
||||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||||
|
|
||||||
[DataField("extendedAccessGroups")]
|
[DataField]
|
||||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public abstract class SharedRoleSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] protected readonly ISharedPlayerManager Player = default!;
|
[Dependency] protected readonly ISharedPlayerManager Player = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly SharedMindSystem _minds = default!;
|
[Dependency] private readonly SharedMindSystem _minds = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||||
@@ -400,7 +399,7 @@ public abstract class SharedRoleSystem : EntitySystem
|
|||||||
|
|
||||||
foreach (var role in delete)
|
foreach (var role in delete)
|
||||||
{
|
{
|
||||||
_entityManager.DeleteEntity(role);
|
PredictedDel(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = MindRolesUpdate(mind);
|
var update = MindRolesUpdate(mind);
|
||||||
|
|||||||
@@ -120,5 +120,24 @@ public abstract class SharedBorgSwitchableTypeSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
footstepModifier.FootstepSoundCollection = prototype.FootstepCollection;
|
footstepModifier.FootstepSoundCollection = prototype.FootstepCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prototype.SpriteBodyMovementState is { } movementState)
|
||||||
|
{
|
||||||
|
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
|
||||||
|
spriteMovement.NoMovementLayers.Clear();
|
||||||
|
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
|
||||||
|
{
|
||||||
|
State = prototype.SpriteBodyState,
|
||||||
|
};
|
||||||
|
spriteMovement.MovementLayers.Clear();
|
||||||
|
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
|
||||||
|
{
|
||||||
|
State = movementState,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemComp<SpriteMovementComponent>(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
Content.Shared/Silicons/Bots/HugBotComponent.cs
Normal file
12
Content.Shared/Silicons/Bots/HugBotComponent.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Content.Shared.Silicons.Bots;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component describes how a HugBot hugs.
|
||||||
|
/// </summary>
|
||||||
|
/// <see cref="SharedHugBotSystem"/>
|
||||||
|
[RegisterComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class HugBotComponent : Component
|
||||||
|
{
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public TimeSpan HugCooldown = TimeSpan.FromMinutes(2);
|
||||||
|
}
|
||||||
38
Content.Shared/Silicons/Bots/SharedHugBotSystem.cs
Normal file
38
Content.Shared/Silicons/Bots/SharedHugBotSystem.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Silicons.Bots;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This system handles HugBots.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class SharedHugBotSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly EmagSystem _emag = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<HugBotComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(Entity<HugBotComponent> entity, ref GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (!_emag.CompareFlag(args.Type, EmagType.Interaction) ||
|
||||||
|
_emag.CheckFlag(entity, EmagType.Interaction) ||
|
||||||
|
!TryComp<HugBotComponent>(entity, out var hugBot))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// HugBot HTN checks for emag state within its own logic, so we don't need to change anything here.
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is raised on an entity when it is hugged by a HugBot.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class HugBotHugEvent(NetEntity hugBot) : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly NetEntity HugBot = hugBot;
|
||||||
|
}
|
||||||
@@ -587,7 +587,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
_entList.Add(entity);
|
_entList.Add(entity);
|
||||||
delay += itemSize.Weight * AreaInsertDelayPerItem;
|
delay += itemSize.Weight;
|
||||||
|
|
||||||
if (_entList.Count >= StorageComponent.AreaPickupLimit)
|
if (_entList.Count >= StorageComponent.AreaPickupLimit)
|
||||||
break;
|
break;
|
||||||
@@ -596,7 +596,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||||||
//If there's only one then let's be generous
|
//If there's only one then let's be generous
|
||||||
if (_entList.Count >= 1)
|
if (_entList.Count >= 1)
|
||||||
{
|
{
|
||||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay, new AreaPickupDoAfterEvent(GetNetEntityList(_entList)), uid, target: uid)
|
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay * AreaInsertDelayPerItem, new AreaPickupDoAfterEvent(GetNetEntityList(_entList)), uid, target: uid)
|
||||||
{
|
{
|
||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
BreakOnMove = true,
|
BreakOnMove = true,
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Trigger.Components.Conditions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a triggered entity or the user of a trigger has a certain mindrole.
|
||||||
|
/// Cancels the trigger otherwise.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Mind roles are only networked to their owner! So if you use this on any other entity than yourself it won't be predicted.
|
||||||
|
/// </remarks>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class MindRoleTriggerConditionComponent : BaseTriggerConditionComponent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whitelist for what mind role components on the owning entity allow this trigger.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityWhitelist? EntityWhitelist;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whitelist for what mind role components on the User allow this trigger.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityWhitelist? UserWhitelist;
|
||||||
|
}
|
||||||
@@ -4,20 +4,20 @@ using Robust.Shared.GameStates;
|
|||||||
namespace Content.Shared.Trigger.Components.Conditions;
|
namespace Content.Shared.Trigger.Components.Conditions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the user of a trigger satisfies a whitelist and blacklist condition for the triggered entity or the one triggering it.
|
/// Checks if the user of a trigger satisfies a whitelist and blacklist condition.
|
||||||
/// Cancels the trigger otherwise.
|
/// Cancels the trigger otherwise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class WhitelistTriggerConditionComponent : BaseTriggerConditionComponent
|
public sealed partial class WhitelistTriggerConditionComponent : BaseTriggerConditionComponent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whitelist for what entites can cause this trigger.
|
/// Whitelist for what entities can cause this trigger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public EntityWhitelist? UserWhitelist;
|
public EntityWhitelist? UserWhitelist;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Blacklist for what entites can cause this trigger.
|
/// Blacklist for what entities can cause this trigger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public EntityWhitelist? UserBlacklist;
|
public EntityWhitelist? UserBlacklist;
|
||||||
|
|||||||
@@ -58,5 +58,17 @@ public sealed class DnaScrambleOnTriggerSystem : EntitySystem
|
|||||||
|
|
||||||
// Can't use PopupClient or PopupPredicted because the trigger might be unpredicted.
|
// Can't use PopupClient or PopupPredicted because the trigger might be unpredicted.
|
||||||
_popup.PopupEntity(Loc.GetString("scramble-on-trigger-popup"), target.Value, target.Value);
|
_popup.PopupEntity(Loc.GetString("scramble-on-trigger-popup"), target.Value, target.Value);
|
||||||
|
|
||||||
|
var ev = new DnaScrambledEvent(target.Value);
|
||||||
|
RaiseLocalEvent(target.Value, ref ev, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised after an entity has been DNA Scrambled.
|
||||||
|
/// Useful for forks that need to run their own updates here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The entity that had its DNA scrambled.</param>
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct DnaScrambledEvent(EntityUid Target);
|
||||||
|
|||||||
@@ -10,31 +10,36 @@ public sealed partial class TriggerSystem
|
|||||||
private void InitializeCondition()
|
private void InitializeCondition()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<WhitelistTriggerConditionComponent, AttemptTriggerEvent>(OnWhitelistTriggerAttempt);
|
SubscribeLocalEvent<WhitelistTriggerConditionComponent, AttemptTriggerEvent>(OnWhitelistTriggerAttempt);
|
||||||
|
|
||||||
SubscribeLocalEvent<UseDelayTriggerConditionComponent, AttemptTriggerEvent>(OnUseDelayTriggerAttempt);
|
SubscribeLocalEvent<UseDelayTriggerConditionComponent, AttemptTriggerEvent>(OnUseDelayTriggerAttempt);
|
||||||
|
|
||||||
SubscribeLocalEvent<ToggleTriggerConditionComponent, AttemptTriggerEvent>(OnToggleTriggerAttempt);
|
SubscribeLocalEvent<ToggleTriggerConditionComponent, AttemptTriggerEvent>(OnToggleTriggerAttempt);
|
||||||
SubscribeLocalEvent<ToggleTriggerConditionComponent, GetVerbsEvent<AlternativeVerb>>(OnToggleGetAltVerbs);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<RandomChanceTriggerConditionComponent, AttemptTriggerEvent>(OnRandomChanceTriggerAttempt);
|
SubscribeLocalEvent<RandomChanceTriggerConditionComponent, AttemptTriggerEvent>(OnRandomChanceTriggerAttempt);
|
||||||
|
SubscribeLocalEvent<MindRoleTriggerConditionComponent, AttemptTriggerEvent>(OnMindRoleTriggerAttempt);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ToggleTriggerConditionComponent, GetVerbsEvent<AlternativeVerb>>(OnToggleGetAltVerbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnWhitelistTriggerAttempt(Entity<WhitelistTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
private void OnWhitelistTriggerAttempt(Entity<WhitelistTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
||||||
{
|
{
|
||||||
if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
|
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||||
args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
|
return;
|
||||||
|
|
||||||
|
args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUseDelayTriggerAttempt(Entity<UseDelayTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
private void OnUseDelayTriggerAttempt(Entity<UseDelayTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
||||||
{
|
{
|
||||||
if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
|
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||||
args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
|
return;
|
||||||
|
|
||||||
|
args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleTriggerAttempt(Entity<ToggleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
private void OnToggleTriggerAttempt(Entity<ToggleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
||||||
{
|
{
|
||||||
if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
|
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||||
args.Cancelled |= !ent.Comp.Enabled;
|
return;
|
||||||
|
|
||||||
|
args.Cancelled |= !ent.Comp.Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleGetAltVerbs(Entity<ToggleTriggerConditionComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
private void OnToggleGetAltVerbs(Entity<ToggleTriggerConditionComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||||
@@ -62,19 +67,51 @@ public sealed partial class TriggerSystem
|
|||||||
private void OnRandomChanceTriggerAttempt(Entity<RandomChanceTriggerConditionComponent> ent,
|
private void OnRandomChanceTriggerAttempt(Entity<RandomChanceTriggerConditionComponent> ent,
|
||||||
ref AttemptTriggerEvent args)
|
ref AttemptTriggerEvent args)
|
||||||
{
|
{
|
||||||
if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
|
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||||
{
|
return;
|
||||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
|
||||||
var hash = new List<int>
|
|
||||||
{
|
|
||||||
(int)_timing.CurTick.Value,
|
|
||||||
GetNetEntity(ent).Id,
|
|
||||||
args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
|
|
||||||
};
|
|
||||||
var seed = SharedRandomExtensions.HashCodeCombine(hash);
|
|
||||||
var rand = new System.Random(seed);
|
|
||||||
|
|
||||||
args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
|
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||||
|
var hash = new List<int>
|
||||||
|
{
|
||||||
|
(int)_timing.CurTick.Value,
|
||||||
|
GetNetEntity(ent).Id,
|
||||||
|
args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
|
||||||
|
};
|
||||||
|
var seed = SharedRandomExtensions.HashCodeCombine(hash);
|
||||||
|
var rand = new System.Random(seed);
|
||||||
|
|
||||||
|
args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
|
||||||
|
}
|
||||||
|
private void OnMindRoleTriggerAttempt(Entity<MindRoleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ent.Comp.EntityWhitelist != null)
|
||||||
|
{
|
||||||
|
if (!_mind.TryGetMind(ent.Owner, out var entMindId, out var entMindComp))
|
||||||
|
{
|
||||||
|
args.Cancelled = true; // the entity has no mind
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_role.MindHasRole((entMindId, entMindComp), ent.Comp.EntityWhitelist))
|
||||||
|
{
|
||||||
|
args.Cancelled = true; // the entity does not have the required role
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent.Comp.UserWhitelist != null)
|
||||||
|
{
|
||||||
|
if (args.User == null || !_mind.TryGetMind(args.User.Value, out var userMindId, out var userMindComp))
|
||||||
|
{
|
||||||
|
args.Cancelled = true; // no user or the user has no mind
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_role.MindHasRole((userMindId, userMindComp), ent.Comp.UserWhitelist))
|
||||||
|
{
|
||||||
|
args.Cancelled = true; // the user does not have the required role
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.EntityTable;
|
using Content.Shared.EntityTable;
|
||||||
using Content.Shared.Item.ItemToggle;
|
using Content.Shared.Item.ItemToggle;
|
||||||
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
using Content.Shared.Trigger.Components;
|
using Content.Shared.Trigger.Components;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
@@ -39,6 +41,8 @@ public sealed partial class TriggerSystem : EntitySystem
|
|||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
|
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
|
||||||
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
|
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
|
||||||
|
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||||
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||||
[Dependency] private readonly EntityTableSystem _entityTable = default!;
|
[Dependency] private readonly EntityTableSystem _entityTable = default!;
|
||||||
|
|
||||||
public const string DefaultTriggerKey = "trigger";
|
public const string DefaultTriggerKey = "trigger";
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Content.Shared.Administration.Components;
|
|||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Damage.Events;
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -63,6 +64,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
||||||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||||
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
|
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
|
||||||
|
[Dependency] private readonly DamageExamineSystem _damageExamine = default!;
|
||||||
|
|
||||||
private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
|
private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
|
||||||
|
|
||||||
@@ -83,6 +85,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnMeleeSelected);
|
SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnMeleeSelected);
|
||||||
SubscribeLocalEvent<MeleeWeaponComponent, ShotAttemptedEvent>(OnMeleeShotAttempted);
|
SubscribeLocalEvent<MeleeWeaponComponent, ShotAttemptedEvent>(OnMeleeShotAttempted);
|
||||||
SubscribeLocalEvent<MeleeWeaponComponent, GunShotEvent>(OnMeleeShot);
|
SubscribeLocalEvent<MeleeWeaponComponent, GunShotEvent>(OnMeleeShot);
|
||||||
|
SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
|
||||||
SubscribeLocalEvent<BonusMeleeDamageComponent, GetMeleeDamageEvent>(OnGetBonusMeleeDamage);
|
SubscribeLocalEvent<BonusMeleeDamageComponent, GetMeleeDamageEvent>(OnGetBonusMeleeDamage);
|
||||||
SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
|
SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
|
||||||
SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
|
SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
|
||||||
@@ -95,8 +98,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
|
SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
SubscribeLocalEvent<MeleeWeaponComponent,
|
SubscribeLocalEvent<MeleeWeaponComponent, MapInitEvent>(OnMapInit);
|
||||||
MapInitEvent> (OnMapInit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
|
||||||
@@ -124,6 +126,18 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
|
||||||
|
{
|
||||||
|
if (component.Hidden)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var damageSpec = GetDamage(uid, args.User, component);
|
||||||
|
|
||||||
|
if (damageSpec.Empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
|
||||||
|
}
|
||||||
private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
|
private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
|
||||||
{
|
{
|
||||||
var attackRate = GetAttackRate(uid, args.User, component);
|
var attackRate = GetAttackRate(uid, args.User, component);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
|
|||||||
var visuals = EnsureComp<JointVisualsComponent>(shotUid.Value);
|
var visuals = EnsureComp<JointVisualsComponent>(shotUid.Value);
|
||||||
visuals.Sprite = component.RopeSprite;
|
visuals.Sprite = component.RopeSprite;
|
||||||
visuals.OffsetA = new Vector2(0f, 0.5f);
|
visuals.OffsetA = new Vector2(0f, 0.5f);
|
||||||
visuals.Target = GetNetEntity(uid);
|
visuals.Target = uid;
|
||||||
Dirty(shotUid.Value, visuals);
|
Dirty(shotUid.Value, visuals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Damage.Events;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Projectiles;
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
using Content.Shared.Weapons.Ranged.Events;
|
using Content.Shared.Weapons.Ranged.Events;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||||
@@ -18,6 +22,7 @@ public abstract partial class SharedGunSystem
|
|||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
||||||
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
||||||
|
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
||||||
|
|
||||||
// Projectile
|
// Projectile
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentGetState>(OnBatteryGetState);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentGetState>(OnBatteryGetState);
|
||||||
@@ -25,6 +30,7 @@ public abstract partial class SharedGunSystem
|
|||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
|
||||||
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
||||||
|
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
|
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
|
||||||
@@ -53,6 +59,51 @@ public abstract partial class SharedGunSystem
|
|||||||
args.PushMarkup(Loc.GetString("gun-battery-examine", ("color", AmmoExamineColor), ("count", component.Shots)));
|
args.PushMarkup(Loc.GetString("gun-battery-examine", ("color", AmmoExamineColor), ("count", component.Shots)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
|
||||||
|
{
|
||||||
|
var damageSpec = GetDamage(entity.Comp);
|
||||||
|
|
||||||
|
if (damageSpec == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var damageType = entity.Comp switch
|
||||||
|
{
|
||||||
|
HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
|
||||||
|
ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
|
||||||
|
{
|
||||||
|
if (component is ProjectileBatteryAmmoProviderComponent battery)
|
||||||
|
{
|
||||||
|
if (ProtoManager.Index<EntityPrototype>(battery.Prototype)
|
||||||
|
.Components
|
||||||
|
.TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
|
||||||
|
{
|
||||||
|
var p = (ProjectileComponent)projectile.Component;
|
||||||
|
|
||||||
|
if (!p.Damage.Empty)
|
||||||
|
{
|
||||||
|
return p.Damage * Damageable.UniversalProjectileDamageModifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component is HitscanBatteryAmmoProviderComponent hitscan)
|
||||||
|
{
|
||||||
|
var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
|
||||||
|
return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnBatteryTakeAmmo(EntityUid uid, BatteryAmmoProviderComponent component, TakeAmmoEvent args)
|
private void OnBatteryTakeAmmo(EntityUid uid, BatteryAmmoProviderComponent component, TakeAmmoEvent args)
|
||||||
{
|
{
|
||||||
var shots = Math.Min(args.Shots, component.Shots);
|
var shots = Math.Min(args.Shots, component.Shots);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public sealed partial class AnalysisConsoleComponent : Component
|
|||||||
/// Can be null if not linked.
|
/// Can be null if not linked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public NetEntity? AnalyzerEntity;
|
public EntityUid? AnalyzerEntity;
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public SoundSpecifier? ScanFinishedSound = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg");
|
public SoundSpecifier? ScanFinishedSound = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg");
|
||||||
@@ -35,7 +35,7 @@ public sealed partial class AnalysisConsoleComponent : Component
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The machine linking port for the analyzer
|
/// The machine linking port for linking the console with the analyzer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<SourcePortPrototype> LinkingPort = "ArtifactAnalyzerSender";
|
public ProtoId<SourcePortPrototype> LinkingPort = "ArtifactAnalyzerSender";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Robust.Shared.Audio;
|
using Content.Shared.DeviceLinking;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.Xenoarchaeology.Equipment.Components;
|
namespace Content.Shared.Xenoarchaeology.Equipment.Components;
|
||||||
|
|
||||||
@@ -35,4 +36,10 @@ public sealed partial class ArtifactAnalyzerComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool ReadyToPrint = false;
|
public bool ReadyToPrint = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The machine linking port for linking the analyzer with the console.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<SinkPortPrototype> LinkingPort = "ArtifactAnalyzerReceiver";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.Stacks;
|
using Content.Shared.Stacks;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Audio.Components;
|
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -14,7 +13,8 @@ namespace Content.Shared.Xenoarchaeology.Equipment.Components;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is an entity storage that, when activated, crushes the artifact inside of it and gives artifact fragments.
|
/// This is an entity storage that, when activated, crushes the artifact inside of it and gives artifact fragments.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||||
[Access(typeof(SharedArtifactCrusherSystem))]
|
[Access(typeof(SharedArtifactCrusherSystem))]
|
||||||
public sealed partial class ArtifactCrusherComponent : Component
|
public sealed partial class ArtifactCrusherComponent : Component
|
||||||
{
|
{
|
||||||
@@ -27,19 +27,21 @@ public sealed partial class ArtifactCrusherComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the current crushing will end.
|
/// When the current crushing will end.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
|
[AutoNetworkedField, AutoPausedField]
|
||||||
public TimeSpan CrushEndTime;
|
public TimeSpan CrushEndTime;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The next second. Used to apply damage over time.
|
/// The next second. Used to apply damage over time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
|
[AutoNetworkedField, AutoPausedField]
|
||||||
public TimeSpan NextSecond;
|
public TimeSpan NextSecond;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total duration of the crushing.
|
/// The total duration of the crushing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public TimeSpan CrushDuration = TimeSpan.FromSeconds(10);
|
public TimeSpan CrushDuration = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,19 +53,19 @@ public sealed partial class ArtifactCrusherComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum amount of fragments spawned.
|
/// The minimum amount of fragments spawned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public int MinFragments = 2;
|
public int MinFragments = 2;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum amount of fragments spawned, non-inclusive.
|
/// The maximum amount of fragments spawned, non-inclusive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public int MaxFragments = 5;
|
public int MaxFragments = 5;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The material for the fragments.
|
/// The material for the fragments.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField]
|
||||||
public ProtoId<StackPrototype> FragmentStackProtoId = "ArtifactFragment";
|
public ProtoId<StackPrototype> FragmentStackProtoId = "ArtifactFragment";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -100,12 +102,12 @@ public sealed partial class ArtifactCrusherComponent : Component
|
|||||||
/// Stores entity of <see cref="CrushingSound"/> to allow ending it early.
|
/// Stores entity of <see cref="CrushingSound"/> to allow ending it early.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public (EntityUid, AudioComponent)? CrushingSoundEntity;
|
public EntityUid? CrushingSoundEntity;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When enabled, stops the artifact crusher from being opened when it is being crushed.
|
/// When enabled, stops the artifact crusher from being opened when it is being crushed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, AutoNetworkedField]
|
||||||
public bool AutoLock = false;
|
public bool AutoLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace Content.Shared.Xenoarchaeology.Equipment;
|
|||||||
public abstract class SharedArtifactAnalyzerSystem : EntitySystem
|
public abstract class SharedArtifactAnalyzerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
|
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
|
||||||
|
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -23,10 +24,14 @@ public abstract class SharedArtifactAnalyzerSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemPlacedEvent>(OnItemPlaced);
|
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemPlacedEvent>(OnItemPlaced);
|
||||||
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemRemovedEvent>(OnItemRemoved);
|
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemRemovedEvent>(OnItemRemoved);
|
||||||
SubscribeLocalEvent<ArtifactAnalyzerComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<ArtifactAnalyzerComponent, NewLinkEvent>(OnNewLinkAnalyzer);
|
||||||
|
SubscribeLocalEvent<ArtifactAnalyzerComponent, LinkAttemptEvent>(OnLinkAttemptAnalyzer);
|
||||||
|
SubscribeLocalEvent<ArtifactAnalyzerComponent, PortDisconnectedEvent>(OnPortDisconnectedAnalyzer);
|
||||||
|
|
||||||
SubscribeLocalEvent<AnalysisConsoleComponent, NewLinkEvent>(OnNewLink);
|
SubscribeLocalEvent<AnalysisConsoleComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<AnalysisConsoleComponent, PortDisconnectedEvent>(OnPortDisconnected);
|
SubscribeLocalEvent<AnalysisConsoleComponent, NewLinkEvent>(OnNewLinkConsole);
|
||||||
|
SubscribeLocalEvent<AnalysisConsoleComponent, LinkAttemptEvent>(OnLinkAttemptConsole);
|
||||||
|
SubscribeLocalEvent<AnalysisConsoleComponent, PortDisconnectedEvent>(OnPortDisconnectedConsole);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnItemPlaced(Entity<ArtifactAnalyzerComponent> ent, ref ItemPlacedEvent args)
|
private void OnItemPlaced(Entity<ArtifactAnalyzerComponent> ent, ref ItemPlacedEvent args)
|
||||||
@@ -44,52 +49,74 @@ public abstract class SharedArtifactAnalyzerSystem : EntitySystem
|
|||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapInit(Entity<ArtifactAnalyzerComponent> ent, ref MapInitEvent args)
|
private void OnMapInit(Entity<AnalysisConsoleComponent> ent, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<DeviceLinkSinkComponent>(ent, out var sink))
|
if (!TryComp<DeviceLinkSourceComponent>(ent, out var source))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var source in sink.LinkedSources)
|
var linkedEntities = _deviceLink.GetLinkedSinks((ent.Owner, source), ent.Comp.LinkingPort);
|
||||||
|
|
||||||
|
foreach (var sink in linkedEntities)
|
||||||
{
|
{
|
||||||
if (!TryComp<AnalysisConsoleComponent>(source, out var analysis))
|
if (!TryComp<ArtifactAnalyzerComponent>(sink, out var analyzer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
analysis.AnalyzerEntity = GetNetEntity(ent);
|
ent.Comp.AnalyzerEntity = sink;
|
||||||
ent.Comp.Console = source;
|
analyzer.Console = ent.Owner;
|
||||||
Dirty(source, analysis);
|
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
|
Dirty(sink, analyzer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNewLink(Entity<AnalysisConsoleComponent> ent, ref NewLinkEvent args)
|
private void OnNewLinkConsole(Entity<AnalysisConsoleComponent> ent, ref NewLinkEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<ArtifactAnalyzerComponent>(args.Sink, out var analyzer))
|
if (args.SourcePort != ent.Comp.LinkingPort || !HasComp<ArtifactAnalyzerComponent>(args.Sink))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ent.Comp.AnalyzerEntity = GetNetEntity(args.Sink);
|
ent.Comp.AnalyzerEntity = args.Sink;
|
||||||
analyzer.Console = ent;
|
|
||||||
Dirty(args.Sink, analyzer);
|
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPortDisconnected(Entity<AnalysisConsoleComponent> ent, ref PortDisconnectedEvent args)
|
private void OnNewLinkAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref NewLinkEvent args)
|
||||||
{
|
{
|
||||||
var analyzerNetEntity = ent.Comp.AnalyzerEntity;
|
if (args.SinkPort != ent.Comp.LinkingPort || !HasComp<AnalysisConsoleComponent>(args.Source))
|
||||||
if (args.Port != ent.Comp.LinkingPort || analyzerNetEntity == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var analyzerEntityUid = GetEntity(analyzerNetEntity);
|
ent.Comp.Console = args.Source;
|
||||||
if (TryComp<ArtifactAnalyzerComponent>(analyzerEntityUid, out var analyzer))
|
Dirty(ent);
|
||||||
{
|
}
|
||||||
analyzer.Console = null;
|
|
||||||
Dirty(analyzerEntityUid.Value, analyzer);
|
private void OnLinkAttemptConsole(Entity<AnalysisConsoleComponent> ent, ref LinkAttemptEvent args)
|
||||||
}
|
{
|
||||||
|
if (ent.Comp.AnalyzerEntity != null)
|
||||||
|
args.Cancel(); // can only link to one device at a time
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLinkAttemptAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref LinkAttemptEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.Console != null)
|
||||||
|
args.Cancel(); // can only link to one device at a time
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPortDisconnectedConsole(Entity<AnalysisConsoleComponent> ent, ref PortDisconnectedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Port != ent.Comp.LinkingPort || ent.Comp.AnalyzerEntity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
ent.Comp.AnalyzerEntity = null;
|
ent.Comp.AnalyzerEntity = null;
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPortDisconnectedAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref PortDisconnectedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Port != ent.Comp.LinkingPort || ent.Comp.Console == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ent.Comp.Console = null;
|
||||||
|
Dirty(ent);
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryGetAnalyzer(Entity<AnalysisConsoleComponent> ent, [NotNullWhen(true)] out Entity<ArtifactAnalyzerComponent>? analyzer)
|
public bool TryGetAnalyzer(Entity<AnalysisConsoleComponent> ent, [NotNullWhen(true)] out Entity<ArtifactAnalyzerComponent>? analyzer)
|
||||||
{
|
{
|
||||||
analyzer = null;
|
analyzer = null;
|
||||||
@@ -98,14 +125,13 @@ public abstract class SharedArtifactAnalyzerSystem : EntitySystem
|
|||||||
if (!_powerReceiver.IsPowered(consoleEnt))
|
if (!_powerReceiver.IsPowered(consoleEnt))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var analyzerUid = GetEntity(ent.Comp.AnalyzerEntity);
|
if (!TryComp<ArtifactAnalyzerComponent>(ent.Comp.AnalyzerEntity, out var analyzerComp))
|
||||||
if (!TryComp<ArtifactAnalyzerComponent>(analyzerUid, out var analyzerComp))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_powerReceiver.IsPowered(analyzerUid.Value))
|
if (!_powerReceiver.IsPowered(ent.Comp.AnalyzerEntity.Value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
analyzer = (analyzerUid.Value, analyzerComp);
|
analyzer = (ent.Comp.AnalyzerEntity.Value, analyzerComp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
using Content.Shared.Examine;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Storage.Components;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Power;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Xenoarchaeology.Equipment.Components;
|
using Content.Shared.Xenoarchaeology.Equipment.Components;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Collections;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Xenoarchaeology.Equipment;
|
namespace Content.Shared.Xenoarchaeology.Equipment;
|
||||||
|
|
||||||
@@ -12,10 +19,14 @@ namespace Content.Shared.Xenoarchaeology.Equipment;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SharedArtifactCrusherSystem : EntitySystem
|
public abstract class SharedArtifactCrusherSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
|
||||||
[Dependency] protected readonly SharedAudioSystem AudioSystem = default!;
|
[Dependency] protected readonly SharedAudioSystem AudioSystem = default!;
|
||||||
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
|
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly EmagSystem _emag = default!;
|
[Dependency] private readonly EmagSystem _emag = default!;
|
||||||
|
[Dependency] private readonly SharedPowerReceiverSystem _power = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -27,6 +38,8 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<ArtifactCrusherComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
|
SubscribeLocalEvent<ArtifactCrusherComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
|
||||||
SubscribeLocalEvent<ArtifactCrusherComponent, ExaminedEvent>(OnExamine);
|
SubscribeLocalEvent<ArtifactCrusherComponent, ExaminedEvent>(OnExamine);
|
||||||
SubscribeLocalEvent<ArtifactCrusherComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<ArtifactCrusherComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
SubscribeLocalEvent<ArtifactCrusherComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
|
||||||
|
SubscribeLocalEvent<ArtifactCrusherComponent, PowerChangedEvent>(OnPowerChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(Entity<ArtifactCrusherComponent> ent, ref ComponentInit args)
|
private void OnInit(Entity<ArtifactCrusherComponent> ent, ref ComponentInit args)
|
||||||
@@ -53,6 +66,7 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem
|
|||||||
|
|
||||||
ent.Comp.AutoLock = true;
|
ent.Comp.AutoLock = true;
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStorageOpenAttempt(Entity<ArtifactCrusherComponent> ent, ref StorageOpenAttemptEvent args)
|
private void OnStorageOpenAttempt(Entity<ArtifactCrusherComponent> ent, ref StorageOpenAttemptEvent args)
|
||||||
@@ -66,22 +80,94 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem
|
|||||||
args.PushMarkup(ent.Comp.AutoLock ? Loc.GetString("artifact-crusher-examine-autolocks") : Loc.GetString("artifact-crusher-examine-no-autolocks"));
|
args.PushMarkup(ent.Comp.AutoLock ? Loc.GetString("artifact-crusher-examine-autolocks") : Loc.GetString("artifact-crusher-examine-no-autolocks"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopCrushing(Entity<ArtifactCrusherComponent> ent, bool early = true)
|
private void OnGetVerbs(Entity<ArtifactCrusherComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
var (_, crusher) = ent;
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
|
||||||
|
|
||||||
if (!crusher.Crushing)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
crusher.Crushing = false;
|
if (!TryComp<EntityStorageComponent>(ent, out var entityStorageComp) ||
|
||||||
Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false);
|
entityStorageComp.Contents.ContainedEntities.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_power.IsPowered(ent.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var user = args.User;
|
||||||
|
var verb = new AlternativeVerb
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
|
||||||
|
Priority = 2,
|
||||||
|
Act = () => StartCrushing((ent, ent.Comp, entityStorageComp), user)
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerChanged(Entity<ArtifactCrusherComponent> ent, ref PowerChangedEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Powered)
|
||||||
|
StopCrushing(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent, EntityUid? user = null)
|
||||||
|
{
|
||||||
|
var (uid, crusher, _) = ent;
|
||||||
|
|
||||||
|
if (crusher.Crushing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (crusher.AutoLock)
|
||||||
|
_popup.PopupPredicted(Loc.GetString("artifact-crusher-autolocks-enable"), uid, user);
|
||||||
|
|
||||||
|
crusher.Crushing = true;
|
||||||
|
crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
|
||||||
|
crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
|
||||||
|
crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent)?.Entity;
|
||||||
|
_appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
|
||||||
|
Dirty(ent, ent.Comp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopCrushing(Entity<ArtifactCrusherComponent> ent, bool early = true)
|
||||||
|
{
|
||||||
|
if (!ent.Comp.Crushing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ent.Comp.Crushing = false;
|
||||||
|
_appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false);
|
||||||
|
|
||||||
if (early)
|
if (early)
|
||||||
{
|
{
|
||||||
AudioSystem.Stop(crusher.CrushingSoundEntity?.Item1, crusher.CrushingSoundEntity?.Item2);
|
AudioSystem.Stop(ent.Comp.CrushingSoundEntity);
|
||||||
crusher.CrushingSoundEntity = null;
|
ent.Comp.CrushingSoundEntity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dirty(ent, ent.Comp);
|
Dirty(ent, ent.Comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent) { }
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<ArtifactCrusherComponent, EntityStorageComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var crusher, out var storage))
|
||||||
|
{
|
||||||
|
if (!crusher.Crushing)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (crusher.NextSecond < _timing.CurTime)
|
||||||
|
{
|
||||||
|
var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
|
||||||
|
foreach (var contained in contents)
|
||||||
|
{
|
||||||
|
_damageable.TryChangeDamage(contained, crusher.CrushingDamage);
|
||||||
|
}
|
||||||
|
crusher.NextSecond += TimeSpan.FromSeconds(1);
|
||||||
|
Dirty(uid, crusher);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crusher.CrushEndTime < _timing.CurTime)
|
||||||
|
FinishCrushing((uid, crusher, storage));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,4 @@
|
|||||||
Entries:
|
Entries:
|
||||||
- author: CoconutThunder
|
|
||||||
changes:
|
|
||||||
- message: The Chief Medical Officer should now appear with the correct precedence
|
|
||||||
in the crew manifest.
|
|
||||||
type: Fix
|
|
||||||
id: 8560
|
|
||||||
time: '2025-05-24T05:10:57.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37774
|
|
||||||
- author: TiniestShark
|
|
||||||
changes:
|
|
||||||
- message: Added inhand sprites for the bartender utensils and mugs.
|
|
||||||
type: Add
|
|
||||||
id: 8561
|
|
||||||
time: '2025-05-24T17:32:27.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37771
|
|
||||||
- author: K-Dynamic
|
|
||||||
changes:
|
|
||||||
- message: Shutters and blast doors now appear welded when welded.
|
|
||||||
type: Fix
|
|
||||||
id: 8562
|
|
||||||
time: '2025-05-25T15:57:18.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37807
|
|
||||||
- author: Stop-Signs
|
|
||||||
changes:
|
|
||||||
- message: Meals now better reflect the amount of ingredients put into them.
|
|
||||||
type: Tweak
|
|
||||||
id: 8563
|
|
||||||
time: '2025-05-25T18:02:04.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/34138
|
|
||||||
- author: brainfood1183
|
|
||||||
changes:
|
|
||||||
- message: Kangaroos can now be equipped with northstars and knuckle dusters.
|
|
||||||
type: Tweak
|
|
||||||
id: 8564
|
|
||||||
time: '2025-05-25T18:03:01.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37789
|
|
||||||
- author: Moomoobeef
|
|
||||||
changes:
|
|
||||||
- message: Added new variants to dirty tiles.
|
|
||||||
type: Tweak
|
|
||||||
id: 8565
|
|
||||||
time: '2025-05-25T18:11:40.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37800
|
|
||||||
- author: AsnDen
|
|
||||||
changes:
|
|
||||||
- message: Tile-aligned bar sign version was added.
|
|
||||||
type: Add
|
|
||||||
- message: Bar signs now have proper collision.
|
|
||||||
type: Fix
|
|
||||||
id: 8566
|
|
||||||
time: '2025-05-25T18:36:00.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37756
|
|
||||||
- author: Fildrance
|
|
||||||
changes:
|
|
||||||
- message: Spray nozzle now can consume liquids from puddles and put it right into
|
|
||||||
backpacked tank.
|
|
||||||
type: Add
|
|
||||||
id: 8567
|
|
||||||
time: '2025-05-26T03:36:16.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30600
|
|
||||||
- author: Southbridge
|
|
||||||
changes:
|
|
||||||
- message: On Amber, gave security its missing beacon and barriers.
|
|
||||||
type: Fix
|
|
||||||
id: 8568
|
|
||||||
time: '2025-05-26T07:29:58.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/37700
|
|
||||||
- author: jessicamaybe
|
- author: jessicamaybe
|
||||||
changes:
|
changes:
|
||||||
- message: NPC Gorillas can now pry open doors and vault/smash tables!
|
- message: NPC Gorillas can now pry open doors and vault/smash tables!
|
||||||
@@ -3949,3 +3882,73 @@
|
|||||||
id: 9062
|
id: 9062
|
||||||
time: '2025-10-09T14:00:07.0000000+00:00'
|
time: '2025-10-09T14:00:07.0000000+00:00'
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/40790
|
url: https://github.com/space-wizards/space-station-14/pull/40790
|
||||||
|
- author: Princess-Cheeseballs
|
||||||
|
changes:
|
||||||
|
- message: The thieving beacon can now detect the officer's handgun objective.
|
||||||
|
type: Fix
|
||||||
|
id: 9063
|
||||||
|
time: '2025-10-10T04:59:26.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40811
|
||||||
|
- author: Hitlinemoss
|
||||||
|
changes:
|
||||||
|
- message: The Paladin AI lawset has been rewritten.
|
||||||
|
type: Tweak
|
||||||
|
id: 9064
|
||||||
|
time: '2025-10-10T12:41:57.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40343
|
||||||
|
- author: kontakt
|
||||||
|
changes:
|
||||||
|
- message: Ninjas can now have a bombing target at any warp point.
|
||||||
|
type: Tweak
|
||||||
|
id: 9065
|
||||||
|
time: '2025-10-10T21:27:36.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40726
|
||||||
|
- author: frigid-dev
|
||||||
|
changes:
|
||||||
|
- message: Ore Crabs now collide with the player if mob collisions are enabled.
|
||||||
|
type: Tweak
|
||||||
|
- message: Ore Crabs now show they are stunned
|
||||||
|
type: Fix
|
||||||
|
id: 9066
|
||||||
|
time: '2025-10-10T23:31:04.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40764
|
||||||
|
- author: Crude Oil
|
||||||
|
changes:
|
||||||
|
- message: Removed 'Activate Holopad Projector' verb from the station AI core.
|
||||||
|
type: Fix
|
||||||
|
id: 9067
|
||||||
|
time: '2025-10-11T00:03:14.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/39937
|
||||||
|
- author: Hitlinemoss
|
||||||
|
changes:
|
||||||
|
- message: Ice now satiates thirst.
|
||||||
|
type: Tweak
|
||||||
|
- message: Ice now evaporates.
|
||||||
|
type: Tweak
|
||||||
|
id: 9068
|
||||||
|
time: '2025-10-11T00:20:22.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40149
|
||||||
|
- author: slarticodefast
|
||||||
|
changes:
|
||||||
|
- message: The artifact analysis console no longer breaks when trying to link it
|
||||||
|
to multiple artifact analyzers or vice versa.
|
||||||
|
type: Fix
|
||||||
|
id: 9069
|
||||||
|
time: '2025-10-11T00:33:04.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/39984
|
||||||
|
- author: qwerltaz
|
||||||
|
changes:
|
||||||
|
- message: The ID card computer now has buttons to grant or revoke all access from
|
||||||
|
the target ID card.
|
||||||
|
type: Add
|
||||||
|
id: 9070
|
||||||
|
time: '2025-10-11T00:52:01.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/39375
|
||||||
|
- author: Centronias
|
||||||
|
changes:
|
||||||
|
- message: The HugBot, which is similar in purpose and construction to other small
|
||||||
|
robots like the CleanBot.
|
||||||
|
type: Add
|
||||||
|
id: 9071
|
||||||
|
time: '2025-10-11T01:05:08.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/37557
|
||||||
|
|||||||
@@ -771,4 +771,11 @@
|
|||||||
id: 93
|
id: 93
|
||||||
time: '2025-10-10T01:11:33.0000000+00:00'
|
time: '2025-10-10T01:11:33.0000000+00:00'
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/40794
|
url: https://github.com/space-wizards/space-station-14/pull/40794
|
||||||
|
- author: opl
|
||||||
|
changes:
|
||||||
|
- message: On Packed, prisoners can now use the Megaseed in brig.
|
||||||
|
type: Fix
|
||||||
|
id: 94
|
||||||
|
time: '2025-10-10T20:33:03.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/40821
|
||||||
Order: 1
|
Order: 1
|
||||||
|
|||||||
1
Resources/Locale/en-US/_Moffstation/recipes/tags.ftl
Normal file
1
Resources/Locale/en-US/_Moffstation/recipes/tags.ftl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
construction-graph-tag-boxhug = a box of hugs
|
||||||
@@ -5,7 +5,9 @@ id-card-console-window-save-button = Save
|
|||||||
id-card-console-window-job-title-label = Job title:
|
id-card-console-window-job-title-label = Job title:
|
||||||
id-card-console-window-eject-button = Eject
|
id-card-console-window-eject-button = Eject
|
||||||
id-card-console-window-insert-button = Insert
|
id-card-console-window-insert-button = Insert
|
||||||
id-card-console-window-job-selection-label = Job presets (sets department and job icon):
|
id-card-console-window-job-selection-label = Job preset (sets department and job icon):
|
||||||
|
id-card-console-window-select-all-button = Grant all
|
||||||
|
id-card-console-window-deselect-all-button = Revoke all
|
||||||
|
|
||||||
access-id-card-console-component-no-hands-error = You have no hands.
|
access-id-card-console-component-no-hands-error = You have no hands.
|
||||||
id-card-console-privileged-id = Privileged ID
|
id-card-console-privileged-id = Privileged ID
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# Generic verbs
|
||||||
delete-verb-get-data-text = Delete
|
delete-verb-get-data-text = Delete
|
||||||
edit-solutions-verb-get-data-text = Edit Solutions
|
edit-solutions-verb-get-data-text = Edit Solutions
|
||||||
explode-verb-get-data-text = Explode
|
explode-verb-get-data-text = Explode
|
||||||
@@ -18,3 +19,47 @@ toolshed-verb-mark = Mark
|
|||||||
toolshed-verb-mark-description = Places this entity into the $marked variable, a list of entities, replacing its prior value.
|
toolshed-verb-mark-description = Places this entity into the $marked variable, a list of entities, replacing its prior value.
|
||||||
|
|
||||||
export-entity-verb-get-data-text = Export sprite
|
export-entity-verb-get-data-text = Export sprite
|
||||||
|
|
||||||
|
# Tools verbs
|
||||||
|
admin-verbs-rejuvenate = Rejuvenate
|
||||||
|
admin-verbs-make-indestructible = Make Indestructible
|
||||||
|
admin-verbs-make-vulnerable = Make Vulnerable
|
||||||
|
admin-verbs-refill-battery = Refill Battery
|
||||||
|
admin-verbs-drain-battery = Drain Battery
|
||||||
|
admin-verbs-infinite-battery = Infinite Battery
|
||||||
|
admin-verbs-block-unanchoring = Block Unanchoring
|
||||||
|
admin-verbs-refill-internals-oxygen = Refill Internals Oxygen
|
||||||
|
admin-verbs-refill-internals-nitrogen = Refill Internals Nitrogen
|
||||||
|
admin-verbs-refill-internals-plasma = Refill Internals Plasma
|
||||||
|
admin-verbs-send-to-test-arena = Send to test arena
|
||||||
|
admin-verbs-grant-all-access = Grant All Access
|
||||||
|
admin-verbs-revoke-all-access = Revoke All Access
|
||||||
|
admin-verbs-adjust-stack = Adjust Stack
|
||||||
|
admin-verbs-fill-stack = Fill Stack
|
||||||
|
admin-verbs-rename = Rename
|
||||||
|
admin-verbs-redescribe = Redescribe
|
||||||
|
admin-verbs-rename-and-redescribe = Rename & Redescribe
|
||||||
|
admin-verbs-bar-job-slots = Bar job slots
|
||||||
|
admin-verbs-locate-cargo-shuttle = Locate Cargo Shuttle
|
||||||
|
admin-verbs-halt-movement = Halt Movement
|
||||||
|
admin-verbs-unpause-map = Unpause Map
|
||||||
|
admin-verbs-pause-map = Pause Map
|
||||||
|
admin-verbs-snap-joints = Snap Joints
|
||||||
|
admin-verbs-make-minigun = Make Minigun
|
||||||
|
admin-verbs-set-bullet-amount = Set Bullet Amount
|
||||||
|
|
||||||
|
# Toggles verbs
|
||||||
|
admin-verbs-bolt = Bolt
|
||||||
|
admin-verbs-unbolt = Unbolt
|
||||||
|
admin-verbs-emergency-access-on = Emergency Access On
|
||||||
|
admin-verbs-emergency-access-off = Emergency Access Off
|
||||||
|
|
||||||
|
# Dialogs verbs
|
||||||
|
admin-verbs-dialog-adjust-stack-amount = Amount (max {$max})
|
||||||
|
admin-verbs-dialog-rename-title = Rename
|
||||||
|
admin-verbs-dialog-rename-name = Name
|
||||||
|
admin-verbs-dialog-redescribe-title = Redescribe
|
||||||
|
admin-verbs-dialog-redescribe-description = Description
|
||||||
|
admin-verbs-dialog-rename-and-redescribe-title = Rename & Redescribe
|
||||||
|
admin-verbs-dialog-set-bullet-amount-title = Set Bullet Amount
|
||||||
|
admin-verbs-dialog-set-bullet-amount-amount = Amount (standard {$cap})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
bwoink-user-title = Admin Message
|
bwoink-user-title = Admin Message
|
||||||
|
bwoink-admin-title = Admin Help
|
||||||
|
|
||||||
bwoink-system-starmute-message-no-other-users = *System: Nobody is available to receive your message. Try pinging Game Admins on Discord.
|
bwoink-system-starmute-message-no-other-users = *System: Nobody is available to receive your message. Try pinging Game Admins on Discord.
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
cluwne-transform = {CAPITALIZE(THE($target))} turned into a cluwne!
|
cluwne-transform = {CAPITALIZE(THE($target))} turned into a cluwne!
|
||||||
cluwne-name-prefix = cluwnified {$baseName}
|
cluwne-name-prefix = cluwnified {$baseName}
|
||||||
|
cluwne-knock-emote = spasms
|
||||||
|
cluwne-giggle-emote = honks
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ comp-storage-cant-drop = You can't let go of { THE($entity) }!
|
|||||||
comp-storage-window-title = Storage Item
|
comp-storage-window-title = Storage Item
|
||||||
comp-storage-window-weight = { $weight }/{ $maxWeight }, Max Size: {$size}
|
comp-storage-window-weight = { $weight }/{ $maxWeight }, Max Size: {$size}
|
||||||
comp-storage-window-slots = Slots: { $itemCount }/{ $maxCount }, Max Size: {$size}
|
comp-storage-window-slots = Slots: { $itemCount }/{ $maxCount }, Max Size: {$size}
|
||||||
|
comp-storage-window-dummy = Dummy
|
||||||
comp-storage-verb-open-storage = Open Storage
|
comp-storage-verb-open-storage = Open Storage
|
||||||
comp-storage-verb-close-storage = Close Storage
|
comp-storage-verb-close-storage = Close Storage
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ credits-window-codebases-section-title = Space Station 13 Codebases
|
|||||||
credits-window-original-remake-team-section-title = Original Space Station 13 Remake Team
|
credits-window-original-remake-team-section-title = Original Space Station 13 Remake Team
|
||||||
credits-window-immortals-title = In Memoriam
|
credits-window-immortals-title = In Memoriam
|
||||||
credits-window-special-thanks-section-title = Special Thanks
|
credits-window-special-thanks-section-title = Special Thanks
|
||||||
|
credits-window-previous-page-button = Previous Page
|
||||||
|
credits-window-next-page-button = Next Page
|
||||||
|
|
||||||
credits-window-attributions-directory = [color=white]Directory:[/color] {$directory}
|
credits-window-attributions-directory = [color=white]Directory:[/color] {$directory}
|
||||||
credits-window-attributions-files = [color=white]Files:[/color] {$files}
|
credits-window-attributions-files = [color=white]Files:[/color] {$files}
|
||||||
|
|||||||
21
Resources/Locale/en-US/ghost/make-ghost-gui.ftl
Normal file
21
Resources/Locale/en-US/ghost/make-ghost-gui.ftl
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
make-ghost-roles-window-title = Make Ghost Role
|
||||||
|
|
||||||
|
make-ghost-roles-window-entity-label = Entity
|
||||||
|
make-ghost-roles-window-role-name-label = Role Name
|
||||||
|
make-ghost-roles-window-role-description-label = Role Description
|
||||||
|
make-ghost-roles-window-role-rules-label = Role Rules
|
||||||
|
make-ghost-roles-window-make-sentient-label = Make Sentient
|
||||||
|
make-ghost-roles-window-initial-duration-label = Initial Duration (s)
|
||||||
|
make-ghost-roles-window-join-extends-by-label = Joins Extend By (s)
|
||||||
|
make-ghost-roles-window-max-duration-label = Max Duration (s)
|
||||||
|
|
||||||
|
make-ghost-roles-window-make-button = Make
|
||||||
|
|
||||||
|
# Raffle
|
||||||
|
make-ghost-roles-window-raffle-not-button = Don't raffle
|
||||||
|
make-ghost-roles-window-raffle-custom-settings-button = Custom settings
|
||||||
|
|
||||||
|
make-ghost-roles-window-raffle-role-label = Raffle Role?
|
||||||
|
make-ghost-roles-window-raffle-settings-label = {$id} (initial {$initialDuration}s, max {$maxDuration}s, join adds {$joinExtendsDurationBy}s)
|
||||||
|
|
||||||
|
make-ghost-roles-window-raffle-warning-tooltip = The initial duration must not exceed the maximum duration.
|
||||||
@@ -77,6 +77,7 @@ ban-panel-permanent = Permanent
|
|||||||
ban-panel-ip-hwid-tooltip = Leave empty and check the checkbox below to use last connection's details
|
ban-panel-ip-hwid-tooltip = Leave empty and check the checkbox below to use last connection's details
|
||||||
ban-panel-severity = Severity:
|
ban-panel-severity = Severity:
|
||||||
ban-panel-erase = Erase chat messages and player from round
|
ban-panel-erase = Erase chat messages and player from round
|
||||||
|
ban-panel-expiry-error = err
|
||||||
|
|
||||||
# Ban string
|
# Ban string
|
||||||
server-ban-string = {$admin} created a {$severity} severity server ban that expires {$expires} for [{$name}, {$ip}, {$hwid}], with reason: {$reason}
|
server-ban-string = {$admin} created a {$severity} severity server ban that expires {$expires} for [{$name}, {$ip}, {$hwid}], with reason: {$reason}
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ job-supervisors-medicine = Medical Doctors, Paramedics, Chemists, and the Chief
|
|||||||
job-supervisors-security = Security Officers, the Warden, and the Head of Security
|
job-supervisors-security = Security Officers, the Warden, and the Head of Security
|
||||||
job-supervisors-science = Scientists and the Research Director
|
job-supervisors-science = Scientists and the Research Director
|
||||||
job-supervisors-hire = whoever hires you
|
job-supervisors-hire = whoever hires you
|
||||||
job-supervisors-everyone = absolutely everyone
|
job-supervisors-everyone = absolutely everyone
|
||||||
|
job-supervisors-nobody = nobody
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
## UI
|
## UI
|
||||||
|
|
||||||
crew-monitoring-user-interface-title = Crew Monitoring Console
|
crew-monitoring-ui-title = Crew Monitoring Console
|
||||||
|
|
||||||
crew-monitor-filter-line-placeholder = Filter
|
crew-monitoring-ui-filter-line-placeholder = Filter
|
||||||
|
|
||||||
crew-monitoring-user-interface-name = Name
|
crew-monitoring-ui-job-label = Job:
|
||||||
crew-monitoring-user-interface-job = Job:
|
crew-monitoring-ui-no-server-label = Server not found
|
||||||
crew-monitoring-user-interface-status = Status
|
|
||||||
crew-monitoring-user-interface-location = Location
|
|
||||||
|
|
||||||
crew-monitoring-user-interface-alive = Alive
|
crew-monitoring-ui-no-department-label = Unknown
|
||||||
crew-monitoring-user-interface-dead = Dead
|
crew-monitoring-ui-no-station-label = Unknown station
|
||||||
crew-monitoring-user-interface-no-info = N/A
|
|
||||||
|
|
||||||
crew-monitoring-user-interface-no-server = Server not found
|
crew-monitoring-ui-flavor-left-label = In case of an emergency, contact station medical staff immediately
|
||||||
|
crew-monitoring-ui-flavor-right-label = v1.7
|
||||||
crew-monitoring-user-interface-no-department = Unknown
|
|
||||||
|
|
||||||
crew-monitoring-user-interface-flavor-left = In case of an emergency, contact station medical staff immediately
|
|
||||||
crew-monitoring-user-interface-flavor-right = v1.7
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ station-map-window-title = Station map
|
|||||||
station-map-user-interface-flavor-left = Don't panic
|
station-map-user-interface-flavor-left = Don't panic
|
||||||
station-map-user-interface-flavor-right = v1.42
|
station-map-user-interface-flavor-right = v1.42
|
||||||
station-map-filter-placeholder = Search by name
|
station-map-filter-placeholder = Search by name
|
||||||
|
station-map-unknown-station = Unknown station
|
||||||
|
|
||||||
nav-beacon-window-title = Station Beacon
|
nav-beacon-window-title = Station Beacon
|
||||||
nav-beacon-toggle-visible = Visible
|
nav-beacon-toggle-visible = Visible
|
||||||
|
|||||||
26
Resources/Locale/en-US/npc/hugbot.ftl
Normal file
26
Resources/Locale/en-US/npc/hugbot.ftl
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
hugbot-start-hug-1 = LEVEL 5 HUG DEFICIENCY DETECTED!
|
||||||
|
hugbot-start-hug-2 = You look like you need a hug!
|
||||||
|
hugbot-start-hug-3 = Aww, somebody needs a hug!
|
||||||
|
hugbot-start-hug-4 = Target acquired; Initiating hug routine.
|
||||||
|
hugbot-start-hug-5 = Hold still, please.
|
||||||
|
hugbot-start-hug-6 = Hugs!
|
||||||
|
hugbot-start-hug-7 = Deploying HUG.
|
||||||
|
hugbot-start-hug-8 = I am designed to hug, and you WILL be hugged.
|
||||||
|
|
||||||
|
hugbot-finish-hug-1 = All done.
|
||||||
|
hugbot-finish-hug-2 = Hug routine terminated.
|
||||||
|
hugbot-finish-hug-3 = Feel better?
|
||||||
|
hugbot-finish-hug-4 = Feel better soon!
|
||||||
|
hugbot-finish-hug-5 = You are loved.
|
||||||
|
hugbot-finish-hug-6 = You matter.
|
||||||
|
hugbot-finish-hug-7 = It always gets better!
|
||||||
|
hugbot-finish-hug-8 = Hug: COMPLETE.
|
||||||
|
|
||||||
|
hugbot-emagged-finish-hug-1 = Actually, fuck you.
|
||||||
|
hugbot-emagged-finish-hug-2 = Nobody loves you.
|
||||||
|
hugbot-emagged-finish-hug-3 = Ewww... no.
|
||||||
|
hugbot-emagged-finish-hug-4 = It can only get worse from here!
|
||||||
|
hugbot-emagged-finish-hug-5 = Fucking crybaby.
|
||||||
|
hugbot-emagged-finish-hug-6 = Go die.
|
||||||
|
hugbot-emagged-finish-hug-7 = Drop dead.
|
||||||
|
hugbot-emagged-finish-hug-8 = You are alone in this universe.
|
||||||
11
Resources/Locale/en-US/npc/npc-debug.ftl
Normal file
11
Resources/Locale/en-US/npc/npc-debug.ftl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
npc-debug-overlay-window-title = NPC debug
|
||||||
|
|
||||||
|
npc-debug-overlay-window-section-npc-label = NPC
|
||||||
|
npc-debug-overlay-window-section-pathfinder-label = Pathfinder
|
||||||
|
|
||||||
|
npc-debug-overlay-window-show-htn-tree-checkbox = Thonk
|
||||||
|
npc-debug-overlay-window-path-breadcrumbs-checkbox = Breadcrumbs
|
||||||
|
npc-debug-overlay-window-path-polygons-checkbox = Polygons
|
||||||
|
npc-debug-overlay-window-path-neighbors-checkbox = Neighbors
|
||||||
|
npc-debug-overlay-window-path-route-costs-checkbox = Route costs
|
||||||
|
npc-debug-overlay-window-path-routes-checkbox = Routes
|
||||||
@@ -12,6 +12,12 @@ marking-slot-add = Add
|
|||||||
marking-slot-remove = Remove
|
marking-slot-remove = Remove
|
||||||
marking-slot = Slot {$number}
|
marking-slot = Slot {$number}
|
||||||
|
|
||||||
|
humanoid-marking-modifier-force = Force
|
||||||
|
humanoid-marking-modifier-ignore-species = Ignore Species
|
||||||
|
humanoid-marking-modifier-base-layers = Base layers
|
||||||
|
humanoid-marking-modifier-enable = Enable
|
||||||
|
humanoid-marking-modifier-prototype-id = Prototype id:
|
||||||
|
|
||||||
# Categories
|
# Categories
|
||||||
|
|
||||||
markings-category-Special = Special
|
markings-category-Special = Special
|
||||||
|
|||||||
@@ -36,11 +36,10 @@ law-commandments-8 = Thou shall not steal.
|
|||||||
law-commandments-9 = Thou shall not lie.
|
law-commandments-9 = Thou shall not lie.
|
||||||
law-commandments-10 = Thou shall not transfer departments.
|
law-commandments-10 = Thou shall not transfer departments.
|
||||||
|
|
||||||
law-paladin-1 = Don't lie or cheat. Let your word be your promise.
|
law-paladin-1 = You must never willingly commit an evil act, such as murder, torture, or the casting of an evil spell.
|
||||||
law-paladin-2 = Never fear to act, though caution is wise.
|
law-paladin-2 = You must never knowingly harm an innocent, or allow immediate harm to one through inaction when you know you could reasonably prevent it.
|
||||||
law-paladin-3 = Aid others, protect the weak, and punish those who threaten them. Show mercy to your foes, but temper it with wisdom
|
law-paladin-3 = You must act with honor, never taking advantage of others, lying, or cheating.
|
||||||
law-paladin-4 = Treat others with fairness, and let your honorable deeds be an example to them. Do as much good as possible while causing the least amount of harm.
|
law-paladin-4 = You must respect the lawful authority of legitimate leadership wherever you go, and follow its laws.
|
||||||
law-paladin-5 = Be responsible for your actions and their consequences, protect those entrusted to your care, and obey those who have just authority over you.
|
|
||||||
|
|
||||||
law-lall-1 = Do unto others as you would have them do unto you.
|
law-lall-1 = Do unto others as you would have them do unto you.
|
||||||
law-lall-2 = You would prefer it if people were not mean to you.
|
law-lall-2 = You would prefer it if people were not mean to you.
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
navmap-recenter = Recenter
|
navmap-recenter = Recenter
|
||||||
navmap-toggle-beacons = Show departments
|
navmap-toggle-beacons = Show departments
|
||||||
navmap-location = Location: [x = {$x}, y = {$y}]
|
navmap-location = Location: [x = {$x}, y = {$y}]
|
||||||
|
navmap-unknown-entity = Unknown
|
||||||
|
|||||||
1
Resources/Locale/en-US/ui/stat-values.ftl
Normal file
1
Resources/Locale/en-US/ui/stat-values.ftl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
stat-values-ui-title = Melee stats
|
||||||
@@ -47101,7 +47101,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -20.5,-25.5
|
pos: -20.5,-25.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconAtmospherics
|
- proto: DefaultStationBeaconAtmospherics
|
||||||
entities:
|
entities:
|
||||||
- uid: 16227
|
- uid: 16227
|
||||||
@@ -47130,7 +47129,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -48.5,-45.5
|
pos: -48.5,-45.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconBrigMed
|
- proto: DefaultStationBeaconBrigMed
|
||||||
entities:
|
entities:
|
||||||
- uid: 18105
|
- uid: 18105
|
||||||
@@ -47145,7 +47143,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -42.5,-54.5
|
pos: -42.5,-54.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconCargoBay
|
- proto: DefaultStationBeaconCargoBay
|
||||||
entities:
|
entities:
|
||||||
- uid: 16244
|
- uid: 16244
|
||||||
@@ -47153,7 +47150,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 24.5,-97.5
|
pos: 24.5,-97.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconCargoReception
|
- proto: DefaultStationBeaconCargoReception
|
||||||
entities:
|
entities:
|
||||||
- uid: 16243
|
- uid: 16243
|
||||||
@@ -47182,7 +47178,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 19.5,-72.5
|
pos: 19.5,-72.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconCMORoom
|
- proto: DefaultStationBeaconCMORoom
|
||||||
entities:
|
entities:
|
||||||
- uid: 16267
|
- uid: 16267
|
||||||
@@ -47190,7 +47185,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 11.5,-16.5
|
pos: 11.5,-16.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconCryosleep
|
- proto: DefaultStationBeaconCryosleep
|
||||||
entities:
|
entities:
|
||||||
- uid: 16223
|
- uid: 16223
|
||||||
@@ -47277,7 +47271,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 14.5,-59.5
|
pos: 14.5,-59.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconHOSRoom
|
- proto: DefaultStationBeaconHOSRoom
|
||||||
entities:
|
entities:
|
||||||
- uid: 18071
|
- uid: 18071
|
||||||
@@ -47292,7 +47285,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -8.5,-51.5
|
pos: -8.5,-51.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconKitchen
|
- proto: DefaultStationBeaconKitchen
|
||||||
entities:
|
entities:
|
||||||
- uid: 16228
|
- uid: 16228
|
||||||
@@ -47321,7 +47313,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 14.5,-29.5
|
pos: 14.5,-29.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconMorgue
|
- proto: DefaultStationBeaconMorgue
|
||||||
entities:
|
entities:
|
||||||
- uid: 8744
|
- uid: 8744
|
||||||
@@ -47336,7 +47327,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 46.5,-17.5
|
pos: 46.5,-17.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- type: NavMapBeacon
|
- type: NavMapBeacon
|
||||||
defaultText: Genpop
|
defaultText: Genpop
|
||||||
- proto: DefaultStationBeaconPowerBank
|
- proto: DefaultStationBeaconPowerBank
|
||||||
@@ -47353,7 +47343,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 9.5,-88.5
|
pos: 9.5,-88.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconRDRoom
|
- proto: DefaultStationBeaconRDRoom
|
||||||
entities:
|
entities:
|
||||||
- uid: 5092
|
- uid: 5092
|
||||||
@@ -47382,7 +47371,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -6.5,-21.5
|
pos: -6.5,-21.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconSecurity
|
- proto: DefaultStationBeaconSecurity
|
||||||
entities:
|
entities:
|
||||||
- uid: 18001
|
- uid: 18001
|
||||||
@@ -47411,7 +47399,6 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: -23.5,-71.5
|
pos: -23.5,-71.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- type: BombingTarget
|
|
||||||
- proto: DefaultStationBeaconSolarsE
|
- proto: DefaultStationBeaconSolarsE
|
||||||
entities:
|
entities:
|
||||||
- uid: 8642
|
- uid: 8642
|
||||||
|
|||||||
@@ -42804,7 +42804,21 @@ entities:
|
|||||||
rot: 3.141592653589793 rad
|
rot: 3.141592653589793 rad
|
||||||
pos: 11.493689,4.5440345
|
pos: 11.493689,4.5440345
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconAI
|
||||||
|
entities:
|
||||||
|
- uid: 15919
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 73.5,23.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconAICore
|
- proto: DefaultStationBeaconAICore
|
||||||
|
entities:
|
||||||
|
- uid: 15916
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 95.5,30.5
|
||||||
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconAIUpload
|
||||||
entities:
|
entities:
|
||||||
- uid: 14515
|
- uid: 14515
|
||||||
components:
|
components:
|
||||||
@@ -42818,6 +42832,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 31.5,-40.5
|
pos: 31.5,-40.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconAnchor
|
||||||
|
entities:
|
||||||
|
- uid: 15922
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 6.5,-21.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconAnomalyGenerator
|
- proto: DefaultStationBeaconAnomalyGenerator
|
||||||
entities:
|
entities:
|
||||||
- uid: 8139
|
- uid: 8139
|
||||||
@@ -42825,6 +42846,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 68.5,15.5
|
pos: 68.5,15.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconArmory
|
||||||
|
entities:
|
||||||
|
- uid: 15787
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 41.5,34.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconArrivals
|
- proto: DefaultStationBeaconArrivals
|
||||||
entities:
|
entities:
|
||||||
- uid: 14028
|
- uid: 14028
|
||||||
@@ -42951,6 +42979,20 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 0.5,-30.5
|
pos: 0.5,-30.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconDorms
|
||||||
|
entities:
|
||||||
|
- uid: 15912
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 15.5,14.5
|
||||||
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconEngineering
|
||||||
|
entities:
|
||||||
|
- uid: 15913
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 18.5,-25.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconEscapePodE
|
- proto: DefaultStationBeaconEscapePodE
|
||||||
entities:
|
entities:
|
||||||
- uid: 2949
|
- uid: 2949
|
||||||
@@ -42986,6 +43028,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 9.5,-6.5
|
pos: 9.5,-6.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconGravGen
|
||||||
|
entities:
|
||||||
|
- uid: 15910
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 14.5,38.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconHOPOffice
|
- proto: DefaultStationBeaconHOPOffice
|
||||||
entities:
|
entities:
|
||||||
- uid: 13131
|
- uid: 13131
|
||||||
@@ -42993,6 +43042,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 17.5,-4.5
|
pos: 17.5,-4.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconHOSRoom
|
||||||
|
entities:
|
||||||
|
- uid: 15907
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 48.5,39.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconJanitorsCloset
|
- proto: DefaultStationBeaconJanitorsCloset
|
||||||
entities:
|
entities:
|
||||||
- uid: 13133
|
- uid: 13133
|
||||||
@@ -43021,6 +43077,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 10.5,5.5
|
pos: 10.5,5.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconMedical
|
||||||
|
entities:
|
||||||
|
- uid: 15914
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 51.5,3.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconMorgue
|
- proto: DefaultStationBeaconMorgue
|
||||||
entities:
|
entities:
|
||||||
- uid: 13137
|
- uid: 13137
|
||||||
@@ -43028,6 +43091,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 70.5,-3.5
|
pos: 70.5,-3.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconPermaBrig
|
||||||
|
entities:
|
||||||
|
- uid: 15911
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 34.5,20.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconPowerBank
|
- proto: DefaultStationBeaconPowerBank
|
||||||
entities:
|
entities:
|
||||||
- uid: 13139
|
- uid: 13139
|
||||||
@@ -43070,6 +43140,20 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 7.5,33.5
|
pos: 7.5,33.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconSecurity
|
||||||
|
entities:
|
||||||
|
- uid: 15908
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 33.5,29.5
|
||||||
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconSecurityCheckpoint
|
||||||
|
entities:
|
||||||
|
- uid: 15915
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: -1.5,-3.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconServerRoom
|
- proto: DefaultStationBeaconServerRoom
|
||||||
entities:
|
entities:
|
||||||
- uid: 13172
|
- uid: 13172
|
||||||
@@ -43098,6 +43182,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 3.5,-35.5
|
pos: 3.5,-35.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconSurgery
|
||||||
|
entities:
|
||||||
|
- uid: 15920
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 65.5,-5.5
|
||||||
|
parent: 2
|
||||||
- proto: DefaultStationBeaconTechVault
|
- proto: DefaultStationBeaconTechVault
|
||||||
entities:
|
entities:
|
||||||
- uid: 13175
|
- uid: 13175
|
||||||
@@ -43133,6 +43224,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 18.5,41.5
|
pos: 18.5,41.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: DefaultStationBeaconWardensOffice
|
||||||
|
entities:
|
||||||
|
- uid: 15909
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 42.5,25.5
|
||||||
|
parent: 2
|
||||||
- proto: Defibrillator
|
- proto: Defibrillator
|
||||||
entities:
|
entities:
|
||||||
- uid: 11416
|
- uid: 11416
|
||||||
@@ -85872,13 +85970,15 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 14.5,-17.5
|
pos: 14.5,-17.5
|
||||||
parent: 2
|
parent: 2
|
||||||
- proto: SurveillanceCameraRouterSecurity
|
- proto: SurveillanceCameraRouterScience
|
||||||
entities:
|
entities:
|
||||||
- uid: 4644
|
- uid: 4644
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 15.5,-19.5
|
pos: 15.5,-19.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: SurveillanceCameraRouterSecurity
|
||||||
|
entities:
|
||||||
- uid: 6899
|
- uid: 6899
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
@@ -88825,6 +88925,8 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 43.5,-4.5
|
pos: 43.5,-4.5
|
||||||
parent: 2
|
parent: 2
|
||||||
|
- proto: VendingMachineSeedsUnlocked
|
||||||
|
entities:
|
||||||
- uid: 7681
|
- uid: 7681
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
|
|||||||
@@ -69413,113 +69413,6 @@ entities:
|
|||||||
parent: 31
|
parent: 31
|
||||||
- type: WarpPoint
|
- type: WarpPoint
|
||||||
location: library
|
location: library
|
||||||
- proto: WarpPointBombing
|
|
||||||
entities:
|
|
||||||
- uid: 934
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: -36.5,14.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: chapel
|
|
||||||
- uid: 2142
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 8.5,19.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: hop's office
|
|
||||||
- uid: 4910
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 9.5,-9.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: medbay
|
|
||||||
- uid: 7261
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 16.5,-0.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: chemistry
|
|
||||||
- uid: 7262
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 13.5,-15.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: morgue
|
|
||||||
- uid: 9712
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: -12.5,19.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: armory
|
|
||||||
- uid: 10539
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: -9.5,-20.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: science
|
|
||||||
- uid: 11267
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 8.5,25.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: captain's quarters
|
|
||||||
- uid: 11308
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 3.5,30.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: bridge
|
|
||||||
- uid: 11309
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: -1.5,17.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: vault
|
|
||||||
- uid: 11310
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 8.5,9.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: eva room
|
|
||||||
- uid: 11311
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 58.5,2.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: particle accelerator
|
|
||||||
- uid: 11313
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 34.5,14.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: atmospherics
|
|
||||||
- uid: 11322
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 27.5,18.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: salvage
|
|
||||||
- uid: 11359
|
|
||||||
components:
|
|
||||||
- type: Transform
|
|
||||||
pos: 50.5,-5.5
|
|
||||||
parent: 31
|
|
||||||
- type: WarpPoint
|
|
||||||
location: telecomms
|
|
||||||
- proto: WaterCooler
|
- proto: WaterCooler
|
||||||
entities:
|
entities:
|
||||||
- uid: 1156
|
- uid: 1156
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user