Merge pull request #542 from crystallpunk-14/ed-06-11-2024-upstream
Ed 06 11 2024 upstream
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.Overlays;
|
using Content.Shared.Overlays;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
@@ -34,7 +36,7 @@ public sealed class ShowHealthBarsCommand : LocalizedCommands
|
|||||||
{
|
{
|
||||||
var showHealthBarsComponent = new ShowHealthBarsComponent
|
var showHealthBarsComponent = new ShowHealthBarsComponent
|
||||||
{
|
{
|
||||||
DamageContainers = args.ToList(),
|
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
|
||||||
HealthStatusIcon = null,
|
HealthStatusIcon = null,
|
||||||
NetSyncEnabled = false
|
NetSyncEnabled = false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsCo
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
|
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
|
||||||
ev.StatusIcons.Add(iconPrototype!);
|
ev.StatusIcons.Add(iconPrototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Margin="8 0 8 0">
|
||||||
|
<BoxContainer Name="Buttons"
|
||||||
|
Orientation="Vertical"
|
||||||
|
SeparationOverride="5">
|
||||||
|
<!-- Buttons are added here by code -->
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
@@ -10,20 +10,17 @@ using Robust.Shared.Utility;
|
|||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
{
|
{
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GhostRolesEntry : BoxContainer
|
public sealed partial class GhostRoleButtonsBox : BoxContainer
|
||||||
{
|
{
|
||||||
private SpriteSystem _spriteSystem;
|
private SpriteSystem _spriteSystem;
|
||||||
public event Action<GhostRoleInfo>? OnRoleSelected;
|
public event Action<GhostRoleInfo>? OnRoleSelected;
|
||||||
public event Action<GhostRoleInfo>? OnRoleFollow;
|
public event Action<GhostRoleInfo>? OnRoleFollow;
|
||||||
|
|
||||||
public GhostRolesEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
public GhostRoleButtonsBox(bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_spriteSystem = spriteSystem;
|
_spriteSystem = spriteSystem;
|
||||||
|
|
||||||
Title.Text = name;
|
|
||||||
Description.SetMessage(description);
|
|
||||||
|
|
||||||
foreach (var role in roles)
|
foreach (var role in roles)
|
||||||
{
|
{
|
||||||
var button = new GhostRoleEntryButtons(role);
|
var button = new GhostRoleEntryButtons(role);
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
<Button Name="RequestButton"
|
<Button Name="RequestButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="{Loc 'ghost-roles-window-request-role-button'}"
|
Text="{Loc 'ghost-roles-window-request-role-button'}"
|
||||||
StyleClasses="OpenRight"
|
StyleClasses="OpenRight"
|
||||||
HorizontalAlignment="Left"
|
HorizontalExpand="True"
|
||||||
SetWidth="300"/>
|
SizeFlagsStretchRatio="3"/>
|
||||||
<Button Name="FollowButton"
|
<Button Name="FollowButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="{Loc 'ghost-roles-window-follow-role-button'}"
|
Text="{Loc 'ghost-roles-window-follow-role-button'}"
|
||||||
StyleClasses="OpenLeft"
|
StyleClasses="OpenLeft"
|
||||||
HorizontalAlignment="Right"
|
HorizontalExpand="True"/>
|
||||||
SetWidth="150"/>
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<Label Name="Title"
|
||||||
|
StyleClasses="LabelKeyText"/>
|
||||||
|
<PanelContainer StyleClasses="HighDivider" />
|
||||||
|
<RichTextLabel Name="Description"
|
||||||
|
Margin="0 4"/>
|
||||||
|
</BoxContainer>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
|
{
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class GhostRoleInfoBox : BoxContainer
|
||||||
|
{
|
||||||
|
public GhostRoleInfoBox(string name, string description)
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
|
Title.Text = name;
|
||||||
|
Description.SetMessage(description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
|
||||||
Orientation="Vertical"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
Margin="0 0 8 8">
|
|
||||||
<Label Name="Title"
|
|
||||||
StyleClasses="LabelKeyText"/>
|
|
||||||
<PanelContainer StyleClasses="HighDivider" />
|
|
||||||
<RichTextLabel Name="Description"
|
|
||||||
Margin="0 4"/>
|
|
||||||
<BoxContainer Name="Buttons"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Orientation="Vertical"
|
|
||||||
SeparationOverride="5">
|
|
||||||
<!-- Buttons are added here by code -->
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
@@ -5,7 +5,6 @@ using Content.Shared.Eui;
|
|||||||
using Content.Shared.Ghost.Roles;
|
using Content.Shared.Ghost.Roles;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
{
|
{
|
||||||
@@ -77,6 +76,13 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
|
|
||||||
if (state is not GhostRolesEuiState ghostState)
|
if (state is not GhostRolesEuiState ghostState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// We must save BodyVisible state, so all Collapsible boxes will not close
|
||||||
|
// on adding new ghost role.
|
||||||
|
// Save the current state of each Collapsible box being visible or not
|
||||||
|
_window.SaveCollapsibleBoxesStates();
|
||||||
|
|
||||||
|
// Clearing the container before adding new roles
|
||||||
_window.ClearEntries();
|
_window.ClearEntries();
|
||||||
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
@@ -84,28 +90,32 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
||||||
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
|
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
|
||||||
|
|
||||||
|
// TODO: role.Requirements value doesn't work at all as an equality key, this must be fixed
|
||||||
|
// Grouping roles
|
||||||
var groupedRoles = ghostState.GhostRoles.GroupBy(
|
var groupedRoles = ghostState.GhostRoles.GroupBy(
|
||||||
role => (role.Name, role.Description, role.Requirements));
|
role => (role.Name, role.Description, role.Requirements));
|
||||||
|
|
||||||
|
// Add a new entry for each role group
|
||||||
foreach (var group in groupedRoles)
|
foreach (var group in groupedRoles)
|
||||||
{
|
{
|
||||||
var name = group.Key.Name;
|
var name = group.Key.Name;
|
||||||
var description = group.Key.Description;
|
var description = group.Key.Description;
|
||||||
bool hasAccess = true;
|
var hasAccess = requirementsManager.CheckRoleRequirements(
|
||||||
FormattedMessage? reason;
|
group.Key.Requirements,
|
||||||
|
null,
|
||||||
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason))
|
out var reason);
|
||||||
{
|
|
||||||
hasAccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Adding a new role
|
||||||
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
|
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore the Collapsible box state if it is saved
|
||||||
|
_window.RestoreCollapsibleBoxesStates();
|
||||||
|
|
||||||
|
// Close the rules window if it is no longer needed
|
||||||
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
|
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
|
||||||
if (closeRulesWindow)
|
if (closeRulesWindow)
|
||||||
{
|
|
||||||
_windowRules?.Close();
|
_windowRules?.Close();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Shared.Ghost.Roles;
|
using Content.Shared.Ghost.Roles;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
@@ -12,20 +15,86 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
|
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
|
||||||
public event Action<GhostRoleInfo>? OnRoleFollow;
|
public event Action<GhostRoleInfo>? OnRoleFollow;
|
||||||
|
|
||||||
|
private Dictionary<(string name, string description), Collapsible> _collapsibleBoxes = new();
|
||||||
|
private HashSet<(string name, string description)> _uncollapsedStates = new();
|
||||||
|
|
||||||
|
public GhostRolesWindow()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void ClearEntries()
|
public void ClearEntries()
|
||||||
{
|
{
|
||||||
NoRolesMessage.Visible = true;
|
NoRolesMessage.Visible = true;
|
||||||
EntryContainer.DisposeAllChildren();
|
EntryContainer.DisposeAllChildren();
|
||||||
|
_collapsibleBoxes.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveCollapsibleBoxesStates()
|
||||||
|
{
|
||||||
|
_uncollapsedStates.Clear();
|
||||||
|
foreach (var (key, collapsible) in _collapsibleBoxes)
|
||||||
|
{
|
||||||
|
if (collapsible.BodyVisible)
|
||||||
|
{
|
||||||
|
_uncollapsedStates.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RestoreCollapsibleBoxesStates()
|
||||||
|
{
|
||||||
|
foreach (var (key, collapsible) in _collapsibleBoxes)
|
||||||
|
{
|
||||||
|
collapsible.BodyVisible = _uncollapsedStates.Contains(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
||||||
{
|
{
|
||||||
NoRolesMessage.Visible = false;
|
NoRolesMessage.Visible = false;
|
||||||
|
|
||||||
var entry = new GhostRolesEntry(name, description, hasAccess, reason, roles, spriteSystem);
|
var ghostRoleInfos = roles.ToList();
|
||||||
entry.OnRoleSelected += OnRoleRequestButtonClicked;
|
var rolesCount = ghostRoleInfos.Count;
|
||||||
entry.OnRoleFollow += OnRoleFollow;
|
|
||||||
EntryContainer.AddChild(entry);
|
var info = new GhostRoleInfoBox(name, description);
|
||||||
|
var buttons = new GhostRoleButtonsBox(hasAccess, reason, ghostRoleInfos, spriteSystem);
|
||||||
|
buttons.OnRoleSelected += OnRoleRequestButtonClicked;
|
||||||
|
buttons.OnRoleFollow += OnRoleFollow;
|
||||||
|
|
||||||
|
EntryContainer.AddChild(info);
|
||||||
|
|
||||||
|
if (rolesCount > 1)
|
||||||
|
{
|
||||||
|
var buttonHeading = new CollapsibleHeading(Loc.GetString("ghost-roles-window-available-button", ("rolesCount", rolesCount)));
|
||||||
|
|
||||||
|
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
|
||||||
|
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
|
||||||
|
buttonHeading.Label.HorizontalExpand = true;
|
||||||
|
|
||||||
|
var body = new CollapsibleBody
|
||||||
|
{
|
||||||
|
Margin = new Thickness(0, 5, 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Add Requirements to this key when it'll be fixed and work as an equality key in GhostRolesEui
|
||||||
|
var key = (name, description);
|
||||||
|
|
||||||
|
var collapsible = new Collapsible(buttonHeading, body)
|
||||||
|
{
|
||||||
|
Orientation = BoxContainer.LayoutOrientation.Vertical,
|
||||||
|
Margin = new Thickness(0, 0, 0, 8),
|
||||||
|
};
|
||||||
|
|
||||||
|
body.AddChild(buttons);
|
||||||
|
|
||||||
|
EntryContainer.AddChild(collapsible);
|
||||||
|
_collapsibleBoxes.Add(key, collapsible);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EntryContainer.AddChild(buttons);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Content.Client.Gameplay;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
@@ -8,6 +9,7 @@ using Content.Shared.Voting;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
|
using Robust.Client.State;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
@@ -28,6 +30,7 @@ namespace Content.Client.Voting.UI
|
|||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
|
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly IStateManager _state = default!;
|
||||||
|
|
||||||
private VotingSystem _votingSystem;
|
private VotingSystem _votingSystem;
|
||||||
|
|
||||||
@@ -62,7 +65,7 @@ namespace Content.Client.Voting.UI
|
|||||||
|
|
||||||
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
||||||
CloseButton.OnPressed += _ => Close();
|
CloseButton.OnPressed += _ => Close();
|
||||||
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime) / 60));
|
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime)));
|
||||||
|
|
||||||
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
|
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
|
||||||
{
|
{
|
||||||
@@ -70,6 +73,7 @@ namespace Content.Client.Voting.UI
|
|||||||
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
|
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_state.OnStateChanged += OnStateChanged;
|
||||||
VoteTypeButton.OnItemSelected += VoteTypeSelected;
|
VoteTypeButton.OnItemSelected += VoteTypeSelected;
|
||||||
CreateButton.OnPressed += CreatePressed;
|
CreateButton.OnPressed += CreatePressed;
|
||||||
FollowButton.OnPressed += FollowSelected;
|
FollowButton.OnPressed += FollowSelected;
|
||||||
@@ -101,6 +105,14 @@ namespace Content.Client.Voting.UI
|
|||||||
UpdateVoteTimeout();
|
UpdateVoteTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnStateChanged(StateChangedEventArgs obj)
|
||||||
|
{
|
||||||
|
if (obj.NewState is not GameplayState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
private void CanCallVoteChanged(bool obj)
|
private void CanCallVoteChanged(bool obj)
|
||||||
{
|
{
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
|
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
|
||||||
{
|
{
|
||||||
if (!_ghostSystem.IsGhost)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
VotePlayerListResponse?.Invoke(msg);
|
VotePlayerListResponse?.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ using Robust.Shared.Toolshed;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Silicons.Laws;
|
using Content.Server.Silicons.Laws;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Silicons.Laws.Components;
|
using Content.Shared.Silicons.Laws.Components;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Content.Shared.Silicons.StationAi;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using static Content.Shared.Configurable.ConfigurationComponent;
|
using static Content.Shared.Configurable.ConfigurationComponent;
|
||||||
|
|
||||||
@@ -345,7 +347,30 @@ namespace Content.Server.Administration.Systems
|
|||||||
Impact = LogImpact.Low
|
Impact = LogImpact.Low
|
||||||
});
|
});
|
||||||
|
|
||||||
if (TryComp<SiliconLawBoundComponent>(args.Target, out var lawBoundComponent))
|
// This logic is needed to be able to modify the AI's laws through its core and eye.
|
||||||
|
EntityUid? target = null;
|
||||||
|
SiliconLawBoundComponent? lawBoundComponent = null;
|
||||||
|
|
||||||
|
if (TryComp(args.Target, out lawBoundComponent))
|
||||||
|
{
|
||||||
|
target = args.Target;
|
||||||
|
}
|
||||||
|
// When inspecting the core we can find the entity with its laws by looking at the AiHolderComponent.
|
||||||
|
else if (TryComp<StationAiHolderComponent>(args.Target, out var holder) && holder.Slot.Item != null
|
||||||
|
&& TryComp(holder.Slot.Item, out lawBoundComponent))
|
||||||
|
{
|
||||||
|
target = holder.Slot.Item.Value;
|
||||||
|
// For the eye we can find the entity with its laws as the source of the movement relay since the eye
|
||||||
|
// is just a proxy for it to move around and look around the station.
|
||||||
|
}
|
||||||
|
else if (TryComp<MovementRelayTargetComponent>(args.Target, out var relay)
|
||||||
|
&& TryComp(relay.Source, out lawBoundComponent))
|
||||||
|
{
|
||||||
|
target = relay.Source;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lawBoundComponent != null && target != null)
|
||||||
{
|
{
|
||||||
args.Verbs.Add(new Verb()
|
args.Verbs.Add(new Verb()
|
||||||
{
|
{
|
||||||
@@ -359,7 +384,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_euiManager.OpenEui(ui, session);
|
_euiManager.OpenEui(ui, session);
|
||||||
ui.UpdateLaws(lawBoundComponent, args.Target);
|
ui.UpdateLaws(lawBoundComponent, target.Value);
|
||||||
},
|
},
|
||||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,20 +47,23 @@ namespace Content.Server.Administration.Systems
|
|||||||
[GeneratedRegex(@"^https://discord\.com/api/webhooks/(\d+)/((?!.*/).*)$")]
|
[GeneratedRegex(@"^https://discord\.com/api/webhooks/(\d+)/((?!.*/).*)$")]
|
||||||
private static partial Regex DiscordRegex();
|
private static partial Regex DiscordRegex();
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
|
||||||
private readonly HttpClient _httpClient = new();
|
|
||||||
private string _webhookUrl = string.Empty;
|
private string _webhookUrl = string.Empty;
|
||||||
private WebhookData? _webhookData;
|
private WebhookData? _webhookData;
|
||||||
|
|
||||||
|
private string _onCallUrl = string.Empty;
|
||||||
|
private WebhookData? _onCallData;
|
||||||
|
|
||||||
|
private ISawmill _sawmill = default!;
|
||||||
|
private readonly HttpClient _httpClient = new();
|
||||||
|
|
||||||
private string _footerIconUrl = string.Empty;
|
private string _footerIconUrl = string.Empty;
|
||||||
private string _avatarUrl = string.Empty;
|
private string _avatarUrl = string.Empty;
|
||||||
private string _serverName = string.Empty;
|
private string _serverName = string.Empty;
|
||||||
|
|
||||||
private readonly
|
private readonly Dictionary<NetUserId, DiscordRelayInteraction> _relayMessages = new();
|
||||||
Dictionary<NetUserId, (string? id, string username, string description, string? characterName, GameRunLevel
|
|
||||||
lastRunLevel)> _relayMessages = new();
|
|
||||||
|
|
||||||
private Dictionary<NetUserId, string> _oldMessageIds = new();
|
private Dictionary<NetUserId, string> _oldMessageIds = new();
|
||||||
private readonly Dictionary<NetUserId, Queue<string>> _messageQueues = new();
|
private readonly Dictionary<NetUserId, Queue<DiscordRelayedData>> _messageQueues = new();
|
||||||
private readonly HashSet<NetUserId> _processingChannels = new();
|
private readonly HashSet<NetUserId> _processingChannels = new();
|
||||||
private readonly Dictionary<NetUserId, (TimeSpan Timestamp, bool Typing)> _typingUpdateTimestamps = new();
|
private readonly Dictionary<NetUserId, (TimeSpan Timestamp, bool Typing)> _typingUpdateTimestamps = new();
|
||||||
private string _overrideClientName = string.Empty;
|
private string _overrideClientName = string.Empty;
|
||||||
@@ -82,12 +85,16 @@ namespace Content.Server.Administration.Systems
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
Subs.CVar(_config, CCVars.DiscordOnCallWebhook, OnCallChanged, true);
|
||||||
|
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpWebhook, OnWebhookChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpWebhook, OnWebhookChanged, true);
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpFooterIcon, OnFooterIconChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpFooterIcon, OnFooterIconChanged, true);
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpAvatar, OnAvatarChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpAvatar, OnAvatarChanged, true);
|
||||||
Subs.CVar(_config, CVars.GameHostName, OnServerNameChanged, true);
|
Subs.CVar(_config, CVars.GameHostName, OnServerNameChanged, true);
|
||||||
Subs.CVar(_config, CCVars.AdminAhelpOverrideClientName, OnOverrideChanged, true);
|
Subs.CVar(_config, CCVars.AdminAhelpOverrideClientName, OnOverrideChanged, true);
|
||||||
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("AHELP");
|
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("AHELP");
|
||||||
|
|
||||||
var defaultParams = new AHelpMessageParams(
|
var defaultParams = new AHelpMessageParams(
|
||||||
string.Empty,
|
string.Empty,
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -96,7 +103,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
_gameTicker.RunLevel,
|
_gameTicker.RunLevel,
|
||||||
playedSound: false
|
playedSound: false
|
||||||
);
|
);
|
||||||
_maxAdditionalChars = GenerateAHelpMessage(defaultParams).Length;
|
_maxAdditionalChars = GenerateAHelpMessage(defaultParams).Message.Length;
|
||||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
|
||||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
||||||
@@ -111,6 +118,33 @@ namespace Content.Server.Administration.Systems
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void OnCallChanged(string url)
|
||||||
|
{
|
||||||
|
_onCallUrl = url;
|
||||||
|
|
||||||
|
if (url == string.Empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var match = DiscordRegex().Match(url);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
Log.Error("On call URL does not appear to be valid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match.Groups.Count <= 2)
|
||||||
|
{
|
||||||
|
Log.Error("Could not get webhook ID or token for on call URL.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var webhookId = match.Groups[1].Value;
|
||||||
|
var webhookToken = match.Groups[2].Value;
|
||||||
|
|
||||||
|
_onCallData = await GetWebhookData(webhookId, webhookToken);
|
||||||
|
}
|
||||||
|
|
||||||
private void PlayerRateLimitedAction(ICommonSession obj)
|
private void PlayerRateLimitedAction(ICommonSession obj)
|
||||||
{
|
{
|
||||||
RaiseNetworkEvent(
|
RaiseNetworkEvent(
|
||||||
@@ -259,13 +293,13 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
// Store the Discord message IDs of the previous round
|
// Store the Discord message IDs of the previous round
|
||||||
_oldMessageIds = new Dictionary<NetUserId, string>();
|
_oldMessageIds = new Dictionary<NetUserId, string>();
|
||||||
foreach (var message in _relayMessages)
|
foreach (var (user, interaction) in _relayMessages)
|
||||||
{
|
{
|
||||||
var id = message.Value.id;
|
var id = interaction.Id;
|
||||||
if (id == null)
|
if (id == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_oldMessageIds[message.Key] = id;
|
_oldMessageIds[user] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
_relayMessages.Clear();
|
_relayMessages.Clear();
|
||||||
@@ -330,10 +364,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
var webhookToken = match.Groups[2].Value;
|
var webhookToken = match.Groups[2].Value;
|
||||||
|
|
||||||
// Fire and forget
|
// Fire and forget
|
||||||
await SetWebhookData(webhookId, webhookToken);
|
_webhookData = await GetWebhookData(webhookId, webhookToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetWebhookData(string id, string token)
|
private async Task<WebhookData?> GetWebhookData(string id, string token)
|
||||||
{
|
{
|
||||||
var response = await _httpClient.GetAsync($"https://discord.com/api/v10/webhooks/{id}/{token}");
|
var response = await _httpClient.GetAsync($"https://discord.com/api/v10/webhooks/{id}/{token}");
|
||||||
|
|
||||||
@@ -342,10 +376,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
{
|
{
|
||||||
_sawmill.Log(LogLevel.Error,
|
_sawmill.Log(LogLevel.Error,
|
||||||
$"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
$"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_webhookData = JsonSerializer.Deserialize<WebhookData>(content);
|
return JsonSerializer.Deserialize<WebhookData>(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFooterIconChanged(string url)
|
private void OnFooterIconChanged(string url)
|
||||||
@@ -358,14 +392,14 @@ namespace Content.Server.Administration.Systems
|
|||||||
_avatarUrl = url;
|
_avatarUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ProcessQueue(NetUserId userId, Queue<string> messages)
|
private async void ProcessQueue(NetUserId userId, Queue<DiscordRelayedData> messages)
|
||||||
{
|
{
|
||||||
// Whether an embed already exists for this player
|
// Whether an embed already exists for this player
|
||||||
var exists = _relayMessages.TryGetValue(userId, out var existingEmbed);
|
var exists = _relayMessages.TryGetValue(userId, out var existingEmbed);
|
||||||
|
|
||||||
// Whether the message will become too long after adding these new messages
|
// Whether the message will become too long after adding these new messages
|
||||||
var tooLong = exists && messages.Sum(msg => Math.Min(msg.Length, MessageLengthCap) + "\n".Length)
|
var tooLong = exists && messages.Sum(msg => Math.Min(msg.Message.Length, MessageLengthCap) + "\n".Length)
|
||||||
+ existingEmbed.description.Length > DescriptionMax;
|
+ existingEmbed?.Description.Length > DescriptionMax;
|
||||||
|
|
||||||
// If there is no existing embed, or it is getting too long, we create a new embed
|
// If there is no existing embed, or it is getting too long, we create a new embed
|
||||||
if (!exists || tooLong)
|
if (!exists || tooLong)
|
||||||
@@ -385,10 +419,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
// If we have all the data required, we can link to the embed of the previous round or embed that was too long
|
// If we have all the data required, we can link to the embed of the previous round or embed that was too long
|
||||||
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
||||||
{
|
{
|
||||||
if (tooLong && existingEmbed.id != null)
|
if (tooLong && existingEmbed?.Id != null)
|
||||||
{
|
{
|
||||||
linkToPrevious =
|
linkToPrevious =
|
||||||
$"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.id})**\n";
|
$"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.Id})**\n";
|
||||||
}
|
}
|
||||||
else if (_oldMessageIds.TryGetValue(userId, out var id) && !string.IsNullOrEmpty(id))
|
else if (_oldMessageIds.TryGetValue(userId, out var id) && !string.IsNullOrEmpty(id))
|
||||||
{
|
{
|
||||||
@@ -398,13 +432,22 @@ namespace Content.Server.Administration.Systems
|
|||||||
}
|
}
|
||||||
|
|
||||||
var characterName = _minds.GetCharacterName(userId);
|
var characterName = _minds.GetCharacterName(userId);
|
||||||
existingEmbed = (null, lookup.Username, linkToPrevious, characterName, _gameTicker.RunLevel);
|
existingEmbed = new DiscordRelayInteraction()
|
||||||
|
{
|
||||||
|
Id = null,
|
||||||
|
CharacterName = characterName,
|
||||||
|
Description = linkToPrevious,
|
||||||
|
Username = lookup.Username,
|
||||||
|
LastRunLevel = _gameTicker.RunLevel,
|
||||||
|
};
|
||||||
|
|
||||||
|
_relayMessages[userId] = existingEmbed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Previous message was in another RunLevel, so show that in the embed
|
// Previous message was in another RunLevel, so show that in the embed
|
||||||
if (existingEmbed.lastRunLevel != _gameTicker.RunLevel)
|
if (existingEmbed!.LastRunLevel != _gameTicker.RunLevel)
|
||||||
{
|
{
|
||||||
existingEmbed.description += _gameTicker.RunLevel switch
|
existingEmbed.Description += _gameTicker.RunLevel switch
|
||||||
{
|
{
|
||||||
GameRunLevel.PreRoundLobby => "\n\n:arrow_forward: _**Pre-round lobby started**_\n",
|
GameRunLevel.PreRoundLobby => "\n\n:arrow_forward: _**Pre-round lobby started**_\n",
|
||||||
GameRunLevel.InRound => "\n\n:arrow_forward: _**Round started**_\n",
|
GameRunLevel.InRound => "\n\n:arrow_forward: _**Round started**_\n",
|
||||||
@@ -413,26 +456,35 @@ namespace Content.Server.Administration.Systems
|
|||||||
$"{_gameTicker.RunLevel} was not matched."),
|
$"{_gameTicker.RunLevel} was not matched."),
|
||||||
};
|
};
|
||||||
|
|
||||||
existingEmbed.lastRunLevel = _gameTicker.RunLevel;
|
existingEmbed.LastRunLevel = _gameTicker.RunLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If last message of the new batch is SOS then relay it to on-call.
|
||||||
|
// ... as long as it hasn't been relayed already.
|
||||||
|
var discordMention = messages.Last();
|
||||||
|
var onCallRelay = !discordMention.Receivers && !existingEmbed.OnCall;
|
||||||
|
|
||||||
// Add available messages to the embed description
|
// Add available messages to the embed description
|
||||||
while (messages.TryDequeue(out var message))
|
while (messages.TryDequeue(out var message))
|
||||||
{
|
{
|
||||||
// In case someone thinks they're funny
|
string text;
|
||||||
if (message.Length > MessageLengthCap)
|
|
||||||
message = message[..(MessageLengthCap - TooLongText.Length)] + TooLongText;
|
|
||||||
|
|
||||||
existingEmbed.description += $"\n{message}";
|
// In case someone thinks they're funny
|
||||||
|
if (message.Message.Length > MessageLengthCap)
|
||||||
|
text = message.Message[..(MessageLengthCap - TooLongText.Length)] + TooLongText;
|
||||||
|
else
|
||||||
|
text = message.Message;
|
||||||
|
|
||||||
|
existingEmbed.Description += $"\n{text}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = GeneratePayload(existingEmbed.description,
|
var payload = GeneratePayload(existingEmbed.Description,
|
||||||
existingEmbed.username,
|
existingEmbed.Username,
|
||||||
existingEmbed.characterName);
|
existingEmbed.CharacterName);
|
||||||
|
|
||||||
// If there is no existing embed, create a new one
|
// If there is no existing embed, create a new one
|
||||||
// Otherwise patch (edit) it
|
// Otherwise patch (edit) it
|
||||||
if (existingEmbed.id == null)
|
if (existingEmbed.Id == null)
|
||||||
{
|
{
|
||||||
var request = await _httpClient.PostAsync($"{_webhookUrl}?wait=true",
|
var request = await _httpClient.PostAsync($"{_webhookUrl}?wait=true",
|
||||||
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
||||||
@@ -455,11 +507,11 @@ namespace Content.Server.Administration.Systems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
existingEmbed.id = id.ToString();
|
existingEmbed.Id = id.ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var request = await _httpClient.PatchAsync($"{_webhookUrl}/messages/{existingEmbed.id}",
|
var request = await _httpClient.PatchAsync($"{_webhookUrl}/messages/{existingEmbed.Id}",
|
||||||
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
if (!request.IsSuccessStatusCode)
|
if (!request.IsSuccessStatusCode)
|
||||||
@@ -474,6 +526,43 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
_relayMessages[userId] = existingEmbed;
|
_relayMessages[userId] = existingEmbed;
|
||||||
|
|
||||||
|
// Actually do the on call relay last, we just need to grab it before we dequeue every message above.
|
||||||
|
if (onCallRelay &&
|
||||||
|
_onCallData != null)
|
||||||
|
{
|
||||||
|
existingEmbed.OnCall = true;
|
||||||
|
var roleMention = _config.GetCVar(CCVars.DiscordAhelpMention);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(roleMention))
|
||||||
|
{
|
||||||
|
var message = new StringBuilder();
|
||||||
|
message.AppendLine($"<@&{roleMention}>");
|
||||||
|
message.AppendLine("Unanswered SOS");
|
||||||
|
|
||||||
|
// Need webhook data to get the correct link for that channel rather than on-call data.
|
||||||
|
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
||||||
|
{
|
||||||
|
message.AppendLine(
|
||||||
|
$"**[Go to ahelp](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.Id})**");
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = GeneratePayload(message.ToString(), existingEmbed.Username, existingEmbed.CharacterName);
|
||||||
|
|
||||||
|
var request = await _httpClient.PostAsync($"{_onCallUrl}?wait=true",
|
||||||
|
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
|
var content = await request.Content.ReadAsStringAsync();
|
||||||
|
if (!request.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
_sawmill.Log(LogLevel.Error, $"Discord returned bad status code when posting relay message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingEmbed.OnCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
_processingChannels.Remove(userId);
|
_processingChannels.Remove(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +741,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
if (sendsWebhook)
|
if (sendsWebhook)
|
||||||
{
|
{
|
||||||
if (!_messageQueues.ContainsKey(msg.UserId))
|
if (!_messageQueues.ContainsKey(msg.UserId))
|
||||||
_messageQueues[msg.UserId] = new Queue<string>();
|
_messageQueues[msg.UserId] = new Queue<DiscordRelayedData>();
|
||||||
|
|
||||||
var str = message.Text;
|
var str = message.Text;
|
||||||
var unameLength = senderSession.Name.Length;
|
var unameLength = senderSession.Name.Length;
|
||||||
@@ -701,7 +790,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateAHelpMessage(AHelpMessageParams parameters)
|
private static DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
|
||||||
{
|
{
|
||||||
var stringbuilder = new StringBuilder();
|
var stringbuilder = new StringBuilder();
|
||||||
|
|
||||||
@@ -718,13 +807,57 @@ namespace Content.Server.Administration.Systems
|
|||||||
stringbuilder.Append($" **{parameters.RoundTime}**");
|
stringbuilder.Append($" **{parameters.RoundTime}**");
|
||||||
if (!parameters.PlayedSound)
|
if (!parameters.PlayedSound)
|
||||||
stringbuilder.Append(" **(S)**");
|
stringbuilder.Append(" **(S)**");
|
||||||
|
|
||||||
if (parameters.Icon == null)
|
if (parameters.Icon == null)
|
||||||
stringbuilder.Append($" **{parameters.Username}:** ");
|
stringbuilder.Append($" **{parameters.Username}:** ");
|
||||||
else
|
else
|
||||||
stringbuilder.Append($" **{parameters.Username}** ");
|
stringbuilder.Append($" **{parameters.Username}** ");
|
||||||
stringbuilder.Append(parameters.Message);
|
stringbuilder.Append(parameters.Message);
|
||||||
return stringbuilder.ToString();
|
|
||||||
|
return new DiscordRelayedData()
|
||||||
|
{
|
||||||
|
Receivers = !parameters.NoReceivers,
|
||||||
|
Message = stringbuilder.ToString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private record struct DiscordRelayedData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Was anyone online to receive it.
|
||||||
|
/// </summary>
|
||||||
|
public bool Receivers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What's the payload to send to discord.
|
||||||
|
/// </summary>
|
||||||
|
public string Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class specifically for holding information regarding existing Discord embeds
|
||||||
|
/// </summary>
|
||||||
|
private sealed class DiscordRelayInteraction
|
||||||
|
{
|
||||||
|
public string? Id;
|
||||||
|
|
||||||
|
public string Username = String.Empty;
|
||||||
|
|
||||||
|
public string? CharacterName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contents for the discord message.
|
||||||
|
/// </summary>
|
||||||
|
public string Description = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run level of the last interaction. If different we'll link to the last Id.
|
||||||
|
/// </summary>
|
||||||
|
public GameRunLevel LastRunLevel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Did we relay this interaction to OnCall previously.
|
||||||
|
/// </summary>
|
||||||
|
public bool OnCall;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public sealed partial class AmeControllerComponent : SharedAmeControllerComponen
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("injectSound")]
|
[DataField("injectSound")]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public SoundSpecifier InjectSound = new SoundCollectionSpecifier("MetalThud");
|
public SoundSpecifier InjectSound = new SoundPathSpecifier("/Audio/Machines/ame_fuelinjection.ogg");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last time this could have injected fuel into the AME.
|
/// The last time this could have injected fuel into the AME.
|
||||||
|
|||||||
@@ -680,7 +680,10 @@ public sealed class PlantHolderSystem : EntitySystem
|
|||||||
if (TryComp<HandsComponent>(user, out var hands))
|
if (TryComp<HandsComponent>(user, out var hands))
|
||||||
{
|
{
|
||||||
if (!_botany.CanHarvest(component.Seed, hands.ActiveHandEntity))
|
if (!_botany.CanHarvest(component.Seed, hands.ActiveHandEntity))
|
||||||
|
{
|
||||||
|
_popup.PopupCursor(Loc.GetString("plant-holder-component-ligneous-cant-harvest-message"), user);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!_botany.CanHarvest(component.Seed))
|
else if (!_botany.CanHarvest(component.Seed))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public sealed class ExaminableDamageSystem : EntitySystem
|
|||||||
|
|
||||||
var level = GetDamageLevel(uid, component);
|
var level = GetDamageLevel(uid, component);
|
||||||
var msg = Loc.GetString(messages[level]);
|
var msg = Loc.GetString(messages[level]);
|
||||||
args.PushMarkup(msg);
|
args.PushMarkup(msg,-99);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetDamageLevel(EntityUid uid, ExaminableDamageComponent? component = null,
|
private int GetDamageLevel(EntityUid uid, ExaminableDamageComponent? component = null,
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
SetBoltsDown(ent, true);
|
SetBoltsDown(ent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateBoltLightStatus(ent);
|
|
||||||
ent.Comp.Powered = args.Powered;
|
ent.Comp.Powered = args.Powered;
|
||||||
Dirty(ent, ent.Comp);
|
Dirty(ent, ent.Comp);
|
||||||
|
UpdateBoltLightStatus(ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,7 +172,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
// TODO: AntagCodewordsComponent
|
// TODO: AntagCodewordsComponent
|
||||||
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
|
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
|
||||||
{
|
{
|
||||||
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
|
if(comp.GiveCodewords)
|
||||||
|
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: figure out how to handle this? add priority to briefing event?
|
// TODO: figure out how to handle this? add priority to briefing event?
|
||||||
|
|||||||
@@ -49,12 +49,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
{
|
{
|
||||||
_puddle.TrySpillAt(uid, solution, out _, false);
|
_puddle.TrySpillAt(uid, solution, out _, false);
|
||||||
}
|
}
|
||||||
if (foodComp.Trash.Count == 0)
|
foreach (var trash in foodComp.Trash)
|
||||||
{
|
{
|
||||||
foreach (var trash in foodComp.Trash)
|
EntityManager.SpawnEntity(trash, Transform(uid).Coordinates);
|
||||||
{
|
|
||||||
EntityManager.SpawnEntity(trash, Transform(uid).Coordinates);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActivatePayload(uid);
|
ActivatePayload(uid);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Content.Server.Shuttles.Events;
|
|||||||
using Content.Server.Shuttles.Systems;
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Decals;
|
using Content.Shared.Decals;
|
||||||
|
using Content.Shared.Ghost;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Parallax.Biomes;
|
using Content.Shared.Parallax.Biomes;
|
||||||
using Content.Shared.Parallax.Biomes.Layers;
|
using Content.Shared.Parallax.Biomes.Layers;
|
||||||
@@ -51,6 +52,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
|
|
||||||
private EntityQuery<BiomeComponent> _biomeQuery;
|
private EntityQuery<BiomeComponent> _biomeQuery;
|
||||||
private EntityQuery<FixturesComponent> _fixturesQuery;
|
private EntityQuery<FixturesComponent> _fixturesQuery;
|
||||||
|
private EntityQuery<GhostComponent> _ghostQuery;
|
||||||
private EntityQuery<TransformComponent> _xformQuery;
|
private EntityQuery<TransformComponent> _xformQuery;
|
||||||
|
|
||||||
private readonly HashSet<EntityUid> _handledEntities = new();
|
private readonly HashSet<EntityUid> _handledEntities = new();
|
||||||
@@ -81,6 +83,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
Log.Level = LogLevel.Debug;
|
Log.Level = LogLevel.Debug;
|
||||||
_biomeQuery = GetEntityQuery<BiomeComponent>();
|
_biomeQuery = GetEntityQuery<BiomeComponent>();
|
||||||
_fixturesQuery = GetEntityQuery<FixturesComponent>();
|
_fixturesQuery = GetEntityQuery<FixturesComponent>();
|
||||||
|
_ghostQuery = GetEntityQuery<GhostComponent>();
|
||||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
SubscribeLocalEvent<BiomeComponent, MapInitEvent>(OnBiomeMapInit);
|
SubscribeLocalEvent<BiomeComponent, MapInitEvent>(OnBiomeMapInit);
|
||||||
SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted);
|
SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted);
|
||||||
@@ -315,6 +318,11 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanLoad(EntityUid uid)
|
||||||
|
{
|
||||||
|
return !_ghostQuery.HasComp(uid);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
@@ -332,7 +340,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
if (_xformQuery.TryGetComponent(pSession.AttachedEntity, out var xform) &&
|
if (_xformQuery.TryGetComponent(pSession.AttachedEntity, out var xform) &&
|
||||||
_handledEntities.Add(pSession.AttachedEntity.Value) &&
|
_handledEntities.Add(pSession.AttachedEntity.Value) &&
|
||||||
_biomeQuery.TryGetComponent(xform.MapUid, out var biome) &&
|
_biomeQuery.TryGetComponent(xform.MapUid, out var biome) &&
|
||||||
biome.Enabled)
|
biome.Enabled &&
|
||||||
|
CanLoad(pSession.AttachedEntity.Value))
|
||||||
{
|
{
|
||||||
var worldPos = _transform.GetWorldPosition(xform);
|
var worldPos = _transform.GetWorldPosition(xform);
|
||||||
AddChunksInRange(biome, worldPos);
|
AddChunksInRange(biome, worldPos);
|
||||||
@@ -349,7 +358,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
if (!_handledEntities.Add(viewer) ||
|
if (!_handledEntities.Add(viewer) ||
|
||||||
!_xformQuery.TryGetComponent(viewer, out xform) ||
|
!_xformQuery.TryGetComponent(viewer, out xform) ||
|
||||||
!_biomeQuery.TryGetComponent(xform.MapUid, out biome) ||
|
!_biomeQuery.TryGetComponent(xform.MapUid, out biome) ||
|
||||||
!biome.Enabled)
|
!biome.Enabled ||
|
||||||
|
!CanLoad(viewer))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public sealed class RadioDeviceSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
|
||||||
// Used to prevent a shitter from using a bunch of radios to spam chat.
|
// Used to prevent a shitter from using a bunch of radios to spam chat.
|
||||||
private HashSet<(string, EntityUid)> _recentlySent = new();
|
private HashSet<(string, EntityUid, RadioChannelPrototype)> _recentlySent = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -114,7 +114,7 @@ public sealed class RadioDeviceSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (args.Powered)
|
if (args.Powered)
|
||||||
return;
|
return;
|
||||||
SetMicrophoneEnabled(uid, null, false, true, component);
|
SetMicrophoneEnabled(uid, null, false, true, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMicrophoneEnabled(EntityUid uid, EntityUid? user, bool enabled, bool quiet = false, RadioMicrophoneComponent? component = null)
|
public void SetMicrophoneEnabled(EntityUid uid, EntityUid? user, bool enabled, bool quiet = false, RadioMicrophoneComponent? component = null)
|
||||||
@@ -191,8 +191,9 @@ public sealed class RadioDeviceSystem : EntitySystem
|
|||||||
if (HasComp<RadioSpeakerComponent>(args.Source))
|
if (HasComp<RadioSpeakerComponent>(args.Source))
|
||||||
return; // no feedback loops please.
|
return; // no feedback loops please.
|
||||||
|
|
||||||
if (_recentlySent.Add((args.Message, args.Source)))
|
var channel = _protoMan.Index<RadioChannelPrototype>(component.BroadcastChannel)!;
|
||||||
_radio.SendRadioMessage(args.Source, args.Message, _protoMan.Index<RadioChannelPrototype>(component.BroadcastChannel), uid);
|
if (_recentlySent.Add((args.Message, args.Source, channel)))
|
||||||
|
_radio.SendRadioMessage(args.Source, args.Message, channel, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAttemptListen(EntityUid uid, RadioMicrophoneComponent component, ListenAttemptEvent args)
|
private void OnAttemptListen(EntityUid uid, RadioMicrophoneComponent component, ListenAttemptEvent args)
|
||||||
@@ -279,7 +280,7 @@ public sealed class RadioDeviceSystem : EntitySystem
|
|||||||
if (TryComp<RadioMicrophoneComponent>(ent, out var mic))
|
if (TryComp<RadioMicrophoneComponent>(ent, out var mic))
|
||||||
mic.BroadcastChannel = channel;
|
mic.BroadcastChannel = channel;
|
||||||
if (TryComp<RadioSpeakerComponent>(ent, out var speaker))
|
if (TryComp<RadioSpeakerComponent>(ent, out var speaker))
|
||||||
speaker.Channels = new(){ channel };
|
speaker.Channels = new() { channel };
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
using Content.Server.EUI;
|
using Content.Server.EUI;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Eui;
|
using Content.Shared.Eui;
|
||||||
@@ -52,8 +52,8 @@ public sealed class SiliconLawEui : BaseEui
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var player = _entityManager.GetEntity(message.Target);
|
var player = _entityManager.GetEntity(message.Target);
|
||||||
|
if (_entityManager.TryGetComponent<SiliconLawProviderComponent>(player, out var playerProviderComp))
|
||||||
_siliconLawSystem.SetLaws(message.Laws, player);
|
_siliconLawSystem.SetLaws(message.Laws, player, playerProviderComp.LawUploadSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAllowed()
|
private bool IsAllowed()
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ using Robust.Shared.Containers;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Toolshed;
|
using Robust.Shared.Toolshed;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.Silicons.Laws;
|
namespace Content.Server.Silicons.Laws;
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
component.Lawset = args.Lawset;
|
component.Lawset = args.Lawset;
|
||||||
|
|
||||||
// gotta tell player to check their laws
|
// gotta tell player to check their laws
|
||||||
NotifyLawsChanged(uid);
|
NotifyLawsChanged(uid, component.LawUploadSound);
|
||||||
|
|
||||||
// new laws may allow antagonist behaviour so make it clear for admins
|
// new laws may allow antagonist behaviour so make it clear for admins
|
||||||
if (TryComp<EmagSiliconLawComponent>(uid, out var emag))
|
if (TryComp<EmagSiliconLawComponent>(uid, out var emag))
|
||||||
@@ -149,14 +151,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
base.OnGotEmagged(uid, component, ref args);
|
base.OnGotEmagged(uid, component, ref args);
|
||||||
NotifyLawsChanged(uid);
|
NotifyLawsChanged(uid, component.EmaggedSound);
|
||||||
EnsureEmaggedRole(uid, component);
|
EnsureEmaggedRole(uid, component);
|
||||||
|
|
||||||
_stunSystem.TryParalyze(uid, component.StunTime, true);
|
_stunSystem.TryParalyze(uid, component.StunTime, true);
|
||||||
|
|
||||||
if (!_mind.TryGetMind(uid, out var mindId, out _))
|
|
||||||
return;
|
|
||||||
_roles.MindPlaySound(mindId, component.EmaggedSound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagMindAdded(EntityUid uid, EmagSiliconLawComponent component, MindAddedMessage args)
|
private void OnEmagMindAdded(EntityUid uid, EmagSiliconLawComponent component, MindAddedMessage args)
|
||||||
@@ -237,7 +236,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
return ev.Laws;
|
return ev.Laws;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotifyLawsChanged(EntityUid uid)
|
public void NotifyLawsChanged(EntityUid uid, SoundSpecifier? cue = null)
|
||||||
{
|
{
|
||||||
if (!TryComp<ActorComponent>(uid, out var actor))
|
if (!TryComp<ActorComponent>(uid, out var actor))
|
||||||
return;
|
return;
|
||||||
@@ -245,6 +244,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
var msg = Loc.GetString("laws-update-notify");
|
var msg = Loc.GetString("laws-update-notify");
|
||||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
|
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
|
||||||
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red);
|
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red);
|
||||||
|
|
||||||
|
if (cue != null && _mind.TryGetMind(uid, out var mindId, out _))
|
||||||
|
_roles.MindPlaySound(mindId, cue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -269,7 +271,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the laws of a silicon entity while notifying the player.
|
/// Set the laws of a silicon entity while notifying the player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetLaws(List<SiliconLaw> newLaws, EntityUid target)
|
public void SetLaws(List<SiliconLaw> newLaws, EntityUid target, SoundSpecifier? cue = null)
|
||||||
{
|
{
|
||||||
if (!TryComp<SiliconLawProviderComponent>(target, out var component))
|
if (!TryComp<SiliconLawProviderComponent>(target, out var component))
|
||||||
return;
|
return;
|
||||||
@@ -278,7 +280,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
component.Lawset = new SiliconLawset();
|
component.Lawset = new SiliconLawset();
|
||||||
|
|
||||||
component.Lawset.Laws = newLaws;
|
component.Lawset.Laws = newLaws;
|
||||||
NotifyLawsChanged(target);
|
NotifyLawsChanged(target, cue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
|
protected override void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||||
@@ -292,9 +294,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
|||||||
|
|
||||||
while (query.MoveNext(out var update))
|
while (query.MoveNext(out var update))
|
||||||
{
|
{
|
||||||
SetLaws(lawset, update);
|
SetLaws(lawset, update, provider.LawUploadSound);
|
||||||
if (provider.LawUploadSound != null && _mind.TryGetMind(update, out var mindId, out _))
|
|
||||||
_roles.MindPlaySound(mindId, provider.LawUploadSound);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
|
|
||||||
private VotingSystem? _votingSystem;
|
private VotingSystem? _votingSystem;
|
||||||
private RoleSystem? _roleSystem;
|
private RoleSystem? _roleSystem;
|
||||||
|
private GameTicker? _gameTicker;
|
||||||
|
|
||||||
private static readonly Dictionary<StandardVoteType, CVarDef<bool>> _voteTypesToEnableCVars = new()
|
private static readonly Dictionary<StandardVoteType, CVarDef<bool>> _voteTypesToEnableCVars = new()
|
||||||
{
|
{
|
||||||
@@ -70,8 +71,8 @@ namespace Content.Server.Voting.Managers
|
|||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(voteType), voteType, null);
|
throw new ArgumentOutOfRangeException(nameof(voteType), voteType, null);
|
||||||
}
|
}
|
||||||
var ticker = _entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
_gameTicker = _entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||||
ticker.UpdateInfoText();
|
_gameTicker.UpdateInfoText();
|
||||||
if (timeoutVote)
|
if (timeoutVote)
|
||||||
TimeoutStandardVote(voteType);
|
TimeoutStandardVote(voteType);
|
||||||
}
|
}
|
||||||
@@ -346,8 +347,14 @@ namespace Content.Server.Voting.Managers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var voterEligibility = _cfg.GetCVar(CCVars.VotekickVoterGhostRequirement) ? VoterEligibility.GhostMinimumPlaytime : VoterEligibility.MinimumPlaytime;
|
||||||
|
if (_cfg.GetCVar(CCVars.VotekickIgnoreGhostReqInLobby) && _gameTicker!.RunLevel == GameRunLevel.PreRoundLobby)
|
||||||
|
voterEligibility = VoterEligibility.MinimumPlaytime;
|
||||||
|
|
||||||
var eligibleVoterNumberRequirement = _cfg.GetCVar(CCVars.VotekickEligibleNumberRequirement);
|
var eligibleVoterNumberRequirement = _cfg.GetCVar(CCVars.VotekickEligibleNumberRequirement);
|
||||||
var eligibleVoterNumber = _cfg.GetCVar(CCVars.VotekickVoterGhostRequirement) ? CalculateEligibleVoterNumber(VoterEligibility.GhostMinimumPlaytime) : CalculateEligibleVoterNumber(VoterEligibility.MinimumPlaytime);
|
var eligibleVoterNumber = CalculateEligibleVoterNumber(voterEligibility);
|
||||||
|
|
||||||
string target = args[0];
|
string target = args[0];
|
||||||
string reason = args[1];
|
string reason = args[1];
|
||||||
@@ -441,7 +448,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
},
|
},
|
||||||
Duration = TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VotekickTimer)),
|
Duration = TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VotekickTimer)),
|
||||||
InitiatorTimeout = TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.VotekickTimeout)),
|
InitiatorTimeout = TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.VotekickTimeout)),
|
||||||
VoterEligibility = _cfg.GetCVar(CCVars.VotekickVoterGhostRequirement) ? VoterEligibility.GhostMinimumPlaytime : VoterEligibility.MinimumPlaytime,
|
VoterEligibility = voterEligibility,
|
||||||
DisplayVotes = false,
|
DisplayVotes = false,
|
||||||
TargetEntity = targetNetEntity
|
TargetEntity = targetNetEntity
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Server.Voting.Managers
|
namespace Content.Server.Voting.Managers
|
||||||
{
|
{
|
||||||
public sealed partial class VoteManager : IVoteManager
|
public sealed partial class VoteManager : IVoteManager
|
||||||
@@ -40,7 +39,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
[Dependency] private readonly IGameMapManager _gameMapManager = default!;
|
[Dependency] private readonly IGameMapManager _gameMapManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
[Dependency] private readonly ISharedPlaytimeManager _playtimeManager = default!;
|
[Dependency] private readonly ISharedPlaytimeManager _playtimeManager = default!;
|
||||||
|
|
||||||
private int _nextVoteId = 1;
|
private int _nextVoteId = 1;
|
||||||
|
|
||||||
@@ -282,7 +281,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Admin always see the vote count, even if the vote is set to hide it.
|
// Admin always see the vote count, even if the vote is set to hide it.
|
||||||
if (_adminMgr.HasAdminFlag(player, AdminFlags.Moderator))
|
if (v.DisplayVotes || _adminMgr.HasAdminFlag(player, AdminFlags.Moderator))
|
||||||
{
|
{
|
||||||
msg.DisplayVotes = true;
|
msg.DisplayVotes = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Ghost;
|
using Content.Server.Ghost;
|
||||||
using Content.Server.Roles.Jobs;
|
using Content.Server.Roles.Jobs;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
@@ -12,6 +13,7 @@ using Robust.Shared.Network;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Content.Shared.Players.PlayTimeTracking;
|
||||||
|
|
||||||
namespace Content.Server.Voting;
|
namespace Content.Server.Voting;
|
||||||
|
|
||||||
@@ -24,6 +26,8 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly JobSystem _jobs = default!;
|
[Dependency] private readonly JobSystem _jobs = default!;
|
||||||
|
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||||
|
[Dependency] private readonly ISharedPlaytimeManager _playtimeManager = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -34,8 +38,7 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
|
|
||||||
private async void OnVotePlayerListRequestEvent(VotePlayerListRequestEvent msg, EntitySessionEventArgs args)
|
private async void OnVotePlayerListRequestEvent(VotePlayerListRequestEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.SenderSession.AttachedEntity is not { Valid: true } entity
|
if (!await CheckVotekickInitEligibility(args.SenderSession))
|
||||||
|| !await CheckVotekickInitEligibility(args.SenderSession))
|
|
||||||
{
|
{
|
||||||
var deniedResponse = new VotePlayerListResponseEvent(new (NetUserId, NetEntity, string)[0], true);
|
var deniedResponse = new VotePlayerListResponseEvent(new (NetUserId, NetEntity, string)[0], true);
|
||||||
RaiseNetworkEvent(deniedResponse, args.SenderSession.Channel);
|
RaiseNetworkEvent(deniedResponse, args.SenderSession.Channel);
|
||||||
@@ -46,17 +49,23 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
|
|
||||||
foreach (var player in _playerManager.Sessions)
|
foreach (var player in _playerManager.Sessions)
|
||||||
{
|
{
|
||||||
if (player.AttachedEntity is not { Valid: true } attached)
|
if (args.SenderSession == player) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (attached == entity) continue;
|
|
||||||
|
|
||||||
if (_adminManager.IsAdmin(player, false)) continue;
|
if (_adminManager.IsAdmin(player, false)) continue;
|
||||||
|
|
||||||
var playerName = GetPlayerVoteListName(attached);
|
if (player.AttachedEntity is not { Valid: true } attached)
|
||||||
var netEntity = GetNetEntity(attached);
|
{
|
||||||
|
var playerName = player.Name;
|
||||||
|
var netEntity = NetEntity.Invalid;
|
||||||
|
players.Add((player.UserId, netEntity, playerName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var playerName = GetPlayerVoteListName(attached);
|
||||||
|
var netEntity = GetNetEntity(attached);
|
||||||
|
|
||||||
players.Add((player.UserId, netEntity, playerName));
|
players.Add((player.UserId, netEntity, playerName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = new VotePlayerListResponseEvent(players.ToArray(), false);
|
var response = new VotePlayerListResponseEvent(players.ToArray(), false);
|
||||||
@@ -86,22 +95,29 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
if (initiator.AttachedEntity != null && _adminManager.IsAdmin(initiator.AttachedEntity.Value, false))
|
if (initiator.AttachedEntity != null && _adminManager.IsAdmin(initiator.AttachedEntity.Value, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (_cfg.GetCVar(CCVars.VotekickInitiatorGhostRequirement))
|
// If cvar enabled, skip the ghost requirement in the preround lobby
|
||||||
|
if (!_cfg.GetCVar(CCVars.VotekickIgnoreGhostReqInLobby) || (_cfg.GetCVar(CCVars.VotekickIgnoreGhostReqInLobby) && _gameTicker.RunLevel != GameRunLevel.PreRoundLobby))
|
||||||
{
|
{
|
||||||
// Must be ghost
|
if (_cfg.GetCVar(CCVars.VotekickInitiatorGhostRequirement))
|
||||||
if (!TryComp(initiator.AttachedEntity, out GhostComponent? ghostComp))
|
{
|
||||||
return false;
|
// Must be ghost
|
||||||
|
if (!TryComp(initiator.AttachedEntity, out GhostComponent? ghostComp))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Must have been dead for x seconds
|
// Must have been dead for x seconds
|
||||||
if ((int)_gameTiming.RealTime.Subtract(ghostComp.TimeOfDeath).TotalSeconds < _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime))
|
if ((int)_gameTiming.RealTime.Subtract(ghostComp.TimeOfDeath).TotalSeconds < _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be whitelisted
|
// Must be whitelisted
|
||||||
if (!await _dbManager.GetWhitelistStatusAsync(initiator.UserId))
|
if (!await _dbManager.GetWhitelistStatusAsync(initiator.UserId) && _cfg.GetCVar(CCVars.VotekickInitiatorWhitelistedRequirement))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
// Must be eligible to vote
|
||||||
|
var playtime = _playtimeManager.GetPlayTimes(initiator);
|
||||||
|
return playtime.TryGetValue(PlayTimeTrackingShared.TrackerOverall, out TimeSpan overallTime) && (overallTime >= TimeSpan.FromHours(_cfg.GetCVar(CCVars.VotekickEligibleVoterPlaytime))
|
||||||
|
|| !_cfg.GetCVar(CCVars.VotekickInitiatorTimeRequirement));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -461,6 +461,18 @@ namespace Content.Shared.CCVar
|
|||||||
* Discord
|
* Discord
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The role that will get mentioned if a new SOS ahelp comes in.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<string> DiscordAhelpMention =
|
||||||
|
CVarDef.Create("discord.on_call_ping", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL of the discord webhook to relay unanswered ahelp messages.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<string> DiscordOnCallWebhook =
|
||||||
|
CVarDef.Create("discord.on_call_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// URL of the Discord webhook which will relay all ahelp messages.
|
/// URL of the Discord webhook which will relay all ahelp messages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1472,7 +1484,7 @@ namespace Content.Shared.CCVar
|
|||||||
/// Config for when the votekick should be allowed to be called based on number of eligible voters.
|
/// Config for when the votekick should be allowed to be called based on number of eligible voters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<int> VotekickEligibleNumberRequirement =
|
public static readonly CVarDef<int> VotekickEligibleNumberRequirement =
|
||||||
CVarDef.Create("votekick.eligible_number", 10, CVar.SERVERONLY);
|
CVarDef.Create("votekick.eligible_number", 5, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a votekick initiator must be a ghost or not.
|
/// Whether a votekick initiator must be a ghost or not.
|
||||||
@@ -1480,6 +1492,18 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool> VotekickInitiatorGhostRequirement =
|
public static readonly CVarDef<bool> VotekickInitiatorGhostRequirement =
|
||||||
CVarDef.Create("votekick.initiator_ghost_requirement", true, CVar.SERVERONLY);
|
CVarDef.Create("votekick.initiator_ghost_requirement", true, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the initiator be whitelisted to initiate a votekick?
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<bool> VotekickInitiatorWhitelistedRequirement =
|
||||||
|
CVarDef.Create("votekick.initiator_whitelist_requirement", true, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the initiator be able to start a votekick if they are bellow the votekick.voter_playtime requirement?
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<bool> VotekickInitiatorTimeRequirement =
|
||||||
|
CVarDef.Create("votekick.initiator_time_requirement", false, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a votekick voter must be a ghost or not.
|
/// Whether a votekick voter must be a ghost or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1496,7 +1520,7 @@ namespace Content.Shared.CCVar
|
|||||||
/// Config for how many seconds a player must have been dead to initiate a votekick / be able to vote on a votekick.
|
/// Config for how many seconds a player must have been dead to initiate a votekick / be able to vote on a votekick.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<int> VotekickEligibleVoterDeathtime =
|
public static readonly CVarDef<int> VotekickEligibleVoterDeathtime =
|
||||||
CVarDef.Create("votekick.voter_deathtime", 180, CVar.REPLICATED | CVar.SERVER);
|
CVarDef.Create("votekick.voter_deathtime", 30, CVar.REPLICATED | CVar.SERVER);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The required ratio of eligible voters that must agree for a votekick to go through.
|
/// The required ratio of eligible voters that must agree for a votekick to go through.
|
||||||
@@ -1540,6 +1564,12 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<int> VotekickBanDuration =
|
public static readonly CVarDef<int> VotekickBanDuration =
|
||||||
CVarDef.Create("votekick.ban_duration", 180, CVar.SERVERONLY);
|
CVarDef.Create("votekick.ban_duration", 180, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the ghost requirement settings for votekicks should be ignored for the lobby.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<bool> VotekickIgnoreGhostReqInLobby =
|
||||||
|
CVarDef.Create("votekick.ignore_ghost_req_in_lobby", true, CVar.SERVERONLY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BAN
|
* BAN
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public sealed partial class CartridgeLoaderComponent : Component
|
|||||||
/// The maximum amount of programs that can be installed on the cartridge loader entity
|
/// The maximum amount of programs that can be installed on the cartridge loader entity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public int DiskSpace = 5;
|
public int DiskSpace = 8;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls whether the cartridge loader will play notifications if it supports it at all
|
/// Controls whether the cartridge loader will play notifications if it supports it at all
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace Content.Shared.Chemistry.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a container that also contains a solution.
|
||||||
|
/// This means that reactive entities react when inserted into the container.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class ReactiveContainerComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The container that holds the solution.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string Container = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The solution in the container.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public string Solution = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reaction;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
|
namespace Content.Shared.Chemistry.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class ReactiveContainerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
|
||||||
|
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ReactiveContainerComponent, EntInsertedIntoContainerMessage>(OnInserted);
|
||||||
|
SubscribeLocalEvent<ReactiveContainerComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInserted(EntityUid uid, ReactiveContainerComponent comp, EntInsertedIntoContainerMessage args)
|
||||||
|
{
|
||||||
|
// Only reactive entities can react with the solution
|
||||||
|
if (!HasComp<ReactiveComponent>(args.Entity))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_solutionContainerSystem.TryGetSolution(uid, comp.Solution, out _, out var solution))
|
||||||
|
return;
|
||||||
|
if (solution.Volume == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_reactiveSystem.DoEntityReaction(args.Entity, solution, ReactionMethod.Touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSolutionChange(EntityUid uid, ReactiveContainerComponent comp, SolutionContainerChangedEvent args)
|
||||||
|
{
|
||||||
|
if (!_solutionContainerSystem.TryGetSolution(uid, comp.Solution, out _, out var solution))
|
||||||
|
return;
|
||||||
|
if (solution.Volume == 0)
|
||||||
|
return;
|
||||||
|
if (!TryComp<ContainerManagerComponent>(uid, out var manager))
|
||||||
|
return;
|
||||||
|
if (!_containerSystem.TryGetContainer(uid, comp.Container, out var container))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var entity in container.ContainedEntities)
|
||||||
|
{
|
||||||
|
if (!HasComp<ReactiveComponent>(entity))
|
||||||
|
continue;
|
||||||
|
_reactiveSystem.DoEntityReaction(entity, solution, ReactionMethod.Touch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region ComponentManagement
|
#region ComponentManagement
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spawn in starting items for any item slots that should have one.
|
/// Spawn in starting items for any item slots that should have one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -70,7 +71,8 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (slot.HasItem || string.IsNullOrEmpty(slot.StartingItem))
|
if (slot.HasItem || string.IsNullOrEmpty(slot.StartingItem))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = EntityManager.SpawnEntity(slot.StartingItem, EntityManager.GetComponent<TransformComponent>(uid).Coordinates);
|
var item = Spawn(slot.StartingItem, Transform(uid).Coordinates);
|
||||||
|
|
||||||
if (slot.ContainerSlot != null)
|
if (slot.ContainerSlot != null)
|
||||||
_containers.Insert(item, slot.ContainerSlot);
|
_containers.Insert(item, slot.ContainerSlot);
|
||||||
}
|
}
|
||||||
@@ -99,7 +101,8 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (itemSlots.Slots.TryGetValue(id, out var existing))
|
if (itemSlots.Slots.TryGetValue(id, out var existing))
|
||||||
{
|
{
|
||||||
if (existing.Local)
|
if (existing.Local)
|
||||||
Log.Error($"Duplicate item slot key. Entity: {EntityManager.GetComponent<MetaDataComponent>(uid).EntityName} ({uid}), key: {id}");
|
Log.Error(
|
||||||
|
$"Duplicate item slot key. Entity: {EntityManager.GetComponent<MetaDataComponent>(uid).EntityName} ({uid}), key: {id}");
|
||||||
else
|
else
|
||||||
// server state takes priority
|
// server state takes priority
|
||||||
slot.CopyFrom(existing);
|
slot.CopyFrom(existing);
|
||||||
@@ -134,7 +137,10 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
Dirty(uid, itemSlots);
|
Dirty(uid, itemSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetSlot(EntityUid uid, string slotId, [NotNullWhen(true)] out ItemSlot? itemSlot, ItemSlotsComponent? component = null)
|
public bool TryGetSlot(EntityUid uid,
|
||||||
|
string slotId,
|
||||||
|
[NotNullWhen(true)] out ItemSlot? itemSlot,
|
||||||
|
ItemSlotsComponent? component = null)
|
||||||
{
|
{
|
||||||
itemSlot = null;
|
itemSlot = null;
|
||||||
|
|
||||||
@@ -143,9 +149,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
|
|
||||||
return component.Slots.TryGetValue(slotId, out itemSlot);
|
return component.Slots.TryGetValue(slotId, out itemSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Interactions
|
#region Interactions
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempt to take an item from a slot, if any are set to EjectOnInteract.
|
/// Attempt to take an item from a slot, if any are set to EjectOnInteract.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -201,20 +209,50 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (itemSlots.Slots.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If any slot can be inserted into don't show popup.
|
||||||
|
// If any whitelist passes, but slot is locked, then show locked.
|
||||||
|
// If whitelist fails all, show whitelist fail.
|
||||||
|
|
||||||
|
// valid, insertable slots (if any)
|
||||||
var slots = new List<ItemSlot>();
|
var slots = new List<ItemSlot>();
|
||||||
|
|
||||||
|
string? whitelistFailPopup = null;
|
||||||
|
string? lockedFailPopup = null;
|
||||||
foreach (var slot in itemSlots.Slots.Values)
|
foreach (var slot in itemSlots.Slots.Values)
|
||||||
{
|
{
|
||||||
if (!slot.InsertOnInteract)
|
if (!slot.InsertOnInteract)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!CanInsert(uid, args.Used, args.User, slot, swap: slot.Swap, popup: args.User))
|
if (CanInsert(uid, args.Used, args.User, slot, slot.Swap))
|
||||||
continue;
|
{
|
||||||
|
slots.Add(slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var allowed = CanInsertWhitelist(args.Used, slot);
|
||||||
|
if (lockedFailPopup == null && slot.LockedFailPopup != null && allowed && slot.Locked)
|
||||||
|
lockedFailPopup = slot.LockedFailPopup;
|
||||||
|
|
||||||
slots.Add(slot);
|
if (whitelistFailPopup == null && slot.WhitelistFailPopup != null)
|
||||||
|
whitelistFailPopup = slot.WhitelistFailPopup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slots.Count == 0)
|
if (slots.Count == 0)
|
||||||
|
{
|
||||||
|
// it's a bit weird that the popupMessage is stored with the item slots themselves, but in practice
|
||||||
|
// the popup messages will just all be the same, so it's probably fine.
|
||||||
|
//
|
||||||
|
// doing a check to make sure that they're all the same or something is probably frivolous
|
||||||
|
if (lockedFailPopup != null)
|
||||||
|
_popupSystem.PopupClient(Loc.GetString(lockedFailPopup), uid, args.User);
|
||||||
|
else if (whitelistFailPopup != null)
|
||||||
|
_popupSystem.PopupClient(Loc.GetString(whitelistFailPopup), uid, args.User);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Drop the held item onto the floor. Return if the user cannot drop.
|
// Drop the held item onto the floor. Return if the user cannot drop.
|
||||||
if (!_handsSystem.TryDrop(args.User, args.Used, handsComp: hands))
|
if (!_handsSystem.TryDrop(args.User, args.Used, handsComp: hands))
|
||||||
@@ -236,23 +274,31 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Insert
|
#region Insert
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Insert an item into a slot. This does not perform checks, so make sure to also use <see
|
/// Insert an item into a slot. This does not perform checks, so make sure to also use <see
|
||||||
/// cref="CanInsert"/> or just use <see cref="TryInsert"/> instead.
|
/// cref="CanInsert"/> or just use <see cref="TryInsert"/> instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="excludeUserAudio">If true, will exclude the user when playing sound. Does nothing client-side.
|
/// <param name="excludeUserAudio">If true, will exclude the user when playing sound. Does nothing client-side.
|
||||||
/// Useful for predicted interactions</param>
|
/// Useful for predicted interactions</param>
|
||||||
private void Insert(EntityUid uid, ItemSlot slot, EntityUid item, EntityUid? user, bool excludeUserAudio = false)
|
private void Insert(EntityUid uid,
|
||||||
|
ItemSlot slot,
|
||||||
|
EntityUid item,
|
||||||
|
EntityUid? user,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
bool? inserted = slot.ContainerSlot != null ? _containers.Insert(item, slot.ContainerSlot) : null;
|
bool? inserted = slot.ContainerSlot != null ? _containers.Insert(item, slot.ContainerSlot) : null;
|
||||||
// ContainerSlot automatically raises a directed EntInsertedIntoContainerMessage
|
// ContainerSlot automatically raises a directed EntInsertedIntoContainerMessage
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
if (inserted != null && inserted.Value && user != null)
|
if (inserted != null && inserted.Value && user != null)
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user.Value)} inserted {ToPrettyString(item)} into {slot.ContainerSlot?.ID + " slot of "}{ToPrettyString(uid)}");
|
_adminLogger.Add(LogType.Action,
|
||||||
|
LogImpact.Low,
|
||||||
|
$"{ToPrettyString(user.Value)} inserted {ToPrettyString(item)} into {slot.ContainerSlot?.ID + " slot of "}{ToPrettyString(uid)}");
|
||||||
|
|
||||||
_audioSystem.PlayPredicted(slot.InsertSound, uid, excludeUserAudio ? user : null);
|
_audioSystem.PlayPredicted(slot.InsertSound, uid, excludeUserAudio ? user : null);
|
||||||
}
|
}
|
||||||
@@ -261,46 +307,53 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// Check whether a given item can be inserted into a slot. Unless otherwise specified, this will return
|
/// Check whether a given item can be inserted into a slot. Unless otherwise specified, this will return
|
||||||
/// false if the slot is already filled.
|
/// false if the slot is already filled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
public bool CanInsert(EntityUid uid,
|
||||||
/// If a popup entity is given, and if the item slot is set to generate a popup message when it fails to
|
EntityUid usedUid,
|
||||||
/// pass the whitelist or due to slot being locked, then this will generate an appropriate popup.
|
EntityUid? user,
|
||||||
/// </remarks>
|
ItemSlot slot,
|
||||||
public bool CanInsert(EntityUid uid, EntityUid usedUid, EntityUid? user, ItemSlot slot, bool swap = false, EntityUid? popup = null)
|
bool swap = false)
|
||||||
{
|
{
|
||||||
if (slot.ContainerSlot == null)
|
if (slot.ContainerSlot == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_whitelistSystem.IsWhitelistFail(slot.Whitelist, usedUid) || _whitelistSystem.IsBlacklistPass(slot.Blacklist, usedUid))
|
if (slot.HasItem && (!swap || swap && !CanEject(uid, user, slot)))
|
||||||
{
|
return false;
|
||||||
if (popup.HasValue && slot.WhitelistFailPopup.HasValue)
|
|
||||||
_popupSystem.PopupClient(Loc.GetString(slot.WhitelistFailPopup), uid, popup.Value);
|
if (!CanInsertWhitelist(usedUid, slot))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (slot.Locked)
|
if (slot.Locked)
|
||||||
{
|
|
||||||
if (popup.HasValue && slot.LockedFailPopup.HasValue)
|
|
||||||
_popupSystem.PopupClient(Loc.GetString(slot.LockedFailPopup), uid, popup.Value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot.HasItem && (!swap || (swap && !CanEject(uid, user, slot))))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ev = new ItemSlotInsertAttemptEvent(uid, usedUid, user, slot);
|
var ev = new ItemSlotInsertAttemptEvent(uid, usedUid, user, slot);
|
||||||
RaiseLocalEvent(uid, ref ev);
|
RaiseLocalEvent(uid, ref ev);
|
||||||
RaiseLocalEvent(usedUid, ref ev);
|
RaiseLocalEvent(usedUid, ref ev);
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _containers.CanInsert(usedUid, slot.ContainerSlot, assumeEmpty: swap);
|
return _containers.CanInsert(usedUid, slot.ContainerSlot, assumeEmpty: swap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanInsertWhitelist(EntityUid usedUid, ItemSlot slot)
|
||||||
|
{
|
||||||
|
if (_whitelistSystem.IsWhitelistFail(slot.Whitelist, usedUid)
|
||||||
|
|| _whitelistSystem.IsBlacklistPass(slot.Blacklist, usedUid))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to insert item into a specific slot.
|
/// Tries to insert item into a specific slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False if failed to insert item</returns>
|
/// <returns>False if failed to insert item</returns>
|
||||||
public bool TryInsert(EntityUid uid, string id, EntityUid item, EntityUid? user, ItemSlotsComponent? itemSlots = null, bool excludeUserAudio = false)
|
public bool TryInsert(EntityUid uid,
|
||||||
|
string id,
|
||||||
|
EntityUid item,
|
||||||
|
EntityUid? user,
|
||||||
|
ItemSlotsComponent? itemSlots = null,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref itemSlots))
|
if (!Resolve(uid, ref itemSlots))
|
||||||
return false;
|
return false;
|
||||||
@@ -315,7 +368,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// Tries to insert item into a specific slot.
|
/// Tries to insert item into a specific slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False if failed to insert item</returns>
|
/// <returns>False if failed to insert item</returns>
|
||||||
public bool TryInsert(EntityUid uid, ItemSlot slot, EntityUid item, EntityUid? user, bool excludeUserAudio = false)
|
public bool TryInsert(EntityUid uid,
|
||||||
|
ItemSlot slot,
|
||||||
|
EntityUid item,
|
||||||
|
EntityUid? user,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
if (!CanInsert(uid, item, user, slot))
|
if (!CanInsert(uid, item, user, slot))
|
||||||
return false;
|
return false;
|
||||||
@@ -329,7 +386,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// Does not check action blockers.
|
/// Does not check action blockers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False if failed to insert item</returns>
|
/// <returns>False if failed to insert item</returns>
|
||||||
public bool TryInsertFromHand(EntityUid uid, ItemSlot slot, EntityUid user, HandsComponent? hands = null, bool excludeUserAudio = false)
|
public bool TryInsertFromHand(EntityUid uid,
|
||||||
|
ItemSlot slot,
|
||||||
|
EntityUid user,
|
||||||
|
HandsComponent? hands = null,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(user, ref hands, false))
|
if (!Resolve(user, ref hands, false))
|
||||||
return false;
|
return false;
|
||||||
@@ -443,6 +504,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Eject
|
#region Eject
|
||||||
@@ -462,7 +524,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot.ContainerSlot?.ContainedEntity is not {} item)
|
if (slot.ContainerSlot?.ContainedEntity is not { } item)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ev = new ItemSlotEjectAttemptEvent(uid, item, user, slot);
|
var ev = new ItemSlotEjectAttemptEvent(uid, item, user, slot);
|
||||||
@@ -487,7 +549,9 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
if (ejected != null && ejected.Value && user != null)
|
if (ejected != null && ejected.Value && user != null)
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user.Value)} ejected {ToPrettyString(item)} from {slot.ContainerSlot?.ID + " slot of "}{ToPrettyString(uid)}");
|
_adminLogger.Add(LogType.Action,
|
||||||
|
LogImpact.Low,
|
||||||
|
$"{ToPrettyString(user.Value)} ejected {ToPrettyString(item)} from {slot.ContainerSlot?.ID + " slot of "}{ToPrettyString(uid)}");
|
||||||
|
|
||||||
_audioSystem.PlayPredicted(slot.EjectSound, uid, excludeUserAudio ? user : null);
|
_audioSystem.PlayPredicted(slot.EjectSound, uid, excludeUserAudio ? user : null);
|
||||||
}
|
}
|
||||||
@@ -496,7 +560,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// Try to eject an item from a slot.
|
/// Try to eject an item from a slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False if item slot is locked or has no item inserted</returns>
|
/// <returns>False if item slot is locked or has no item inserted</returns>
|
||||||
public bool TryEject(EntityUid uid, ItemSlot slot, EntityUid? user, [NotNullWhen(true)] out EntityUid? item, bool excludeUserAudio = false)
|
public bool TryEject(EntityUid uid,
|
||||||
|
ItemSlot slot,
|
||||||
|
EntityUid? user,
|
||||||
|
[NotNullWhen(true)] out EntityUid? item,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
item = null;
|
item = null;
|
||||||
|
|
||||||
@@ -518,8 +586,12 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// Try to eject item from a slot.
|
/// Try to eject item from a slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False if the id is not valid, the item slot is locked, or it has no item inserted</returns>
|
/// <returns>False if the id is not valid, the item slot is locked, or it has no item inserted</returns>
|
||||||
public bool TryEject(EntityUid uid, string id, EntityUid? user,
|
public bool TryEject(EntityUid uid,
|
||||||
[NotNullWhen(true)] out EntityUid? item, ItemSlotsComponent? itemSlots = null, bool excludeUserAudio = false)
|
string id,
|
||||||
|
EntityUid? user,
|
||||||
|
[NotNullWhen(true)] out EntityUid? item,
|
||||||
|
ItemSlotsComponent? itemSlots = null,
|
||||||
|
bool excludeUserAudio = false)
|
||||||
{
|
{
|
||||||
item = null;
|
item = null;
|
||||||
|
|
||||||
@@ -550,12 +622,16 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Verbs
|
#region Verbs
|
||||||
private void AddAlternativeVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent<AlternativeVerb> args)
|
|
||||||
|
private void AddAlternativeVerbs(EntityUid uid,
|
||||||
|
ItemSlotsComponent itemSlots,
|
||||||
|
GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (args.Hands == null || !args.CanAccess ||!args.CanInteract)
|
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -649,7 +725,9 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddInteractionVerbsVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent<InteractionVerb> args)
|
private void AddInteractionVerbsVerbs(EntityUid uid,
|
||||||
|
ItemSlotsComponent itemSlots,
|
||||||
|
GetVerbsEvent<InteractionVerb> args)
|
||||||
{
|
{
|
||||||
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
||||||
return;
|
return;
|
||||||
@@ -708,7 +786,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
new SpriteSpecifier.Texture(
|
new SpriteSpecifier.Texture(
|
||||||
new ResPath("/Textures/Interface/VerbIcons/insert.svg.192dpi.png"));
|
new ResPath("/Textures/Interface/VerbIcons/insert.svg.192dpi.png"));
|
||||||
}
|
}
|
||||||
else if(slot.EjectOnInteract)
|
else if (slot.EjectOnInteract)
|
||||||
{
|
{
|
||||||
// Inserting/ejecting is a primary interaction for this entity. Instead of using the insert
|
// Inserting/ejecting is a primary interaction for this entity. Instead of using the insert
|
||||||
// category, we will use a single "Place <item>" verb.
|
// category, we will use a single "Place <item>" verb.
|
||||||
@@ -727,9 +805,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
args.Verbs.Add(insertVerb);
|
args.Verbs.Add(insertVerb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BUIs
|
#region BUIs
|
||||||
|
|
||||||
private void HandleButtonPressed(EntityUid uid, ItemSlotsComponent component, ItemSlotButtonPressedEvent args)
|
private void HandleButtonPressed(EntityUid uid, ItemSlotsComponent component, ItemSlotButtonPressedEvent args)
|
||||||
{
|
{
|
||||||
if (!component.Slots.TryGetValue(args.SlotId, out var slot))
|
if (!component.Slots.TryGetValue(args.SlotId, out var slot))
|
||||||
@@ -740,6 +820,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
else if (args.TryInsert && !slot.HasItem)
|
else if (args.TryInsert && !slot.HasItem)
|
||||||
TryInsertFromHand(uid, slot, args.Actor);
|
TryInsertFromHand(uid, slot, args.Actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public abstract partial class InventorySystem
|
|||||||
|
|
||||||
private void OnEntRemoved(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args)
|
private void OnEntRemoved(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args)
|
||||||
{
|
{
|
||||||
if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))
|
if (!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var unequippedEvent = new DidUnequipEvent(uid, args.Entity, slotDef);
|
var unequippedEvent = new DidUnequipEvent(uid, args.Entity, slotDef);
|
||||||
@@ -59,8 +59,8 @@ public abstract partial class InventorySystem
|
|||||||
|
|
||||||
private void OnEntInserted(EntityUid uid, InventoryComponent component, EntInsertedIntoContainerMessage args)
|
private void OnEntInserted(EntityUid uid, InventoryComponent component, EntInsertedIntoContainerMessage args)
|
||||||
{
|
{
|
||||||
if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))
|
if (!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var equippedEvent = new DidEquipEvent(uid, args.Entity, slotDef);
|
var equippedEvent = new DidEquipEvent(uid, args.Entity, slotDef);
|
||||||
RaiseLocalEvent(uid, equippedEvent, true);
|
RaiseLocalEvent(uid, equippedEvent, true);
|
||||||
@@ -118,7 +118,7 @@ public abstract partial class InventorySystem
|
|||||||
|
|
||||||
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor));
|
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor));
|
||||||
|
|
||||||
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter:true);
|
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false,
|
public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false,
|
||||||
@@ -365,6 +365,25 @@ public abstract partial class InventorySystem
|
|||||||
ClothingComponent? clothing = null,
|
ClothingComponent? clothing = null,
|
||||||
bool reparent = true,
|
bool reparent = true,
|
||||||
bool checkDoafter = false)
|
bool checkDoafter = false)
|
||||||
|
{
|
||||||
|
var itemsDropped = 0;
|
||||||
|
return TryUnequip(actor, target, slot, out removedItem, ref itemsDropped,
|
||||||
|
silent, force, predicted, inventory, clothing, reparent, checkDoafter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryUnequip(
|
||||||
|
EntityUid actor,
|
||||||
|
EntityUid target,
|
||||||
|
string slot,
|
||||||
|
[NotNullWhen(true)] out EntityUid? removedItem,
|
||||||
|
ref int itemsDropped,
|
||||||
|
bool silent = false,
|
||||||
|
bool force = false,
|
||||||
|
bool predicted = false,
|
||||||
|
InventoryComponent? inventory = null,
|
||||||
|
ClothingComponent? clothing = null,
|
||||||
|
bool reparent = true,
|
||||||
|
bool checkDoafter = false)
|
||||||
{
|
{
|
||||||
removedItem = null;
|
removedItem = null;
|
||||||
|
|
||||||
@@ -423,17 +442,27 @@ public abstract partial class InventorySystem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_containerSystem.Remove(removedItem.Value, slotContainer, force: force, reparent: reparent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// this is in order to keep track of whether this is the first instance of a recursion call
|
||||||
|
var firstRun = itemsDropped == 0;
|
||||||
|
++itemsDropped;
|
||||||
|
|
||||||
foreach (var slotDef in inventory.Slots)
|
foreach (var slotDef in inventory.Slots)
|
||||||
{
|
{
|
||||||
if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name)
|
if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name)
|
||||||
{
|
{
|
||||||
//this recursive call might be risky
|
//this recursive call might be risky
|
||||||
TryUnequip(actor, target, slotDef.Name, true, true, predicted, inventory, reparent: reparent);
|
TryUnequip(actor, target, slotDef.Name, out _, ref itemsDropped, true, true, predicted, inventory, reparent: reparent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_containerSystem.Remove(removedItem.Value, slotContainer, force: force, reparent: reparent))
|
// we check if any items were dropped, and make a popup if they were.
|
||||||
return false;
|
// the reason we check for > 1 is because the first item is always the one we are trying to unequip,
|
||||||
|
// whereas we only want to notify for extra dropped items.
|
||||||
|
if (!silent && _gameTiming.IsFirstTimePredicted && firstRun && itemsDropped > 1)
|
||||||
|
_popup.PopupClient(Loc.GetString("inventory-component-dropped-from-unequip", ("items", itemsDropped - 1)), target, target);
|
||||||
|
|
||||||
// TODO: Inventory needs a hot cleanup hoo boy
|
// TODO: Inventory needs a hot cleanup hoo boy
|
||||||
// Check if something else (AKA toggleable) dumped it into a container.
|
// Check if something else (AKA toggleable) dumped it into a container.
|
||||||
@@ -466,7 +495,7 @@ public abstract partial class InventorySystem
|
|||||||
if ((containerSlot == null || slotDefinition == null) && !TryGetSlotContainer(target, slot, out containerSlot, out slotDefinition, inventory))
|
if ((containerSlot == null || slotDefinition == null) && !TryGetSlotContainer(target, slot, out containerSlot, out slotDefinition, inventory))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (containerSlot.ContainedEntity is not {} itemUid)
|
if (containerSlot.ContainedEntity is not { } itemUid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_containerSystem.CanRemove(itemUid, containerSlot))
|
if (!_containerSystem.CanRemove(itemUid, containerSlot))
|
||||||
|
|||||||
@@ -81,6 +81,24 @@ public sealed partial class NpcFactionSystem : EntitySystem
|
|||||||
return ent.Comp.Factions.Contains(faction);
|
return ent.Comp.Factions.Contains(faction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether an entity is a member of any listed faction.
|
||||||
|
/// If the list is empty this returns false.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMemberOfAny(Entity<NpcFactionMemberComponent?> ent, IEnumerable<ProtoId<NpcFactionPrototype>> factions)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var faction in factions)
|
||||||
|
{
|
||||||
|
if (ent.Comp.Factions.Contains(faction))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds this entity to the particular faction.
|
/// Adds this entity to the particular faction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -33,18 +33,10 @@ public sealed class HungerSystem : EntitySystem
|
|||||||
[ValidatePrototypeId<SatiationIconPrototype>]
|
[ValidatePrototypeId<SatiationIconPrototype>]
|
||||||
private const string HungerIconStarvingId = "HungerIconStarving";
|
private const string HungerIconStarvingId = "HungerIconStarving";
|
||||||
|
|
||||||
private SatiationIconPrototype? _hungerIconOverfed;
|
|
||||||
private SatiationIconPrototype? _hungerIconPeckish;
|
|
||||||
private SatiationIconPrototype? _hungerIconStarving;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
DebugTools.Assert(_prototype.TryIndex(HungerIconOverfedId, out _hungerIconOverfed) &&
|
|
||||||
_prototype.TryIndex(HungerIconPeckishId, out _hungerIconPeckish) &&
|
|
||||||
_prototype.TryIndex(HungerIconStarvingId, out _hungerIconStarving));
|
|
||||||
|
|
||||||
SubscribeLocalEvent<HungerComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<HungerComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<HungerComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<HungerComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<HungerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
SubscribeLocalEvent<HungerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||||
@@ -221,13 +213,13 @@ public sealed class HungerSystem : EntitySystem
|
|||||||
switch (component.CurrentThreshold)
|
switch (component.CurrentThreshold)
|
||||||
{
|
{
|
||||||
case HungerThreshold.Overfed:
|
case HungerThreshold.Overfed:
|
||||||
prototype = _hungerIconOverfed;
|
_prototype.TryIndex(HungerIconOverfedId, out prototype);
|
||||||
break;
|
break;
|
||||||
case HungerThreshold.Peckish:
|
case HungerThreshold.Peckish:
|
||||||
prototype = _hungerIconPeckish;
|
_prototype.TryIndex(HungerIconPeckishId, out prototype);
|
||||||
break;
|
break;
|
||||||
case HungerThreshold.Starving:
|
case HungerThreshold.Starving:
|
||||||
prototype = _hungerIconStarving;
|
_prototype.TryIndex(HungerIconStarvingId, out prototype);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
prototype = null;
|
prototype = null;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Content.Shared.Nutrition.EntitySystems;
|
namespace Content.Shared.Nutrition.EntitySystems;
|
||||||
|
|
||||||
@@ -31,18 +32,10 @@ public sealed class ThirstSystem : EntitySystem
|
|||||||
[ValidatePrototypeId<SatiationIconPrototype>]
|
[ValidatePrototypeId<SatiationIconPrototype>]
|
||||||
private const string ThirstIconParchedId = "ThirstIconParched";
|
private const string ThirstIconParchedId = "ThirstIconParched";
|
||||||
|
|
||||||
private SatiationIconPrototype? _thirstIconOverhydrated = null;
|
|
||||||
private SatiationIconPrototype? _thirstIconThirsty = null;
|
|
||||||
private SatiationIconPrototype? _thirstIconParched = null;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
DebugTools.Assert(_prototype.TryIndex(ThirstIconOverhydratedId, out _thirstIconOverhydrated) &&
|
|
||||||
_prototype.TryIndex(ThirstIconThirstyId, out _thirstIconThirsty) &&
|
|
||||||
_prototype.TryIndex(ThirstIconParchedId, out _thirstIconParched));
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||||
SubscribeLocalEvent<ThirstComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<ThirstComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
@@ -128,26 +121,28 @@ public sealed class ThirstSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetStatusIconPrototype(ThirstComponent component, out SatiationIconPrototype? prototype)
|
public bool TryGetStatusIconPrototype(ThirstComponent component, [NotNullWhen(true)] out SatiationIconPrototype? prototype)
|
||||||
{
|
{
|
||||||
switch (component.CurrentThirstThreshold)
|
switch (component.CurrentThirstThreshold)
|
||||||
{
|
{
|
||||||
case ThirstThreshold.OverHydrated:
|
case ThirstThreshold.OverHydrated:
|
||||||
prototype = _thirstIconOverhydrated;
|
_prototype.TryIndex(ThirstIconOverhydratedId, out prototype);
|
||||||
return true;
|
break;
|
||||||
|
|
||||||
case ThirstThreshold.Thirsty:
|
case ThirstThreshold.Thirsty:
|
||||||
prototype = _thirstIconThirsty;
|
_prototype.TryIndex(ThirstIconThirstyId, out prototype);
|
||||||
return true;
|
break;
|
||||||
|
|
||||||
case ThirstThreshold.Parched:
|
case ThirstThreshold.Parched:
|
||||||
prototype = _thirstIconParched;
|
_prototype.TryIndex(ThirstIconParchedId, out prototype);
|
||||||
return true;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
prototype = null;
|
prototype = null;
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return prototype != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateEffects(EntityUid uid, ThirstComponent component)
|
private void UpdateEffects(EntityUid uid, ThirstComponent component)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Content.Shared.Damage.Prototypes;
|
|||||||
using Content.Shared.StatusIcon;
|
using Content.Shared.StatusIcon;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
|
||||||
|
|
||||||
namespace Content.Shared.Overlays;
|
namespace Content.Shared.Overlays;
|
||||||
|
|
||||||
@@ -15,8 +14,11 @@ public sealed partial class ShowHealthBarsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays health bars of the damage containers.
|
/// Displays health bars of the damage containers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageContainerPrototype>))]
|
[DataField]
|
||||||
public List<string> DamageContainers = new();
|
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
|
||||||
|
{
|
||||||
|
"Biological"
|
||||||
|
};
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public ProtoId<HealthIconPrototype>? HealthStatusIcon = "HealthIconFine";
|
public ProtoId<HealthIconPrototype>? HealthStatusIcon = "HealthIconFine";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.Overlays;
|
namespace Content.Shared.Overlays;
|
||||||
|
|
||||||
@@ -13,6 +13,9 @@ public sealed partial class ShowHealthIconsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays health status icons of the damage containers.
|
/// Displays health status icons of the damage containers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageContainerPrototype>))]
|
[DataField]
|
||||||
public List<string> DamageContainers = new();
|
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
|
||||||
|
{
|
||||||
|
"Biological"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed partial class SiliconLawProviderComponent : Component
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sound that plays for the Silicon player
|
/// The sound that plays for the Silicon player
|
||||||
/// when the particular lawboard has been inserted.
|
/// when the law change is processed for the provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public SoundSpecifier? LawUploadSound = new SoundPathSpecifier("/Audio/Misc/cryo_warning.ogg");
|
public SoundSpecifier? LawUploadSound = new SoundPathSpecifier("/Audio/Misc/cryo_warning.ogg");
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
|
|
||||||
if (TryComp(user, out EyeComponent? eyeComp))
|
if (TryComp(user, out EyeComponent? eyeComp))
|
||||||
{
|
{
|
||||||
|
_eye.SetDrawFov(user, false, eyeComp);
|
||||||
_eye.SetTarget(user, ent.Comp.RemoteEntity.Value, eyeComp);
|
_eye.SetTarget(user, ent.Comp.RemoteEntity.Value, eyeComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +357,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
|
|
||||||
if (TryComp(args.Entity, out EyeComponent? eyeComp))
|
if (TryComp(args.Entity, out EyeComponent? eyeComp))
|
||||||
{
|
{
|
||||||
|
_eye.SetDrawFov(args.Entity, true, eyeComp);
|
||||||
_eye.SetTarget(args.Entity, null, eyeComp);
|
_eye.SetTarget(args.Entity, null, eyeComp);
|
||||||
}
|
}
|
||||||
ClearEye(ent);
|
ClearEye(ent);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Shared.Examine;
|
|||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Inventory.VirtualItem;
|
using Content.Shared.Inventory.VirtualItem;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
@@ -125,7 +126,7 @@ public sealed class WieldableSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args)
|
private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (HasComp<GunRequiresWieldComponent>(uid))
|
if (HasComp<GunRequiresWieldComponent>(uid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (component.WieldBonusExamineMessage != null)
|
if (component.WieldBonusExamineMessage != null)
|
||||||
@@ -253,7 +254,7 @@ public sealed class WieldableSystem : EntitySystem
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var selfMessage = Loc.GetString("wieldable-component-successful-wield", ("item", used));
|
var selfMessage = Loc.GetString("wieldable-component-successful-wield", ("item", used));
|
||||||
var othersMessage = Loc.GetString("wieldable-component-successful-wield-other", ("user", user), ("item", used));
|
var othersMessage = Loc.GetString("wieldable-component-successful-wield-other", ("user", Identity.Entity(user, EntityManager)), ("item", used));
|
||||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
|
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
|
||||||
|
|
||||||
var targEv = new ItemWieldedEvent();
|
var targEv = new ItemWieldedEvent();
|
||||||
@@ -298,7 +299,7 @@ public sealed class WieldableSystem : EntitySystem
|
|||||||
_audioSystem.PlayPredicted(component.UnwieldSound, uid, args.User);
|
_audioSystem.PlayPredicted(component.UnwieldSound, uid, args.User);
|
||||||
|
|
||||||
var selfMessage = Loc.GetString("wieldable-component-failed-wield", ("item", uid));
|
var selfMessage = Loc.GetString("wieldable-component-failed-wield", ("item", uid));
|
||||||
var othersMessage = Loc.GetString("wieldable-component-failed-wield-other", ("user", args.User.Value), ("item", uid));
|
var othersMessage = Loc.GetString("wieldable-component-failed-wield-other", ("user", Identity.Entity(args.User.Value, EntityManager)), ("item", uid));
|
||||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, args.User.Value, args.User.Value);
|
_popupSystem.PopupPredicted(selfMessage, othersMessage, args.User.Value, args.User.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
Resources/Audio/Machines/ame_fuelinjection.ogg
Normal file
BIN
Resources/Audio/Machines/ame_fuelinjection.ogg
Normal file
Binary file not shown.
@@ -181,3 +181,8 @@
|
|||||||
license: "CC0-1.0"
|
license: "CC0-1.0"
|
||||||
copyright: "by ScarKy0"
|
copyright: "by ScarKy0"
|
||||||
source: "https://github.com/space-wizards/space-station-14/pull/32012"
|
source: "https://github.com/space-wizards/space-station-14/pull/32012"
|
||||||
|
|
||||||
|
- files: ["ame_fuelinjection.ogg"]
|
||||||
|
license: "CC0-1.0"
|
||||||
|
copyright: "by AftrLite (Github). Uses audio from hypospray.ogg and hiss.ogg (Found in Resources/Audio/Items)"
|
||||||
|
source: "https://github.com/space-wizards/space-station-14/pull/33097"
|
||||||
|
|||||||
Binary file not shown.
@@ -567,5 +567,28 @@ Entries:
|
|||||||
id: 70
|
id: 70
|
||||||
time: '2024-10-16T22:24:31.0000000+00:00'
|
time: '2024-10-16T22:24:31.0000000+00:00'
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/32844
|
url: https://github.com/space-wizards/space-station-14/pull/32844
|
||||||
|
- author: BramvanZijp
|
||||||
|
changes:
|
||||||
|
- message: CC, ERT, Admin, and Deathsquad PDA's now have all departmental programs
|
||||||
|
pre-installed.
|
||||||
|
type: Tweak
|
||||||
|
id: 71
|
||||||
|
time: '2024-10-31T14:53:38.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32601
|
||||||
|
- author: metalgearsloth
|
||||||
|
changes:
|
||||||
|
- message: Added on-call functionality for discord relay to get notified on unanswered
|
||||||
|
ahelps.
|
||||||
|
type: Add
|
||||||
|
id: 72
|
||||||
|
time: '2024-11-02T09:29:16.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/30443
|
||||||
|
- author: nikthechampiongr
|
||||||
|
changes:
|
||||||
|
- message: It is now possible to edit the AI's laws through its core and eye.
|
||||||
|
type: Fix
|
||||||
|
id: 73
|
||||||
|
time: '2024-11-02T13:21:10.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32461
|
||||||
Name: Admin
|
Name: Admin
|
||||||
Order: 1
|
Order: 1
|
||||||
|
|||||||
@@ -1,364 +1,4 @@
|
|||||||
Entries:
|
Entries:
|
||||||
- author: Errant
|
|
||||||
changes:
|
|
||||||
- message: Medical Mask sprite now works on vox.
|
|
||||||
type: Fix
|
|
||||||
id: 7052
|
|
||||||
time: '2024-08-07T03:41:40.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30702
|
|
||||||
- author: Lyroth001
|
|
||||||
changes:
|
|
||||||
- message: Dragons are immune to flashes
|
|
||||||
type: Tweak
|
|
||||||
id: 7053
|
|
||||||
time: '2024-08-07T07:42:00.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30658
|
|
||||||
- author: ShadowCommander
|
|
||||||
changes:
|
|
||||||
- message: Rollerbeds can now be dragged to the player to fold and pick them up.
|
|
||||||
type: Add
|
|
||||||
id: 7054
|
|
||||||
time: '2024-08-07T09:19:10.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30002
|
|
||||||
- author: Errant
|
|
||||||
changes:
|
|
||||||
- message: Survivors arriving via the Unknown Shuttle event, ERT and CBURN agents,
|
|
||||||
and Death Squad members are now equipped with the appropriate species-specific
|
|
||||||
survival gear.
|
|
||||||
type: Fix
|
|
||||||
- message: Unknown Shuttle event can once again spawn vox characters.
|
|
||||||
type: Tweak
|
|
||||||
id: 7055
|
|
||||||
time: '2024-08-07T09:26:40.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29746
|
|
||||||
- author: IProduceWidgets
|
|
||||||
changes:
|
|
||||||
- message: butter is slippery
|
|
||||||
type: Tweak
|
|
||||||
id: 7056
|
|
||||||
time: '2024-08-07T21:47:03.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29772
|
|
||||||
- author: Mervill
|
|
||||||
changes:
|
|
||||||
- message: Gas Miners now have detailed examine text
|
|
||||||
type: Tweak
|
|
||||||
id: 7057
|
|
||||||
time: '2024-08-08T02:14:31.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30480
|
|
||||||
- author: BackeTako
|
|
||||||
changes:
|
|
||||||
- message: "!, \u203D and multiple punctuations now work for Spanish."
|
|
||||||
type: Tweak
|
|
||||||
id: 7058
|
|
||||||
time: '2024-08-08T03:08:28.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30551
|
|
||||||
- author: strO0pwafel
|
|
||||||
changes:
|
|
||||||
- message: Fixed inconsistent naming of CentComm.
|
|
||||||
type: Fix
|
|
||||||
id: 7059
|
|
||||||
time: '2024-08-08T10:04:20.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29217
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: Buffed the range of EMP implants from a radius of 1.75 tiles to 2.75
|
|
||||||
tiles.
|
|
||||||
type: Tweak
|
|
||||||
- message: Buffed the range of EMP grenades from a radius of 4 tiles to 5.5 tiles.
|
|
||||||
type: Tweak
|
|
||||||
id: 7060
|
|
||||||
time: '2024-08-08T10:04:50.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30660
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: You can drop food or drinks from your hands to interrupt eating it, again.
|
|
||||||
type: Fix
|
|
||||||
- message: Barber scissors are now interrupted if the item is dropped or if the
|
|
||||||
user changes hands.
|
|
||||||
type: Tweak
|
|
||||||
id: 7061
|
|
||||||
time: '2024-08-08T11:39:47.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30361
|
|
||||||
- author: TheShuEd
|
|
||||||
changes:
|
|
||||||
- message: Add "thieving beacon" to Thief antag - a device that counts objects within
|
|
||||||
a radius of itself as stolen.
|
|
||||||
type: Add
|
|
||||||
- message: Return thief structures stealing objectives.
|
|
||||||
type: Add
|
|
||||||
- message: Animal theft objectives can no longer appear if the animals are not on
|
|
||||||
the station.
|
|
||||||
type: Fix
|
|
||||||
id: 7062
|
|
||||||
time: '2024-08-08T13:17:50.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29997
|
|
||||||
- author: lzk228
|
|
||||||
changes:
|
|
||||||
- message: RD labcoat added in RD's dresser.
|
|
||||||
type: Add
|
|
||||||
id: 7063
|
|
||||||
time: '2024-08-08T22:50:57.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30671
|
|
||||||
- author: SlamBamActionman
|
|
||||||
changes:
|
|
||||||
- message: Animal DNA now shows up as "unknown DNA" in the Forensic Scanner.
|
|
||||||
type: Tweak
|
|
||||||
- message: Forensic Scanner can now scan fluid containers for DNA in reagents.
|
|
||||||
type: Tweak
|
|
||||||
- message: Fluids keep their DNA data when moved.
|
|
||||||
type: Fix
|
|
||||||
- message: Fluids now stain containers they're in with DNA. Make sure to scrub your
|
|
||||||
blood bucket after use!
|
|
||||||
type: Add
|
|
||||||
- message: Vomit now includes DNA!
|
|
||||||
type: Add
|
|
||||||
id: 7064
|
|
||||||
time: '2024-08-08T23:27:28.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/26699
|
|
||||||
- author: themias
|
|
||||||
changes:
|
|
||||||
- message: Butter can be sliced, cookie and toast recipes now use butter slices.
|
|
||||||
type: Tweak
|
|
||||||
- message: Chefvend butter reduced from 4 to 3.
|
|
||||||
type: Tweak
|
|
||||||
id: 7065
|
|
||||||
time: '2024-08-08T23:32:42.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30789
|
|
||||||
- author: EmoGarbage404
|
|
||||||
changes:
|
|
||||||
- message: You should have significantly less friction when moving in space.
|
|
||||||
type: Tweak
|
|
||||||
id: 7066
|
|
||||||
time: '2024-08-09T04:52:25.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29383
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: Hardsuits and EVA suits now count as protection for unscrewing lightbulbs.
|
|
||||||
type: Add
|
|
||||||
- message: More gloves were given the ability to unscrew light bulbs.
|
|
||||||
type: Add
|
|
||||||
- message: Behonkers no longer hurt you when melee attacking them or interacting
|
|
||||||
with them.
|
|
||||||
type: Remove
|
|
||||||
id: 7067
|
|
||||||
time: '2024-08-09T05:32:41.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30244
|
|
||||||
- author: Ian321
|
|
||||||
changes:
|
|
||||||
- message: The warden is now an important job.
|
|
||||||
type: Tweak
|
|
||||||
id: 7068
|
|
||||||
time: '2024-08-09T05:45:51.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30745
|
|
||||||
- author: slarticodefast
|
|
||||||
changes:
|
|
||||||
- message: Added tooltips to the agent ID job icons
|
|
||||||
type: Add
|
|
||||||
id: 7069
|
|
||||||
time: '2024-08-09T06:14:07.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/28575
|
|
||||||
- author: stalengd
|
|
||||||
changes:
|
|
||||||
- message: Head bandana no longer blocks food eating.
|
|
||||||
type: Fix
|
|
||||||
id: 7070
|
|
||||||
time: '2024-08-09T06:17:51.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/28910
|
|
||||||
- author: Ubaser
|
|
||||||
changes:
|
|
||||||
- message: Oxygen and nitrogen canisters now have new sprites when worn.
|
|
||||||
type: Add
|
|
||||||
id: 7071
|
|
||||||
time: '2024-08-09T10:32:55.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30809
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: Buckling someone now triggers a short do-after.
|
|
||||||
type: Tweak
|
|
||||||
id: 7072
|
|
||||||
time: '2024-08-09T15:43:02.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29621
|
|
||||||
- author: Ubaser
|
|
||||||
changes:
|
|
||||||
- message: Normal crowbars cannot be placed in pockets, but can now fit in belts.
|
|
||||||
type: Tweak
|
|
||||||
- message: Depending on where you obtained the crowbars, they will now have different
|
|
||||||
colours.
|
|
||||||
type: Tweak
|
|
||||||
id: 7073
|
|
||||||
time: '2024-08-09T19:29:00.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/28988
|
|
||||||
- author: lzk228
|
|
||||||
changes:
|
|
||||||
- message: Hotplate works again.
|
|
||||||
type: Fix
|
|
||||||
id: 7074
|
|
||||||
time: '2024-08-10T01:10:39.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30830
|
|
||||||
- author: EmoGarbage404
|
|
||||||
changes:
|
|
||||||
- message: Maintenance closets have more variety in what they can contain.
|
|
||||||
type: Tweak
|
|
||||||
id: 7075
|
|
||||||
time: '2024-08-10T02:12:40.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30579
|
|
||||||
- author: Ko4erga
|
|
||||||
changes:
|
|
||||||
- message: Changed chemistry airlock color.
|
|
||||||
type: Tweak
|
|
||||||
id: 7076
|
|
||||||
time: '2024-08-10T03:23:47.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30666
|
|
||||||
- author: Blackern5000
|
|
||||||
changes:
|
|
||||||
- message: Bent pipes now deal 8 thrown damage instead of 3.
|
|
||||||
type: Tweak
|
|
||||||
id: 7077
|
|
||||||
time: '2024-08-10T03:30:43.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30634
|
|
||||||
- author: shampunj
|
|
||||||
changes:
|
|
||||||
- message: Rat king can now wideswing
|
|
||||||
type: Tweak
|
|
||||||
id: 7078
|
|
||||||
time: '2024-08-10T12:47:55.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30808
|
|
||||||
- author: BackeTako
|
|
||||||
changes:
|
|
||||||
- message: Added a suitskirt for the psychologist
|
|
||||||
type: Add
|
|
||||||
id: 7079
|
|
||||||
time: '2024-08-10T12:51:54.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30709
|
|
||||||
- author: Unkn0wnGh0st333
|
|
||||||
changes:
|
|
||||||
- message: ERT Chaplain starting gear was fixed and will no longer give the ERT
|
|
||||||
Engineer gear
|
|
||||||
type: Fix
|
|
||||||
id: 7080
|
|
||||||
time: '2024-08-10T12:55:20.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30855
|
|
||||||
- author: Ubaser
|
|
||||||
changes:
|
|
||||||
- message: Light tube structures now have new sprites.
|
|
||||||
type: Tweak
|
|
||||||
id: 7081
|
|
||||||
time: '2024-08-10T15:00:22.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29091
|
|
||||||
- author: lzk228
|
|
||||||
changes:
|
|
||||||
- message: Standartized some clothing recipes.
|
|
||||||
type: Tweak
|
|
||||||
id: 7082
|
|
||||||
time: '2024-08-10T18:16:56.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29315
|
|
||||||
- author: TheShuEd
|
|
||||||
changes:
|
|
||||||
- message: You cat cut burger bun into two halfs, and make custom burgers now!
|
|
||||||
type: Add
|
|
||||||
id: 7083
|
|
||||||
time: '2024-08-10T19:31:32.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30755
|
|
||||||
- author: thetolbean
|
|
||||||
changes:
|
|
||||||
- message: Updated Core's boxing ring beacon label to be correct
|
|
||||||
type: Tweak
|
|
||||||
id: 7084
|
|
||||||
time: '2024-08-10T19:50:08.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30800
|
|
||||||
- author: Flareguy
|
|
||||||
changes:
|
|
||||||
- message: Added vox sprites for most of the remaining common mask items.
|
|
||||||
type: Add
|
|
||||||
id: 7085
|
|
||||||
time: '2024-08-10T21:06:50.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30838
|
|
||||||
- author: Scribbles0, Plykiya, nikthechampiongr
|
|
||||||
changes:
|
|
||||||
- message: You can now execute incapacitated/cuffed entities or yourself with certain
|
|
||||||
sharp weapons. Executions require a do-after, deal 9x the damage of a normal
|
|
||||||
attack, and ignore damage resistances.
|
|
||||||
type: Add
|
|
||||||
id: 7086
|
|
||||||
time: '2024-08-11T03:05:54.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30104
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: Cooking shelves have been renamed to Kitchen shelves, you can now put
|
|
||||||
more drinks and cutlery in them.
|
|
||||||
type: Tweak
|
|
||||||
id: 7087
|
|
||||||
time: '2024-08-11T06:21:34.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30858
|
|
||||||
- author: BombasterDS
|
|
||||||
changes:
|
|
||||||
- message: You can now change the suit's sensors on incapacitated people without
|
|
||||||
taking it off
|
|
||||||
type: Tweak
|
|
||||||
id: 7088
|
|
||||||
time: '2024-08-11T09:04:43.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29668
|
|
||||||
- author: lzk228
|
|
||||||
changes:
|
|
||||||
- message: RCD UI can be activated only in hand.
|
|
||||||
type: Tweak
|
|
||||||
id: 7089
|
|
||||||
time: '2024-08-11T09:15:28.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30861
|
|
||||||
- author: TokenStyle
|
|
||||||
changes:
|
|
||||||
- message: Pax reagent now refresh pacified.
|
|
||||||
type: Tweak
|
|
||||||
- message: Pax reagent pacified duration has been changed from 2 seconds to 4 seconds.
|
|
||||||
type: Tweak
|
|
||||||
id: 7090
|
|
||||||
time: '2024-08-11T09:19:01.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30778
|
|
||||||
- author: osjarw
|
|
||||||
changes:
|
|
||||||
- message: You can once again pull and buckle pets.
|
|
||||||
type: Fix
|
|
||||||
id: 7091
|
|
||||||
time: '2024-08-11T09:22:46.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30066
|
|
||||||
- author: slarticodefast
|
|
||||||
changes:
|
|
||||||
- message: The sentient plant mutation can no longer be propagated to other trays
|
|
||||||
via seeds or swabs. It has also been made more rare.
|
|
||||||
type: Tweak
|
|
||||||
id: 7092
|
|
||||||
time: '2024-08-11T09:23:14.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29133
|
|
||||||
- author: Moomoobeef
|
|
||||||
changes:
|
|
||||||
- message: Added The Throngler (Plushie) to the grand lottery!!
|
|
||||||
type: Add
|
|
||||||
id: 7093
|
|
||||||
time: '2024-08-11T10:26:37.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/29978
|
|
||||||
- author: Plykiya
|
|
||||||
changes:
|
|
||||||
- message: Energy sword weapons are now execution-capable.
|
|
||||||
type: Add
|
|
||||||
id: 7094
|
|
||||||
time: '2024-08-11T22:12:31.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30909
|
|
||||||
- author: Blackern5000
|
|
||||||
changes:
|
|
||||||
- message: Added diamond-tipped mining drills, a science printed item found under
|
|
||||||
T2 industrial.
|
|
||||||
type: Add
|
|
||||||
- message: Standard mining drills now attack faster and break rocks in two hits.
|
|
||||||
type: Tweak
|
|
||||||
- message: Moved ore bags of holding to T2 industrial tech.
|
|
||||||
type: Tweak
|
|
||||||
- message: Grappling guns are now researched with Salvage Equipment.
|
|
||||||
type: Tweak
|
|
||||||
- message: Diamonds are now worth 2,000 spesos each.
|
|
||||||
type: Tweak
|
|
||||||
id: 7095
|
|
||||||
time: '2024-08-12T01:49:09.0000000+00:00'
|
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/30814
|
|
||||||
- author: mirrorcult
|
- author: mirrorcult
|
||||||
changes:
|
changes:
|
||||||
- message: With space law being overhauled, you can now examine items to see their
|
- message: With space law being overhauled, you can now examine items to see their
|
||||||
@@ -3959,3 +3599,348 @@
|
|||||||
id: 7551
|
id: 7551
|
||||||
time: '2024-10-24T03:41:03.0000000+00:00'
|
time: '2024-10-24T03:41:03.0000000+00:00'
|
||||||
url: https://github.com/space-wizards/space-station-14/pull/32965
|
url: https://github.com/space-wizards/space-station-14/pull/32965
|
||||||
|
- author: slarticodefast
|
||||||
|
changes:
|
||||||
|
- message: Mix 1u aluminium, 1u potassium and 1u sulfur for a flash reaction effect.
|
||||||
|
The radius scales with the reagent amount.
|
||||||
|
type: Add
|
||||||
|
id: 7552
|
||||||
|
time: '2024-10-25T22:47:12.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32377
|
||||||
|
- author: BramvanZijp
|
||||||
|
changes:
|
||||||
|
- message: Fixed the Lone Nuclear Operative mid-round antagonist being extremely
|
||||||
|
rare.
|
||||||
|
type: Fix
|
||||||
|
id: 7553
|
||||||
|
time: '2024-10-26T02:16:45.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32942
|
||||||
|
- author: Moomoobeef
|
||||||
|
changes:
|
||||||
|
- message: Bowls no longer make an eating sound when drinking from them.
|
||||||
|
type: Fix
|
||||||
|
id: 7554
|
||||||
|
time: '2024-10-26T04:00:49.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32819
|
||||||
|
- author: SaphireLattice
|
||||||
|
changes:
|
||||||
|
- message: Added a warning about unrevivability in the health analyzer UI.
|
||||||
|
type: Add
|
||||||
|
id: 7555
|
||||||
|
time: '2024-10-26T17:22:09.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32636
|
||||||
|
- author: slarticodefast
|
||||||
|
changes:
|
||||||
|
- message: Fixed pie throwing sound not playing.
|
||||||
|
type: Fix
|
||||||
|
id: 7556
|
||||||
|
time: '2024-10-27T04:25:55.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33017
|
||||||
|
- author: stalengd
|
||||||
|
changes:
|
||||||
|
- message: Fixed playtime labels not being able to correctly display time greater
|
||||||
|
than 24 hours
|
||||||
|
type: Fix
|
||||||
|
id: 7557
|
||||||
|
time: '2024-10-28T18:00:00.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32974
|
||||||
|
- author: august-sun
|
||||||
|
changes:
|
||||||
|
- message: Extended the minimum round time for meteor swarm events.
|
||||||
|
type: Tweak
|
||||||
|
id: 7558
|
||||||
|
time: '2024-10-28T21:25:34.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32876
|
||||||
|
- author: deltanedas
|
||||||
|
changes:
|
||||||
|
- message: Fixed lava planet expeditions not working.
|
||||||
|
type: Fix
|
||||||
|
id: 7559
|
||||||
|
time: '2024-10-29T05:00:29.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33042
|
||||||
|
- author: metalgearsloth
|
||||||
|
changes:
|
||||||
|
- message: Fix separated game screen bumping slightly.
|
||||||
|
type: Fix
|
||||||
|
id: 7560
|
||||||
|
time: '2024-10-29T05:07:57.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33046
|
||||||
|
- author: Blackern5000
|
||||||
|
changes:
|
||||||
|
- message: Proto-kitentic crushers, glaives, and daggers now have more accurate
|
||||||
|
inhand sprites.
|
||||||
|
type: Tweak
|
||||||
|
id: 7561
|
||||||
|
time: '2024-10-30T07:38:19.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32212
|
||||||
|
- author: Blackern5000
|
||||||
|
changes:
|
||||||
|
- message: Security belts now contain a holobarrier projector and a handheld security
|
||||||
|
radio by default rather than tear gas and a flashbang.
|
||||||
|
type: Tweak
|
||||||
|
id: 7562
|
||||||
|
time: '2024-10-30T07:40:33.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32291
|
||||||
|
- author: Blackern5000
|
||||||
|
changes:
|
||||||
|
- message: Added three bottle boxes to the nanomed plus inventory for doctors to
|
||||||
|
carry small amounts of chemicals on their person
|
||||||
|
type: Add
|
||||||
|
id: 7563
|
||||||
|
time: '2024-10-30T07:41:51.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33018
|
||||||
|
- author: Blackern5000
|
||||||
|
changes:
|
||||||
|
- message: Added the interdyne defibrillator, a black-and-red defibrillator that
|
||||||
|
can be used as a melee weapon.
|
||||||
|
type: Add
|
||||||
|
- message: The syndicate medical bundle now contains an interdyne defibrillator,
|
||||||
|
a collection of various instant injectors, tourniquets, and several combat kits.
|
||||||
|
The price has been raised to 24 tc.
|
||||||
|
type: Tweak
|
||||||
|
id: 7564
|
||||||
|
time: '2024-10-30T09:15:30.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32720
|
||||||
|
- author: Boaz1111
|
||||||
|
changes:
|
||||||
|
- message: Pill bottles can now only store pills.
|
||||||
|
type: Tweak
|
||||||
|
id: 7565
|
||||||
|
time: '2024-10-31T10:56:07.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33074
|
||||||
|
- author: Jarmer123
|
||||||
|
changes:
|
||||||
|
- message: You can now find a spare bible in the PietyVend
|
||||||
|
type: Add
|
||||||
|
id: 7566
|
||||||
|
time: '2024-10-31T13:26:46.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32363
|
||||||
|
- author: justinbrick
|
||||||
|
changes:
|
||||||
|
- message: Added a pop-up notification when extra items are dropped while unequipping
|
||||||
|
something.
|
||||||
|
type: Tweak
|
||||||
|
id: 7567
|
||||||
|
time: '2024-10-31T14:12:26.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33078
|
||||||
|
- author: BramvanZijp
|
||||||
|
changes:
|
||||||
|
- message: The maximum amount of programs that can be installed on a PDA has been
|
||||||
|
increased from 5 to 8
|
||||||
|
type: Tweak
|
||||||
|
- message: The Detective and Head of Security now get the logprobe program pre-installed
|
||||||
|
on their PDA.
|
||||||
|
type: Tweak
|
||||||
|
id: 7568
|
||||||
|
time: '2024-10-31T14:53:38.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32601
|
||||||
|
- author: Psychpsyo
|
||||||
|
changes:
|
||||||
|
- message: Carp plushies can now be placed in mop buckets, along with other rehydratable
|
||||||
|
things like monkey cubes.
|
||||||
|
type: Add
|
||||||
|
id: 7569
|
||||||
|
time: '2024-10-31T18:46:19.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33079
|
||||||
|
- author: Bhijn and Myr
|
||||||
|
changes:
|
||||||
|
- message: Tail thumping has been downmixed to mono to fix the sound lacking any
|
||||||
|
sort of positioning. They're now capable of having a presence in the actual
|
||||||
|
soundspace, in turn meaning lizards are no longer occupying your headset at
|
||||||
|
all times of day.
|
||||||
|
type: Fix
|
||||||
|
id: 7570
|
||||||
|
time: '2024-10-31T21:30:58.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33092
|
||||||
|
- author: reesque
|
||||||
|
changes:
|
||||||
|
- message: pie not dropping tin on thrown
|
||||||
|
type: Fix
|
||||||
|
id: 7571
|
||||||
|
time: '2024-11-01T01:43:11.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33013
|
||||||
|
- author: SlamBamActionman
|
||||||
|
changes:
|
||||||
|
- message: Votekicks can now be initiated during the pregame lobby.
|
||||||
|
type: Fix
|
||||||
|
id: 7572
|
||||||
|
time: '2024-11-01T01:52:55.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32528
|
||||||
|
- author: PopGamer46
|
||||||
|
changes:
|
||||||
|
- message: Fixed bolt lights of recently unpowered bolted doors
|
||||||
|
type: Fix
|
||||||
|
id: 7573
|
||||||
|
time: '2024-11-01T02:04:09.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33063
|
||||||
|
- author: RumiTiger
|
||||||
|
changes:
|
||||||
|
- message: A chocolate and banana muffin has been added to the game. The berry and
|
||||||
|
cherry muffins have also been resprited!
|
||||||
|
type: Add
|
||||||
|
- message: Now you can make a regular, chocolate, banana, and berry muffin!
|
||||||
|
type: Tweak
|
||||||
|
- message: Muffin tins have been added to the game. They are needed for making muffins!
|
||||||
|
type: Add
|
||||||
|
id: 7574
|
||||||
|
time: '2024-11-01T02:06:46.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/29318
|
||||||
|
- author: ScarKy0
|
||||||
|
changes:
|
||||||
|
- message: AI can no longer toggle seeing jobs off.
|
||||||
|
type: Tweak
|
||||||
|
- message: Borgs can no longer see mindshield status.
|
||||||
|
type: Fix
|
||||||
|
id: 7575
|
||||||
|
time: '2024-11-01T02:32:28.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33069
|
||||||
|
- author: Minemoder5000
|
||||||
|
changes:
|
||||||
|
- message: The cargo shuttle's cargo pallets can no longer sell or buy.
|
||||||
|
type: Fix
|
||||||
|
id: 7576
|
||||||
|
time: '2024-11-01T06:22:39.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33022
|
||||||
|
- author: aspiringLich
|
||||||
|
changes:
|
||||||
|
- message: Fixed the logic triggering popups when inserting items into machines.
|
||||||
|
type: Fix
|
||||||
|
id: 7577
|
||||||
|
time: '2024-11-02T01:33:26.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/28856
|
||||||
|
- author: K-Dynamic
|
||||||
|
changes:
|
||||||
|
- message: Pills are explosion resistant.
|
||||||
|
type: Tweak
|
||||||
|
id: 7578
|
||||||
|
time: '2024-11-02T09:51:45.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32458
|
||||||
|
- author: K-Dynamic
|
||||||
|
changes:
|
||||||
|
- message: Handcrafted gauze now takes 3 seconds instead of 10 seconds of crafting
|
||||||
|
type: Tweak
|
||||||
|
- message: Medical techfab gauze recipe now takes 1 cloth instead of 2
|
||||||
|
type: Tweak
|
||||||
|
id: 7579
|
||||||
|
time: '2024-11-02T09:53:19.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32744
|
||||||
|
- author: Ubaser
|
||||||
|
changes:
|
||||||
|
- message: Service workers can now be antagonists.
|
||||||
|
type: Fix
|
||||||
|
id: 7580
|
||||||
|
time: '2024-11-02T10:07:52.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/31359
|
||||||
|
- author: AftrLite
|
||||||
|
changes:
|
||||||
|
- message: The AME now has a new sound effect for fuel injection!
|
||||||
|
type: Add
|
||||||
|
id: 7581
|
||||||
|
time: '2024-11-02T13:19:33.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33097
|
||||||
|
- author: deltanedas
|
||||||
|
changes:
|
||||||
|
- message: Printing cables in an autolathe is now 20 times faster.
|
||||||
|
type: Tweak
|
||||||
|
id: 7582
|
||||||
|
time: '2024-11-02T13:24:08.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/31521
|
||||||
|
- author: Centronias
|
||||||
|
changes:
|
||||||
|
- message: Fixed a bug where attempting to speak into a handheld radio and an intercom
|
||||||
|
simultaneously would lead to only one device transmitting the message.
|
||||||
|
type: Fix
|
||||||
|
id: 7583
|
||||||
|
time: '2024-11-02T15:04:22.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32737
|
||||||
|
- author: joshepvodka
|
||||||
|
changes:
|
||||||
|
- message: Headphones are now selectable in loadouts.
|
||||||
|
type: Add
|
||||||
|
id: 7584
|
||||||
|
time: '2024-11-02T15:12:26.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33067
|
||||||
|
- author: Plykiya
|
||||||
|
changes:
|
||||||
|
- message: Wielding weapons no longer displays your character's real identity when
|
||||||
|
your identity is hidden.
|
||||||
|
type: Fix
|
||||||
|
id: 7585
|
||||||
|
time: '2024-11-03T11:25:30.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33134
|
||||||
|
- author: MilenVolf
|
||||||
|
changes:
|
||||||
|
- message: Ghost roles menu is now collapsible! This makes it much easier to find
|
||||||
|
a specific role that you want.
|
||||||
|
type: Tweak
|
||||||
|
id: 7586
|
||||||
|
time: '2024-11-04T00:49:42.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32717
|
||||||
|
- author: Tr1bute
|
||||||
|
changes:
|
||||||
|
- message: A popup now appears when attempting to harvest mutated plants that require
|
||||||
|
sharp tools.
|
||||||
|
type: Add
|
||||||
|
id: 7587
|
||||||
|
time: '2024-11-04T00:56:41.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33136
|
||||||
|
- author: Boolean-Buckeye
|
||||||
|
changes:
|
||||||
|
- message: Emergency lights can be constructed and deconstructed
|
||||||
|
type: Add
|
||||||
|
id: 7588
|
||||||
|
time: '2024-11-04T03:24:22.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32945
|
||||||
|
- author: thetolbean
|
||||||
|
changes:
|
||||||
|
- message: The web coat and boots can now be broken down into silk.
|
||||||
|
type: Fix
|
||||||
|
id: 7589
|
||||||
|
time: '2024-11-04T03:33:51.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33121
|
||||||
|
- author: Kickguy223
|
||||||
|
changes:
|
||||||
|
- message: Ion Storms now notify a Borg that their laws have changed via a sound
|
||||||
|
cue.
|
||||||
|
type: Add
|
||||||
|
id: 7590
|
||||||
|
time: '2024-11-04T11:23:12.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32887
|
||||||
|
- author: DrSmugleaf
|
||||||
|
changes:
|
||||||
|
- message: Fixed not being able to see vote counts for non-votekick votes.
|
||||||
|
type: Fix
|
||||||
|
id: 7591
|
||||||
|
time: '2024-11-05T00:12:29.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33170
|
||||||
|
- author: kirus59
|
||||||
|
changes:
|
||||||
|
- message: Fixed display of icons when using hunger or thirst huds
|
||||||
|
type: Fix
|
||||||
|
- message: Fixed errors spam when using beer goggles
|
||||||
|
type: Fix
|
||||||
|
id: 7592
|
||||||
|
time: '2024-11-05T16:58:23.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/32832
|
||||||
|
- author: Errant
|
||||||
|
changes:
|
||||||
|
- message: Syndicate Reinforcements no longer list their (hidden and unused) codewords
|
||||||
|
on the Round End window.
|
||||||
|
type: Fix
|
||||||
|
id: 7593
|
||||||
|
time: '2024-11-05T18:18:28.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33181
|
||||||
|
- author: Baptr0b0t
|
||||||
|
changes:
|
||||||
|
- message: Fixed Intelicard can see through walls.
|
||||||
|
type: Fix
|
||||||
|
id: 7594
|
||||||
|
time: '2024-11-06T03:28:58.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33177
|
||||||
|
- author: slarticodefast
|
||||||
|
changes:
|
||||||
|
- message: Removed the wanted list cartridge from the captain's PDA.
|
||||||
|
type: Remove
|
||||||
|
id: 7595
|
||||||
|
time: '2024-11-06T13:20:05.0000000+00:00'
|
||||||
|
url: https://github.com/space-wizards/space-station-14/pull/33084
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -31,3 +31,4 @@ plant-holder-component-heat-improper-warning = The [color=orange]improper temper
|
|||||||
plant-holder-component-pressure-improper-warning = The [color=lightblue]improper environment pressure alert[/color] is blinking.
|
plant-holder-component-pressure-improper-warning = The [color=lightblue]improper environment pressure alert[/color] is blinking.
|
||||||
plant-holder-component-gas-missing-warning = The [color=cyan]improper gas environment alert[/color] is blinking.
|
plant-holder-component-gas-missing-warning = The [color=cyan]improper gas environment alert[/color] is blinking.
|
||||||
plant-holder-component-early-sample-message = The plant hasn't grown enough to take a sample yet.
|
plant-holder-component-early-sample-message = The plant hasn't grown enough to take a sample yet.
|
||||||
|
plant-holder-component-ligneous-cant-harvest-message = The plant is too tough to harvest with your bare hands.
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ ghost-target-window-current-button = Warp: {$name}
|
|||||||
ghost-target-window-warp-to-most-followed = Warp to Most Followed
|
ghost-target-window-warp-to-most-followed = Warp to Most Followed
|
||||||
|
|
||||||
ghost-roles-window-title = Ghost Roles
|
ghost-roles-window-title = Ghost Roles
|
||||||
|
ghost-roles-window-available-button = Available ({$rolesCount})
|
||||||
ghost-roles-window-join-raffle-button = Join raffle
|
ghost-roles-window-join-raffle-button = Join raffle
|
||||||
ghost-roles-window-raffle-in-progress-button =
|
ghost-roles-window-raffle-in-progress-button =
|
||||||
Join raffle ({$time} left, { $players ->
|
Join raffle ({$time} left, { $players ->
|
||||||
|
|||||||
@@ -2,3 +2,9 @@ inventory-component-can-equip-cannot = You can't equip this!
|
|||||||
inventory-component-can-equip-does-not-fit = This doesn't fit!
|
inventory-component-can-equip-does-not-fit = This doesn't fit!
|
||||||
|
|
||||||
inventory-component-can-unequip-cannot = You can't unequip this!
|
inventory-component-can-unequip-cannot = You can't unequip this!
|
||||||
|
|
||||||
|
inventory-component-dropped-from-unequip =
|
||||||
|
You dropped {$items ->
|
||||||
|
[1] an item!
|
||||||
|
*[other] some items!
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# mop bucket
|
# mop bucket
|
||||||
mop-bucket-slot-component-slot-name-shark = Shark
|
mop-bucket-slot-component-slot-name-item = Item
|
||||||
|
mop-bucket-slot-component-eject-verb = Take out
|
||||||
# janitorial trolley
|
# janitorial trolley
|
||||||
janitorial-trolley-slot-component-slot-name-plunger = Plunger
|
janitorial-trolley-slot-component-slot-name-plunger = Plunger
|
||||||
janitorial-trolley-slot-component-slot-name-sign = Sign
|
janitorial-trolley-slot-component-slot-name-sign = Sign
|
||||||
|
|||||||
@@ -216,8 +216,8 @@ uplink-chemistry-kit-desc = A starter kit for the aspiring chemist, includes tox
|
|||||||
uplink-knives-kit-name = Throwing Knives Kit
|
uplink-knives-kit-name = Throwing Knives Kit
|
||||||
uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims.
|
uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims.
|
||||||
|
|
||||||
uplink-meds-bundle-name = Medical Bundle
|
uplink-meds-bundle-name = Interdyne Medical Bundle
|
||||||
uplink-meds-bundle-desc = All you need to get your comrades back in the fight: mainly a combat medkit, a defibrillator and three combat medipens.
|
uplink-meds-bundle-desc = An assortment of autoinjectors and premium medical equipment to cover for every possible situation. Contains an elite compact defibrillator that can be used as a weapon.
|
||||||
|
|
||||||
uplink-ammo-bundle-name = Ammo Bundle
|
uplink-ammo-bundle-name = Ammo Bundle
|
||||||
uplink-ammo-bundle-desc = Reloading! Contains 4 magazines for the C-20r, 4 drums for the Bulldog, and 2 ammo boxes for the L6 SAW.
|
uplink-ammo-bundle-desc = Reloading! Contains 4 magazines for the C-20r, 4 drums for the Bulldog, and 2 ammo boxes for the L6 SAW.
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ ui-vote-type-not-available = This vote type has been disabled
|
|||||||
|
|
||||||
# Vote option only available for specific users.
|
# Vote option only available for specific users.
|
||||||
ui-vote-trusted-users-notice =
|
ui-vote-trusted-users-notice =
|
||||||
This vote option is only available to whitelisted players.
|
This vote option is only available to players who have enough playtime or are whitelisted.
|
||||||
In addition, you must have been a ghost for { $timeReq } minutes.
|
In addition, you must have been a ghost for { $timeReq } seconds.
|
||||||
|
|
||||||
# Warning to not abuse a specific vote option.
|
# Warning to not abuse a specific vote option.
|
||||||
ui-vote-abuse-warning =
|
ui-vote-abuse-warning =
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
# Shown when examining the window. Each entry represents the window's health condition
|
# Shown when examining the window. Each entry represents the window's health condition
|
||||||
comp-window-damaged-1 = It looks fully intact.
|
comp-window-damaged-1 = It looks fully intact.
|
||||||
comp-window-damaged-2 = It has a few scratches
|
comp-window-damaged-2 = It has a few scratches.
|
||||||
comp-window-damaged-3 = It has a few small cracks.
|
comp-window-damaged-3 = It has a few small cracks.
|
||||||
comp-window-damaged-4 = It has several big cracks running along its surface.
|
comp-window-damaged-4 = [color=yellow]It has several big cracks running along its surface.[/color]
|
||||||
comp-window-damaged-5 = It has deep cracks across multiple layers.
|
comp-window-damaged-5 = [color=orange]It has deep cracks across multiple layers.[/color]
|
||||||
comp-window-damaged-6 = It's extremely cracked and on the verge of shattering.
|
comp-window-damaged-6 = [color=red]It's extremely cracked and on the verge of shattering.[/color]
|
||||||
|
|
||||||
### Interaction Messages
|
### Interaction Messages
|
||||||
|
|
||||||
# Shown when knocking on a window
|
# Shown when knocking on a window
|
||||||
comp-window-knock = *knock knock*
|
comp-window-knock = *knock knock*
|
||||||
|
|
||||||
|
|||||||
@@ -6576,7 +6576,7 @@ entities:
|
|||||||
- uid: 2031
|
- uid: 2031
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 3.6114278,-10.732791
|
pos: 4.0109396,-12.223828
|
||||||
parent: 104
|
parent: 104
|
||||||
- uid: 2095
|
- uid: 2095
|
||||||
components:
|
components:
|
||||||
@@ -10993,6 +10993,13 @@ entities:
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
pos: 11.5,-6.5
|
pos: 11.5,-6.5
|
||||||
parent: 104
|
parent: 104
|
||||||
|
- proto: HandLabeler
|
||||||
|
entities:
|
||||||
|
- uid: 1826
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
pos: 3.4542694,-10.616036
|
||||||
|
parent: 104
|
||||||
- proto: KitchenKnife
|
- proto: KitchenKnife
|
||||||
entities:
|
entities:
|
||||||
- uid: 1061
|
- uid: 1061
|
||||||
|
|||||||
@@ -5,35 +5,20 @@
|
|||||||
description: Sends your eye back to the core.
|
description: Sends your eye back to the core.
|
||||||
components:
|
components:
|
||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
priority: -10
|
priority: -9
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
icon:
|
icon:
|
||||||
sprite: Interface/Actions/actions_ai.rsi
|
sprite: Interface/Actions/actions_ai.rsi
|
||||||
state: ai_core
|
state: ai_core
|
||||||
event: !type:JumpToCoreEvent
|
event: !type:JumpToCoreEvent
|
||||||
|
|
||||||
- type: entity
|
|
||||||
id: ActionShowJobIcons
|
|
||||||
name: Show job icons
|
|
||||||
description: Shows job icons for crew members.
|
|
||||||
components:
|
|
||||||
- type: InstantAction
|
|
||||||
priority: -5
|
|
||||||
itemIconStyle: BigAction
|
|
||||||
icon:
|
|
||||||
sprite: Interface/Actions/actions_ai.rsi
|
|
||||||
state: job_view
|
|
||||||
event: !type:ActionComponentChangeEvent
|
|
||||||
components:
|
|
||||||
- type: ShowJobIcons
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionSurvCameraLights
|
id: ActionSurvCameraLights
|
||||||
name: Toggle camera lights
|
name: Toggle camera lights
|
||||||
description: Enable surveillance camera lights near wherever you're viewing.
|
description: Enable surveillance camera lights near wherever you're viewing.
|
||||||
components:
|
components:
|
||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
priority: -6
|
priority: -5
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
icon:
|
icon:
|
||||||
sprite: Interface/Actions/actions_ai.rsi
|
sprite: Interface/Actions/actions_ai.rsi
|
||||||
|
|||||||
@@ -302,13 +302,19 @@
|
|||||||
components:
|
components:
|
||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
|
- id: DefibrillatorSyndicate
|
||||||
- id: MedkitCombatFilled
|
- id: MedkitCombatFilled
|
||||||
- id: Defibrillator
|
amount: 4
|
||||||
|
- id: Tourniquet
|
||||||
|
amount: 4
|
||||||
- id: CombatMedipen
|
- id: CombatMedipen
|
||||||
amount: 3
|
amount: 4
|
||||||
- id: ClothingHandsGlovesNitrile
|
- id: PunctAutoInjector
|
||||||
- id: SyringeTranexamicAcid
|
amount: 4
|
||||||
- id: SyringeHyronalin
|
- id: PyraAutoInjector
|
||||||
|
amount: 4
|
||||||
|
- id: AirlossAutoInjector
|
||||||
|
amount: 4
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBackpackDuffelSyndicateBundle
|
parent: ClothingBackpackDuffelSyndicateBundle
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
table: !type:AllSelector
|
table: !type:AllSelector
|
||||||
children:
|
children:
|
||||||
- id: Stunbaton
|
- id: Stunbaton
|
||||||
- id: GrenadeFlashBang
|
|
||||||
- id: TearGasGrenade
|
|
||||||
- id: Handcuffs
|
- id: Handcuffs
|
||||||
- id: Handcuffs
|
- id: Handcuffs
|
||||||
|
- id: HoloprojectorSecurity
|
||||||
|
- id: RadioHandheldSecurity
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ClothingBeltSecurityFilled
|
id: ClothingBeltSecurityFilled
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
BoxCandle: 2
|
BoxCandle: 2
|
||||||
BoxCandleSmall: 2
|
BoxCandleSmall: 2
|
||||||
Urn: 5
|
Urn: 5
|
||||||
|
Bible: 1
|
||||||
emaggedInventory:
|
emaggedInventory:
|
||||||
ClothingOuterArmorCult: 1
|
ClothingOuterArmorCult: 1
|
||||||
ClothingHeadHelmetCult: 1
|
ClothingHeadHelmetCult: 1
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
FoodPlate: 10
|
FoodPlate: 10
|
||||||
FoodPlateSmall: 10
|
FoodPlateSmall: 10
|
||||||
FoodPlateTin: 5
|
FoodPlateTin: 5
|
||||||
|
FoodPlateMuffinTin: 5
|
||||||
FoodKebabSkewer: 5
|
FoodKebabSkewer: 5
|
||||||
DrinkGlass: 5
|
DrinkGlass: 5
|
||||||
Beaker: 5
|
Beaker: 5
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
Bloodpack: 5
|
Bloodpack: 5
|
||||||
EpinephrineChemistryBottle: 3
|
EpinephrineChemistryBottle: 3
|
||||||
Syringe: 5
|
Syringe: 5
|
||||||
|
BoxBottle: 3
|
||||||
ClothingEyesHudMedical: 2
|
ClothingEyesHudMedical: 2
|
||||||
ClothingEyesEyepatchHudMedical: 2
|
ClothingEyesEyepatchHudMedical: 2
|
||||||
|
|
||||||
|
|||||||
@@ -699,9 +699,9 @@
|
|||||||
productEntity: ClothingBackpackDuffelSyndicateMedicalBundleFilled
|
productEntity: ClothingBackpackDuffelSyndicateMedicalBundleFilled
|
||||||
discountCategory: rareDiscounts
|
discountCategory: rareDiscounts
|
||||||
discountDownTo:
|
discountDownTo:
|
||||||
Telecrystal: 12
|
Telecrystal: 16
|
||||||
cost:
|
cost:
|
||||||
Telecrystal: 20
|
Telecrystal: 24
|
||||||
categories:
|
categories:
|
||||||
- UplinkChemicals
|
- UplinkChemicals
|
||||||
conditions:
|
conditions:
|
||||||
|
|||||||
@@ -487,7 +487,6 @@
|
|||||||
- CartridgeAmmo
|
- CartridgeAmmo
|
||||||
- DoorRemote
|
- DoorRemote
|
||||||
- Whistle
|
- Whistle
|
||||||
- HolosignProjector
|
|
||||||
- BalloonPopper
|
- BalloonPopper
|
||||||
- type: ItemMapper
|
- type: ItemMapper
|
||||||
mapLayers:
|
mapLayers:
|
||||||
|
|||||||
@@ -13,11 +13,7 @@
|
|||||||
categories: [ HideSpawnMenu ]
|
categories: [ HideSpawnMenu ]
|
||||||
components:
|
components:
|
||||||
- type: ShowHealthBars
|
- type: ShowHealthBars
|
||||||
damageContainers:
|
|
||||||
- Biological
|
|
||||||
- type: ShowHealthIcons
|
- type: ShowHealthIcons
|
||||||
damageContainers:
|
|
||||||
- Biological
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -223,8 +219,6 @@
|
|||||||
sprite: Clothing/Eyes/Hud/syndagent.rsi
|
sprite: Clothing/Eyes/Hud/syndagent.rsi
|
||||||
- type: ShowSyndicateIcons
|
- type: ShowSyndicateIcons
|
||||||
- type: ShowHealthBars
|
- type: ShowHealthBars
|
||||||
damageContainers:
|
|
||||||
- Biological
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: [ClothingEyesGlassesSunglasses, ShowSecurityIcons]
|
parent: [ClothingEyesGlassesSunglasses, ShowSecurityIcons]
|
||||||
|
|||||||
@@ -853,6 +853,10 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: WebObjects
|
graph: WebObjects
|
||||||
node: coat
|
node: coat
|
||||||
|
- type: Butcherable
|
||||||
|
spawned:
|
||||||
|
- id: MaterialWebSilk1
|
||||||
|
amount: 5
|
||||||
- type: FlavorProfile
|
- type: FlavorProfile
|
||||||
flavors:
|
flavors:
|
||||||
- cobwebs
|
- cobwebs
|
||||||
|
|||||||
@@ -187,6 +187,10 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Fiber
|
- ReagentId: Fiber
|
||||||
Quantity: 10
|
Quantity: 10
|
||||||
|
- type: Butcherable
|
||||||
|
spawned:
|
||||||
|
- id: MaterialWebSilk1
|
||||||
|
amount: 2
|
||||||
- type: Construction
|
- type: Construction
|
||||||
graph: WebObjects
|
graph: WebObjects
|
||||||
node: boots
|
node: boots
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
- FoodBakedMuffinBerry
|
- FoodBakedMuffinBerry
|
||||||
- FoodBakedMuffinCherry
|
- FoodBakedMuffinCherry
|
||||||
- FoodBakedMuffinBluecherry
|
- FoodBakedMuffinBluecherry
|
||||||
|
- FoodBakedMuffinChocolate
|
||||||
|
- FoodBakedMuffinBanana
|
||||||
- FoodBakedBunHoney
|
- FoodBakedBunHoney
|
||||||
- FoodBakedBunHotX
|
- FoodBakedBunHotX
|
||||||
- FoodBakedBunMeat
|
- FoodBakedBunMeat
|
||||||
|
|||||||
@@ -285,7 +285,6 @@
|
|||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Command"], ["Research"]]
|
access: [["Command"], ["Research"]]
|
||||||
- type: ShowJobIcons
|
- type: ShowJobIcons
|
||||||
- type: ShowMindShieldIcons
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: BaseBorgChassisSyndicate
|
id: BaseBorgChassisSyndicate
|
||||||
|
|||||||
@@ -391,8 +391,6 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
node: syndicatemedical
|
node: syndicatemedical
|
||||||
- type: ShowHealthBars
|
- type: ShowHealthBars
|
||||||
damageContainers:
|
|
||||||
- Biological
|
|
||||||
- type: InteractionPopup
|
- type: InteractionPopup
|
||||||
interactSuccessString: petting-success-syndicate-cyborg
|
interactSuccessString: petting-success-syndicate-cyborg
|
||||||
interactFailureString: petting-failure-syndicate-cyborg
|
interactFailureString: petting-failure-syndicate-cyborg
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
icon: { sprite: Interface/Actions/actions_ai.rsi, state: mass_scanner }
|
icon: { sprite: Interface/Actions/actions_ai.rsi, state: mass_scanner }
|
||||||
iconOn: Interface/Actions/actions_ai.rsi/mass_scanner.png
|
iconOn: Interface/Actions/actions_ai.rsi/mass_scanner.png
|
||||||
keywords: [ "AI", "console", "interface" ]
|
keywords: [ "AI", "console", "interface" ]
|
||||||
priority: -7
|
priority: -6
|
||||||
event: !type:ToggleIntrinsicUIEvent { key: enum.RadarConsoleUiKey.Key }
|
event: !type:ToggleIntrinsicUIEvent { key: enum.RadarConsoleUiKey.Key }
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
icon: { sprite: Interface/Actions/actions_ai.rsi, state: crew_monitor }
|
icon: { sprite: Interface/Actions/actions_ai.rsi, state: crew_monitor }
|
||||||
iconOn: Interface/Actions/actions_ai.rsi/crew_monitor.png
|
iconOn: Interface/Actions/actions_ai.rsi/crew_monitor.png
|
||||||
keywords: [ "AI", "console", "interface" ]
|
keywords: [ "AI", "console", "interface" ]
|
||||||
priority: -9
|
priority: -8
|
||||||
event: !type:ToggleIntrinsicUIEvent { key: enum.CrewMonitoringUIKey.Key }
|
event: !type:ToggleIntrinsicUIEvent { key: enum.CrewMonitoringUIKey.Key }
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -163,5 +163,5 @@
|
|||||||
icon: { sprite: Interface/Actions/actions_ai.rsi, state: station_records }
|
icon: { sprite: Interface/Actions/actions_ai.rsi, state: station_records }
|
||||||
iconOn: Interface/Actions/actions_ai.rsi/station_records.png
|
iconOn: Interface/Actions/actions_ai.rsi/station_records.png
|
||||||
keywords: [ "AI", "console", "interface" ]
|
keywords: [ "AI", "console", "interface" ]
|
||||||
priority: -8
|
priority: -7
|
||||||
event: !type:ToggleIntrinsicUIEvent { key: enum.GeneralStationRecordConsoleKey.Key }
|
event: !type:ToggleIntrinsicUIEvent { key: enum.GeneralStationRecordConsoleKey.Key }
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
- type: ActionGrant
|
- type: ActionGrant
|
||||||
actions:
|
actions:
|
||||||
- ActionJumpToCore
|
- ActionJumpToCore
|
||||||
- ActionShowJobIcons
|
|
||||||
- ActionSurvCameraLights
|
- ActionSurvCameraLights
|
||||||
- ActionAIViewLaws
|
- ActionAIViewLaws
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
@@ -70,6 +69,9 @@
|
|||||||
canShuttle: false
|
canShuttle: false
|
||||||
title: comms-console-announcement-title-station-ai
|
title: comms-console-announcement-title-station-ai
|
||||||
color: "#2ed2fd"
|
color: "#2ed2fd"
|
||||||
|
- type: Speech
|
||||||
|
speechVerb: Robotic
|
||||||
|
- type: ShowJobIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: AiHeldIntellicard
|
id: AiHeldIntellicard
|
||||||
|
|||||||
@@ -19,44 +19,84 @@
|
|||||||
- type: Item
|
- type: Item
|
||||||
size: Tiny
|
size: Tiny
|
||||||
|
|
||||||
# Muffins/Buns
|
# Muffins
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: muffin
|
name: muffin
|
||||||
parent: FoodBakedBase
|
parent: FoodInjectableBase
|
||||||
id: FoodBakedMuffin
|
id: FoodBakedMuffin
|
||||||
description: A delicious and spongy little cake.
|
description: A delicious and spongy little cake.
|
||||||
components:
|
components:
|
||||||
|
- type: Food
|
||||||
|
trash:
|
||||||
|
- FoodPlateMuffinTin
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Food/Baked/misc.rsi
|
||||||
state: muffin
|
state: muffin
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
maxVol: 10
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 6
|
||||||
|
- ReagentId: Vitamin
|
||||||
|
Quantity: 2
|
||||||
|
- type: FlavorProfile
|
||||||
|
flavors:
|
||||||
|
- sweet
|
||||||
|
- type: Item
|
||||||
|
size: Tiny
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: berry muffin
|
name: berry muffin
|
||||||
parent: FoodBakedBase
|
parent: FoodBakedMuffin
|
||||||
id: FoodBakedMuffinBerry
|
id: FoodBakedMuffinBerry
|
||||||
description: A delicious and spongy little cake, with berries.
|
description: A delicious and spongy little cake, with berries.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: muffin-berry
|
state: muffin-berry
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
maxVol: 12
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 6
|
||||||
|
- ReagentId: Vitamin
|
||||||
|
Quantity: 2
|
||||||
|
- ReagentId: JuiceBerry
|
||||||
|
Quantity: 2
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Fruit
|
- Fruit
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: cherry muffin
|
name: cherry muffin
|
||||||
parent: FoodBakedBase
|
parent: FoodBakedMuffin
|
||||||
id: FoodBakedMuffinCherry
|
id: FoodBakedMuffinCherry
|
||||||
description: A sweet muffin with cherry bits.
|
description: A sweet muffin with cherry bits.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: muffin-cherry
|
state: muffin-cherry
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
maxVol: 12
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 6
|
||||||
|
- ReagentId: Vitamin
|
||||||
|
Quantity: 2
|
||||||
|
- ReagentId: JuiceCherry
|
||||||
|
Quantity: 2
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Fruit
|
- Fruit
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: bluecherry muffin
|
name: bluecherry muffin
|
||||||
parent: FoodBakedBase
|
parent: FoodBakedMuffin
|
||||||
id: FoodBakedMuffinBluecherry
|
id: FoodBakedMuffinBluecherry
|
||||||
description: Blue cherries inside a delicious muffin.
|
description: Blue cherries inside a delicious muffin.
|
||||||
components:
|
components:
|
||||||
@@ -66,6 +106,51 @@
|
|||||||
tags:
|
tags:
|
||||||
- Fruit
|
- Fruit
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: chocolate muffin
|
||||||
|
parent: FoodBakedMuffin
|
||||||
|
id: FoodBakedMuffinChocolate
|
||||||
|
description: A delicious and spongy chocolate muffin.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: muffin-chocolate
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
maxVol: 12
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 6
|
||||||
|
- ReagentId: Vitamin
|
||||||
|
Quantity: 2
|
||||||
|
- ReagentId: CocoaPowder
|
||||||
|
Quantity: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: banana muffin
|
||||||
|
parent: FoodBakedMuffin
|
||||||
|
id: FoodBakedMuffinBanana
|
||||||
|
description: A delicious and spongy banana muffin.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: muffin-banana
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
maxVol: 12
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 6
|
||||||
|
- ReagentId: Vitamin
|
||||||
|
Quantity: 2
|
||||||
|
- ReagentId: JuiceBanana
|
||||||
|
Quantity: 2
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Fruit
|
||||||
|
|
||||||
|
# Buns
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: honey bun #TODO honey
|
name: honey bun #TODO honey
|
||||||
parent: FoodBakedBase
|
parent: FoodBakedBase
|
||||||
@@ -685,4 +770,4 @@
|
|||||||
- type: DamageOtherOnHit
|
- type: DamageOtherOnHit
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Blunt: 0 # so the damage stats icon doesn't immediately give away the syndie ones
|
Blunt: 0 # so the damage stats icon doesn't immediately give away the syndie ones
|
||||||
|
|||||||
@@ -178,3 +178,27 @@
|
|||||||
materialComposition:
|
materialComposition:
|
||||||
Steel: 60
|
Steel: 60
|
||||||
- type: SpaceGarbage
|
- type: SpaceGarbage
|
||||||
|
|
||||||
|
# Muffin Tin
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: muffin tin
|
||||||
|
parent: BaseItem
|
||||||
|
id: FoodPlateMuffinTin
|
||||||
|
description: A cheap foil tin for muffins.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Food/plates.rsi
|
||||||
|
state: muffin-tin
|
||||||
|
- type: Item
|
||||||
|
size: Small
|
||||||
|
shape:
|
||||||
|
- 0,0,1,0
|
||||||
|
storedOffset: 0,-3
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Trash
|
||||||
|
- type: PhysicalComposition
|
||||||
|
materialComposition:
|
||||||
|
Steel: 30
|
||||||
|
- type: SpaceGarbage
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
components:
|
components:
|
||||||
- Anchorable
|
- Anchorable
|
||||||
- Item
|
- Item
|
||||||
|
tags:
|
||||||
- Bot # for funny bot moments
|
- Bot # for funny bot moments
|
||||||
blacklist:
|
blacklist:
|
||||||
components:
|
components:
|
||||||
|
|||||||
@@ -121,6 +121,7 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- HolofanProjector
|
- HolofanProjector
|
||||||
|
- SecBeltEquip
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 50
|
price: 50
|
||||||
|
|
||||||
|
|||||||
@@ -496,7 +496,7 @@
|
|||||||
state: pda-janitor
|
state: pda-janitor
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseSecurityPDA
|
parent: BasePDA
|
||||||
id: CaptainPDA
|
id: CaptainPDA
|
||||||
name: captain PDA
|
name: captain PDA
|
||||||
description: Surprisingly no different from your PDA.
|
description: Surprisingly no different from your PDA.
|
||||||
@@ -684,6 +684,13 @@
|
|||||||
accentHColor: "#447987"
|
accentHColor: "#447987"
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: pda-hos
|
state: pda-hos
|
||||||
|
- type: CartridgeLoader
|
||||||
|
preinstalled:
|
||||||
|
- CrewManifestCartridge
|
||||||
|
- NotekeeperCartridge
|
||||||
|
- NewsReaderCartridge
|
||||||
|
- WantedListCartridge
|
||||||
|
- LogProbeCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseSecurityPDA
|
parent: BaseSecurityPDA
|
||||||
@@ -732,6 +739,16 @@
|
|||||||
borderColor: "#00842e"
|
borderColor: "#00842e"
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: pda-centcom
|
state: pda-centcom
|
||||||
|
- type: CartridgeLoader
|
||||||
|
uiKey: enum.PdaUiKey.Key
|
||||||
|
preinstalled:
|
||||||
|
- CrewManifestCartridge
|
||||||
|
- NotekeeperCartridge
|
||||||
|
- NewsReaderCartridge
|
||||||
|
- MedTekCartridge
|
||||||
|
- WantedListCartridge
|
||||||
|
- LogProbeCartridge
|
||||||
|
- AstroNavCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: CentcomPDA
|
parent: CentcomPDA
|
||||||
@@ -754,6 +771,8 @@
|
|||||||
- NewsReaderCartridge
|
- NewsReaderCartridge
|
||||||
- LogProbeCartridge
|
- LogProbeCartridge
|
||||||
- WantedListCartridge
|
- WantedListCartridge
|
||||||
|
- MedTekCartridge
|
||||||
|
- AstroNavCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: CentcomPDA
|
parent: CentcomPDA
|
||||||
@@ -845,14 +864,6 @@
|
|||||||
uiKey: enum.PdaUiKey.Key
|
uiKey: enum.PdaUiKey.Key
|
||||||
preinstalled:
|
preinstalled:
|
||||||
- NotekeeperCartridge
|
- NotekeeperCartridge
|
||||||
cartridgeSlot:
|
|
||||||
priority: -1
|
|
||||||
name: Cartridge
|
|
||||||
ejectSound: /Audio/Machines/id_swipe.ogg
|
|
||||||
insertSound: /Audio/Machines/id_insert.ogg
|
|
||||||
whitelist:
|
|
||||||
components:
|
|
||||||
- Cartridge
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseSecurityPDA
|
parent: BaseSecurityPDA
|
||||||
@@ -870,6 +881,16 @@
|
|||||||
accentVColor: "#447987"
|
accentVColor: "#447987"
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: pda-ert
|
state: pda-ert
|
||||||
|
- type: CartridgeLoader
|
||||||
|
uiKey: enum.PdaUiKey.Key
|
||||||
|
preinstalled:
|
||||||
|
- CrewManifestCartridge
|
||||||
|
- NotekeeperCartridge
|
||||||
|
- NewsReaderCartridge
|
||||||
|
- MedTekCartridge
|
||||||
|
- WantedListCartridge
|
||||||
|
- LogProbeCartridge
|
||||||
|
- AstroNavCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ERTLeaderPDA
|
parent: ERTLeaderPDA
|
||||||
@@ -910,14 +931,6 @@
|
|||||||
components:
|
components:
|
||||||
- type: Pda
|
- type: Pda
|
||||||
id: ERTMedicIDCard
|
id: ERTMedicIDCard
|
||||||
- type: CartridgeLoader
|
|
||||||
uiKey: enum.PdaUiKey.Key
|
|
||||||
preinstalled:
|
|
||||||
- CrewManifestCartridge
|
|
||||||
- NotekeeperCartridge
|
|
||||||
- NewsReaderCartridge
|
|
||||||
- MedTekCartridge
|
|
||||||
- WantedListCartridge
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ERTLeaderPDA
|
parent: ERTLeaderPDA
|
||||||
@@ -1019,6 +1032,13 @@
|
|||||||
borderColor: "#774705"
|
borderColor: "#774705"
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: pda-detective
|
state: pda-detective
|
||||||
|
- type: CartridgeLoader
|
||||||
|
preinstalled:
|
||||||
|
- CrewManifestCartridge
|
||||||
|
- NotekeeperCartridge
|
||||||
|
- NewsReaderCartridge
|
||||||
|
- WantedListCartridge
|
||||||
|
- LogProbeCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseMedicalPDA
|
parent: BaseMedicalPDA
|
||||||
@@ -1035,6 +1055,13 @@
|
|||||||
accentVColor: "#d7d7d0"
|
accentVColor: "#d7d7d0"
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: pda-brigmedic
|
state: pda-brigmedic
|
||||||
|
- type: CartridgeLoader
|
||||||
|
preinstalled:
|
||||||
|
- CrewManifestCartridge
|
||||||
|
- NotekeeperCartridge
|
||||||
|
- NewsReaderCartridge
|
||||||
|
- WantedListCartridge
|
||||||
|
- MedTekCartridge
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClownPDA
|
parent: ClownPDA
|
||||||
@@ -1151,11 +1178,3 @@
|
|||||||
preinstalled:
|
preinstalled:
|
||||||
- NotekeeperCartridge
|
- NotekeeperCartridge
|
||||||
- MedTekCartridge
|
- MedTekCartridge
|
||||||
cartridgeSlot:
|
|
||||||
priority: -1
|
|
||||||
name: Cartridge
|
|
||||||
ejectSound: /Audio/Machines/id_swipe.ogg
|
|
||||||
insertSound: /Audio/Machines/id_insert.ogg
|
|
||||||
whitelist:
|
|
||||||
components:
|
|
||||||
- Cartridge
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Blunt: 0
|
Blunt: 0
|
||||||
|
hidden: true
|
||||||
- type: PhysicalComposition
|
- type: PhysicalComposition
|
||||||
materialComposition:
|
materialComposition:
|
||||||
Cloth: 100
|
Cloth: 100
|
||||||
@@ -598,6 +599,11 @@
|
|||||||
path: /Audio/Effects/bite.ogg
|
path: /Audio/Effects/bite.ogg
|
||||||
angle: 0
|
angle: 0
|
||||||
animation: WeaponArcBite # Rrrr!
|
animation: WeaponArcBite # Rrrr!
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Payload
|
||||||
|
- ClothMade
|
||||||
|
- PlushieCarp
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: PlushieCarp
|
parent: PlushieCarp
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
density: 15
|
density: 15
|
||||||
mask:
|
mask:
|
||||||
- MachineMask
|
- MachineMask
|
||||||
- type: CargoPallet
|
|
||||||
palletType: All
|
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 100
|
price: 100
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
|||||||
@@ -71,3 +71,69 @@
|
|||||||
id: DefibrillatorOneHandedUnpowered
|
id: DefibrillatorOneHandedUnpowered
|
||||||
parent: BaseDefibrillator
|
parent: BaseDefibrillator
|
||||||
suffix: One-Handed, Unpowered
|
suffix: One-Handed, Unpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DefibrillatorCompact # This should be a research item at some point
|
||||||
|
parent: [ BaseDefibrillator, PowerCellSlotMediumItem ]
|
||||||
|
name: compact defibrillator
|
||||||
|
description: Now in fun size!
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/defibsmall.rsi
|
||||||
|
layers:
|
||||||
|
- state: icon
|
||||||
|
- state: screen
|
||||||
|
map: [ "enum.ToggleVisuals.Layer" ]
|
||||||
|
visible: false
|
||||||
|
shader: unshaded
|
||||||
|
- state: ready
|
||||||
|
map: ["enum.PowerDeviceVisualLayers.Powered"]
|
||||||
|
shader: unshaded
|
||||||
|
- type: Item
|
||||||
|
size: Normal
|
||||||
|
- type: ToggleCellDraw
|
||||||
|
- type: PowerCellDraw
|
||||||
|
useRate: 100
|
||||||
|
- type: Defibrillator
|
||||||
|
zapHeal:
|
||||||
|
types:
|
||||||
|
Asphyxiation: -40
|
||||||
|
doAfterDuration: 6
|
||||||
|
- type: DoAfter
|
||||||
|
- type: UseDelay
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DefibrillatorSyndicate
|
||||||
|
parent: DefibrillatorCompact
|
||||||
|
name: interdyne defibrillator
|
||||||
|
description: Doubles as a self-defense weapon against war-crime inclined tiders.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/defibsyndi.rsi
|
||||||
|
layers:
|
||||||
|
- state: icon
|
||||||
|
- state: screen
|
||||||
|
map: [ "enum.ToggleVisuals.Layer" ]
|
||||||
|
visible: false
|
||||||
|
shader: unshaded
|
||||||
|
- state: ready
|
||||||
|
map: ["enum.PowerDeviceVisualLayers.Powered"]
|
||||||
|
shader: unshaded
|
||||||
|
- type: MeleeWeapon
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 8
|
||||||
|
- type: ItemToggleMeleeWeapon
|
||||||
|
activatedSoundOnHit:
|
||||||
|
path: /Audio/Items/Defib/defib_zap.ogg
|
||||||
|
params:
|
||||||
|
variation: 0.250
|
||||||
|
activatedSoundOnHitNoDamage:
|
||||||
|
path: /Audio/Items/Defib/defib_zap.ogg
|
||||||
|
params:
|
||||||
|
variation: 0.250
|
||||||
|
volume: -10
|
||||||
|
activatedDamage:
|
||||||
|
types:
|
||||||
|
Blunt: 8
|
||||||
|
Shock: 16
|
||||||
|
|||||||
@@ -271,7 +271,6 @@
|
|||||||
transferAmount: 20
|
transferAmount: 20
|
||||||
onlyAffectsMobs: false
|
onlyAffectsMobs: false
|
||||||
injectOnly: true
|
injectOnly: true
|
||||||
|
|
||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
pen:
|
pen:
|
||||||
@@ -284,6 +283,102 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags: []
|
tags: []
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: puncturase auto-injector
|
||||||
|
parent: ChemicalMedipen
|
||||||
|
id: PunctAutoInjector
|
||||||
|
description: A rapid dose of puncturase and tranexamic acid, intended for combat applications.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/medipen.rsi
|
||||||
|
layers:
|
||||||
|
- state: punctpen
|
||||||
|
map: ["enum.SolutionContainerLayers.Fill"]
|
||||||
|
- type: SolutionContainerVisuals
|
||||||
|
maxFillLevels: 1
|
||||||
|
changeColor: false
|
||||||
|
emptySpriteName: punctpen_empty
|
||||||
|
- type: Hypospray
|
||||||
|
solutionName: pen
|
||||||
|
transferAmount: 15
|
||||||
|
onlyAffectsMobs: false
|
||||||
|
injectOnly: true
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
pen:
|
||||||
|
maxVol: 15
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Puncturase
|
||||||
|
Quantity: 10
|
||||||
|
- ReagentId: TranexamicAcid
|
||||||
|
Quantity: 5
|
||||||
|
- type: Tag
|
||||||
|
tags: []
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: pyrazine auto-injector
|
||||||
|
parent: ChemicalMedipen
|
||||||
|
id: PyraAutoInjector
|
||||||
|
description: A rapid dose of pyrazine and dermaline, intended for combat applications.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/medipen.rsi
|
||||||
|
layers:
|
||||||
|
- state: pyrapen
|
||||||
|
map: ["enum.SolutionContainerLayers.Fill"]
|
||||||
|
- type: SolutionContainerVisuals
|
||||||
|
maxFillLevels: 1
|
||||||
|
changeColor: false
|
||||||
|
emptySpriteName: pyrapen_empty
|
||||||
|
- type: Hypospray
|
||||||
|
solutionName: pen
|
||||||
|
transferAmount: 20
|
||||||
|
onlyAffectsMobs: false
|
||||||
|
injectOnly: true
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
pen:
|
||||||
|
maxVol: 20
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Pyrazine
|
||||||
|
Quantity: 10
|
||||||
|
- ReagentId: Dermaline
|
||||||
|
Quantity: 10
|
||||||
|
- type: Tag
|
||||||
|
tags: []
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: airloss auto-injector
|
||||||
|
parent: ChemicalMedipen
|
||||||
|
id: AirlossAutoInjector
|
||||||
|
description: A rapid dose of saline and dexalin plus, intended to get someone up quickly.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/medipen.rsi
|
||||||
|
layers:
|
||||||
|
- state: dexpen
|
||||||
|
map: ["enum.SolutionContainerLayers.Fill"]
|
||||||
|
- type: SolutionContainerVisuals
|
||||||
|
maxFillLevels: 1
|
||||||
|
changeColor: false
|
||||||
|
emptySpriteName: dexpen_empty
|
||||||
|
- type: Hypospray
|
||||||
|
solutionName: pen
|
||||||
|
transferAmount: 40
|
||||||
|
onlyAffectsMobs: false
|
||||||
|
injectOnly: true
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
pen:
|
||||||
|
maxVol: 40
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Saline
|
||||||
|
Quantity: 20
|
||||||
|
- ReagentId: DexalinPlus
|
||||||
|
Quantity: 20
|
||||||
|
- type: Tag
|
||||||
|
tags: []
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: space medipen
|
name: space medipen
|
||||||
parent: ChemicalMedipen
|
parent: ChemicalMedipen
|
||||||
|
|||||||
@@ -5,60 +5,65 @@
|
|||||||
description: A strange alien device.
|
description: A strange alien device.
|
||||||
abstract: true
|
abstract: true
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
drawdepth: SmallObjects
|
drawdepth: SmallObjects
|
||||||
sprite: Objects/Specific/Xenoarchaeology/xeno_artifacts.rsi
|
sprite: Objects/Specific/Xenoarchaeology/xeno_artifacts.rsi
|
||||||
noRot: true
|
noRot: true
|
||||||
layers:
|
layers:
|
||||||
- state: ano30
|
- state: ano30
|
||||||
map: [ "enum.ArtifactsVisualLayers.Base" ]
|
map: [ "enum.ArtifactsVisualLayers.Base" ]
|
||||||
- state: ano30_on
|
- state: ano30_on
|
||||||
map: [ "enum.ArtifactsVisualLayers.Effect" ]
|
map: [ "enum.ArtifactsVisualLayers.Effect" ]
|
||||||
visible: false
|
visible: false
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
- type: Transform
|
- type: Transform
|
||||||
noRot: true
|
noRot: true
|
||||||
- type: UserInterface #needs to be here for certain effects
|
- type: UserInterface #needs to be here for certain effects
|
||||||
interfaces:
|
interfaces:
|
||||||
enum.StorageUiKey.Key:
|
enum.StorageUiKey.Key:
|
||||||
type: StorageBoundUserInterface
|
type: StorageBoundUserInterface
|
||||||
enum.TransferAmountUiKey.Key:
|
enum.TransferAmountUiKey.Key:
|
||||||
type: TransferAmountBoundUserInterface
|
type: TransferAmountBoundUserInterface
|
||||||
enum.InstrumentUiKey.Key:
|
enum.InstrumentUiKey.Key:
|
||||||
type: InstrumentBoundUserInterface
|
type: InstrumentBoundUserInterface
|
||||||
enum.IntercomUiKey.Key:
|
enum.IntercomUiKey.Key:
|
||||||
type: IntercomBoundUserInterface
|
type: IntercomBoundUserInterface
|
||||||
- type: Reactive
|
- type: Reactive
|
||||||
groups:
|
groups:
|
||||||
Acidic: [Touch]
|
Acidic: [Touch]
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
shape:
|
shape:
|
||||||
!type:PhysShapeCircle
|
!type:PhysShapeCircle
|
||||||
radius: 0.45
|
radius: 0.45
|
||||||
density: 75
|
density: 75
|
||||||
layer: # doesn't collide with artifact storage
|
layer: # doesn't collide with artifact storage
|
||||||
- Opaque
|
- Opaque
|
||||||
mask:
|
mask:
|
||||||
- MachineMask
|
- MachineMask
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Artifact
|
- type: Artifact
|
||||||
- type: RandomArtifactSprite
|
- type: RandomArtifactSprite
|
||||||
maxSprite: 36
|
maxSprite: 36
|
||||||
- type: RandomSprite
|
- type: RandomSprite
|
||||||
available:
|
available:
|
||||||
- enum.ArtifactsVisualLayers.Effect:
|
- enum.ArtifactsVisualLayers.Effect:
|
||||||
ano01_on: Rainbow
|
ano01_on: Rainbow
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: Actions
|
- type: Actions
|
||||||
- type: GuideHelp
|
- type: GuideHelp
|
||||||
guides:
|
guides:
|
||||||
- Xenoarchaeology
|
- Xenoarchaeology
|
||||||
- type: StealTarget
|
- type: StealTarget
|
||||||
stealGroup: XenoArtifact
|
stealGroup: XenoArtifact
|
||||||
|
- type: ContainerContainer
|
||||||
|
containers:
|
||||||
|
storagebase: !type:Container # needed for the EffectStorage artifactEffect
|
||||||
|
ents: [ ]
|
||||||
|
revolver-ammo: !type:Container # needed for the EffectBigIron artifactEffect
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseXenoArtifact
|
parent: BaseXenoArtifact
|
||||||
|
|||||||
@@ -543,12 +543,8 @@
|
|||||||
solutions:
|
solutions:
|
||||||
food:
|
food:
|
||||||
maxVol: 20
|
maxVol: 20
|
||||||
- type: SolutionSpiker
|
- type: ExplosionResistance
|
||||||
sourceSolution: food
|
damageCoefficient: 0.025 # survives conventional explosives but not minibombs and nukes
|
||||||
- type: Extractable
|
|
||||||
grindableSolutionName: food
|
|
||||||
- type: StaticPrice
|
|
||||||
price: 0
|
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
@@ -561,6 +557,12 @@
|
|||||||
solution: food
|
solution: food
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: SolutionSpiker
|
||||||
|
sourceSolution: food
|
||||||
|
- type: Extractable
|
||||||
|
grindableSolutionName: food
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Pill
|
- Pill
|
||||||
@@ -588,4 +590,7 @@
|
|||||||
areaInsertRadius: 1
|
areaInsertRadius: 1
|
||||||
storageInsertSound: /Audio/Effects/pill_insert.ogg
|
storageInsertSound: /Audio/Effects/pill_insert.ogg
|
||||||
storageRemoveSound: /Audio/Effects/pill_remove.ogg
|
storageRemoveSound: /Audio/Effects/pill_remove.ogg
|
||||||
|
whitelist:
|
||||||
|
tags:
|
||||||
|
- Pill
|
||||||
- type: Dumpable
|
- type: Dumpable
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WeaponWaterGunBase
|
id: WeaponWaterGunBase
|
||||||
abstract: true
|
abstract: true
|
||||||
parent: BaseItem
|
parent: BaseItem
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
id: WeaponWaterBlaster
|
id: WeaponWaterBlaster
|
||||||
parent: WeaponWaterGunBase
|
parent: WeaponWaterGunBase
|
||||||
name: water blaster
|
name: water blaster
|
||||||
description: With this bad boy, you'll be the cooleste kid at the summer barbecue.
|
description: With this bad boy, you'll be the coolest kid at the summer barbecue.
|
||||||
components:
|
components:
|
||||||
- type: Gun
|
- type: Gun
|
||||||
cameraRecoilScalar: 0 #no recoil
|
cameraRecoilScalar: 0 #no recoil
|
||||||
|
|||||||
@@ -103,6 +103,9 @@
|
|||||||
Slash: 10
|
Slash: 10
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Weapons/Melee/combat_knife.rsi
|
sprite: Objects/Weapons/Melee/combat_knife.rsi
|
||||||
|
storedSprite:
|
||||||
|
state: storage
|
||||||
|
sprite: Objects/Weapons/Melee/combat_knife.rsi
|
||||||
- type: DisarmMalus
|
- type: DisarmMalus
|
||||||
malus: 0.225
|
malus: 0.225
|
||||||
|
|
||||||
@@ -117,6 +120,9 @@
|
|||||||
state: icon
|
state: icon
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Weapons/Melee/survival_knife.rsi
|
sprite: Objects/Weapons/Melee/survival_knife.rsi
|
||||||
|
storedSprite:
|
||||||
|
state: storage
|
||||||
|
sprite: Objects/Weapons/Melee/survival_knife.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: kukri knife
|
name: kukri knife
|
||||||
|
|||||||
@@ -149,6 +149,7 @@
|
|||||||
- type: GunRequiresWield
|
- type: GunRequiresWield
|
||||||
- type: Item
|
- type: Item
|
||||||
size: Ginormous
|
size: Ginormous
|
||||||
|
sprite: Objects/Weapons/Melee/crusher-inhands.rsi
|
||||||
- type: DisarmMalus
|
- type: DisarmMalus
|
||||||
- type: Prying
|
- type: Prying
|
||||||
|
|
||||||
@@ -191,3 +192,6 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Pickaxe
|
- Pickaxe
|
||||||
|
- type: Item
|
||||||
|
size: Ginormous
|
||||||
|
sprite: Objects/Weapons/Melee/crusher_glaive-inhands.rsi
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
- type: RCDDeconstructable
|
- type: RCDDeconstructable
|
||||||
cost: 4
|
cost: 4
|
||||||
delay: 2
|
delay: 2
|
||||||
fx: EffectRCDDeconstruct2
|
fx: EffectRCDDeconstruct2
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
snap:
|
snap:
|
||||||
- Wallmount
|
- Wallmount
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: light
|
name: light
|
||||||
description: "A light fixture. Draws power and produces light when equipped with a light tube."
|
description: "A light fixture. Draws power and produces light when equipped with a light tube."
|
||||||
@@ -400,6 +400,37 @@
|
|||||||
shader: "unshaded"
|
shader: "unshaded"
|
||||||
visible: false
|
visible: false
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
|
- type: Construction
|
||||||
|
graph: LightFixture
|
||||||
|
node: emergencyLight
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 100
|
||||||
|
behaviors: #excess damage, don't spawn entities.
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
|
- !type:PlaySoundBehavior
|
||||||
|
sound:
|
||||||
|
collection: GlassBreak
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 25
|
||||||
|
behaviors:
|
||||||
|
- !type:SpawnEntitiesBehavior
|
||||||
|
spawn:
|
||||||
|
SheetSteel1:
|
||||||
|
min: 1
|
||||||
|
max: 1
|
||||||
|
ShardGlass:
|
||||||
|
min: 1
|
||||||
|
max: 1
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: ["Destruction"]
|
||||||
|
- !type:PlaySoundBehavior
|
||||||
|
sound:
|
||||||
|
collection: GlassBreak
|
||||||
placement:
|
placement:
|
||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
snap:
|
snap:
|
||||||
|
|||||||
@@ -163,6 +163,7 @@
|
|||||||
- FoodPlateSmallPlastic
|
- FoodPlateSmallPlastic
|
||||||
- FoodBowlBig
|
- FoodBowlBig
|
||||||
- FoodPlateTin
|
- FoodPlateTin
|
||||||
|
- FoodPlateMuffinTin
|
||||||
- FoodKebabSkewer
|
- FoodKebabSkewer
|
||||||
- SprayBottle
|
- SprayBottle
|
||||||
- MopItem
|
- MopItem
|
||||||
|
|||||||
@@ -47,19 +47,30 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- PlushieSharkGrey
|
- PlushieSharkGrey
|
||||||
sprite: Objects/Fun/sharkplush.rsi
|
mopbucket_carpplush:
|
||||||
|
whitelist:
|
||||||
|
tags:
|
||||||
|
- PlushieCarp
|
||||||
|
sprite: Objects/Specific/Janitorial/janitorial.rsi
|
||||||
- type: Transform
|
- type: Transform
|
||||||
noRot: true
|
noRot: true
|
||||||
- type: ItemSlots
|
- type: ItemSlots
|
||||||
slots:
|
slots:
|
||||||
shark_slot:
|
item_slot:
|
||||||
name: mop-bucket-slot-component-slot-name-shark
|
name: mop-bucket-slot-component-slot-name-item
|
||||||
|
ejectVerbText: mop-bucket-slot-component-eject-verb
|
||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- PlushieSharkBlue
|
- PlushieSharkBlue
|
||||||
- PlushieSharkPink
|
- PlushieSharkPink
|
||||||
- PlushieSharkGrey
|
- PlushieSharkGrey
|
||||||
|
- PlushieCarp
|
||||||
|
components:
|
||||||
|
- Rehydratable
|
||||||
priority: 3 # Higher than drinking priority
|
priority: 3 # Higher than drinking priority
|
||||||
|
- type: ReactiveContainer
|
||||||
|
solution: bucket
|
||||||
|
container: item_slot
|
||||||
- type: Drink
|
- type: Drink
|
||||||
solution: bucket
|
solution: bucket
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
@@ -70,7 +81,7 @@
|
|||||||
containers:
|
containers:
|
||||||
storagebase: !type:Container
|
storagebase: !type:Container
|
||||||
ents: []
|
ents: []
|
||||||
shark_slot: !type:ContainerSlot {}
|
item_slot: !type:ContainerSlot {}
|
||||||
- type: GuideHelp
|
- type: GuideHelp
|
||||||
guides:
|
guides:
|
||||||
- Janitorial
|
- Janitorial
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
isCollidableWhenOpen: false
|
isCollidableWhenOpen: false
|
||||||
openOnMove: false
|
openOnMove: false
|
||||||
airtight: false
|
airtight: false
|
||||||
capacity: 4 #4 Entities seems like a nice comfy fit for a cardboard box.
|
capacity: 5 #5 entity capacity to fit all of your friends (or teammates on your nuclear operation without reinforcements).
|
||||||
- type: ContainerContainer
|
- type: ContainerContainer
|
||||||
containers:
|
containers:
|
||||||
entity_storage: !type:Container
|
entity_storage: !type:Container
|
||||||
|
|||||||
@@ -64,8 +64,8 @@
|
|||||||
canEditLabel: true
|
canEditLabel: true
|
||||||
- type: TextScreenVisuals
|
- type: TextScreenVisuals
|
||||||
color: FloralWhite
|
color: FloralWhite
|
||||||
textOffset: 0,8
|
textOffset: 0,6
|
||||||
timerOffset: 0,8
|
timerOffset: 0,6
|
||||||
textLength: 5
|
textLength: 5
|
||||||
rows: 1
|
rows: 1
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
baseOdds: 0.036
|
baseOdds: 0.036
|
||||||
appliesToProduce: false
|
appliesToProduce: false
|
||||||
effect: !type:PlantSpeciesChange
|
effect: !type:PlantSpeciesChange
|
||||||
|
persists: false
|
||||||
- name: Unviable
|
- name: Unviable
|
||||||
baseOdds: 0.109
|
baseOdds: 0.109
|
||||||
persists: false
|
persists: false
|
||||||
|
|||||||
@@ -21,6 +21,13 @@
|
|||||||
back:
|
back:
|
||||||
- ClothingHeadHatHairflower
|
- ClothingHeadHatHairflower
|
||||||
|
|
||||||
|
# Headphones
|
||||||
|
- type: loadout
|
||||||
|
id: Headphones
|
||||||
|
storage:
|
||||||
|
back:
|
||||||
|
- ClothingNeckHeadphones
|
||||||
|
|
||||||
# Plushies
|
# Plushies
|
||||||
- type: loadout
|
- type: loadout
|
||||||
id: PlushieLizard
|
id: PlushieLizard
|
||||||
@@ -165,7 +172,7 @@
|
|||||||
!type:OverallPlaytimeRequirement
|
!type:OverallPlaytimeRequirement
|
||||||
time: 36000 # 10hr
|
time: 36000 # 10hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorWhite
|
- TowelColorWhite
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -176,9 +183,9 @@
|
|||||||
!type:OverallPlaytimeRequirement
|
!type:OverallPlaytimeRequirement
|
||||||
time: 1800000 # 500hr
|
time: 1800000 # 500hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorSilver
|
- TowelColorSilver
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
id: TowelColorGold
|
id: TowelColorGold
|
||||||
effects:
|
effects:
|
||||||
@@ -187,7 +194,7 @@
|
|||||||
!type:OverallPlaytimeRequirement
|
!type:OverallPlaytimeRequirement
|
||||||
time: 3600000 # 1000hr
|
time: 3600000 # 1000hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorGold
|
- TowelColorGold
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -199,7 +206,7 @@
|
|||||||
department: Cargo
|
department: Cargo
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorLightBrown
|
- TowelColorLightBrown
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -211,7 +218,7 @@
|
|||||||
department: Civilian
|
department: Civilian
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorGreen
|
- TowelColorGreen
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -223,7 +230,7 @@
|
|||||||
department: Command
|
department: Command
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorDarkBlue
|
- TowelColorDarkBlue
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -235,9 +242,9 @@
|
|||||||
department: Engineering
|
department: Engineering
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorOrange
|
- TowelColorOrange
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
id: TowelColorLightBlue
|
id: TowelColorLightBlue
|
||||||
effects:
|
effects:
|
||||||
@@ -247,7 +254,7 @@
|
|||||||
department: Medical
|
department: Medical
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorLightBlue
|
- TowelColorLightBlue
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -259,7 +266,7 @@
|
|||||||
department: Science
|
department: Science
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorPurple
|
- TowelColorPurple
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -271,7 +278,7 @@
|
|||||||
department: Security
|
department: Security
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorRed
|
- TowelColorRed
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -283,7 +290,7 @@
|
|||||||
role: JobPassenger
|
role: JobPassenger
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorGray
|
- TowelColorGray
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -295,7 +302,7 @@
|
|||||||
role: JobChaplain
|
role: JobChaplain
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorBlack
|
- TowelColorBlack
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -307,7 +314,7 @@
|
|||||||
role: JobLibrarian
|
role: JobLibrarian
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorDarkGreen
|
- TowelColorDarkGreen
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -319,7 +326,7 @@
|
|||||||
role: JobLawyer
|
role: JobLawyer
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorMaroon
|
- TowelColorMaroon
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -331,7 +338,7 @@
|
|||||||
role: JobClown
|
role: JobClown
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorYellow
|
- TowelColorYellow
|
||||||
|
|
||||||
- type: loadout
|
- type: loadout
|
||||||
@@ -343,5 +350,5 @@
|
|||||||
role: JobMime
|
role: JobMime
|
||||||
time: 360000 # 100hr
|
time: 360000 # 100hr
|
||||||
storage:
|
storage:
|
||||||
back:
|
back:
|
||||||
- TowelColorMime
|
- TowelColorMime
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
loadouts:
|
loadouts:
|
||||||
- FlowerWreath
|
- FlowerWreath
|
||||||
- Hairflower
|
- Hairflower
|
||||||
|
- Headphones
|
||||||
- PlushieLizard
|
- PlushieLizard
|
||||||
- PlushieSpaceLizard
|
- PlushieSpaceLizard
|
||||||
- Lighter
|
- Lighter
|
||||||
@@ -42,7 +43,6 @@
|
|||||||
- TowelColorPurple
|
- TowelColorPurple
|
||||||
- TowelColorRed
|
- TowelColorRed
|
||||||
- TowelColorSilver
|
- TowelColorSilver
|
||||||
- TowelColorLightBlue
|
|
||||||
- TowelColorWhite
|
- TowelColorWhite
|
||||||
- TowelColorYellow
|
- TowelColorYellow
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,14 @@
|
|||||||
- material: Steel
|
- material: Steel
|
||||||
amount: 1
|
amount: 1
|
||||||
doAfter: 2.0
|
doAfter: 2.0
|
||||||
|
- to: emergencyLight
|
||||||
|
steps:
|
||||||
|
- material: Steel
|
||||||
|
amount: 1
|
||||||
|
doAfter: 1.0
|
||||||
|
- material: Glass
|
||||||
|
amount: 1
|
||||||
|
doAfter: 1.0
|
||||||
- node: tubeLight
|
- node: tubeLight
|
||||||
entity: PoweredlightEmpty
|
entity: PoweredlightEmpty
|
||||||
edges:
|
edges:
|
||||||
@@ -83,4 +91,19 @@
|
|||||||
- !type:SpawnPrototype
|
- !type:SpawnPrototype
|
||||||
prototype: SheetSteel1
|
prototype: SheetSteel1
|
||||||
amount: 1
|
amount: 1
|
||||||
- !type:DeleteEntity {}
|
- !type:DeleteEntity {}
|
||||||
|
- node: emergencyLight
|
||||||
|
entity: EmergencyLight
|
||||||
|
edges:
|
||||||
|
- to: start
|
||||||
|
steps:
|
||||||
|
- tool: Screwing
|
||||||
|
doAfter: 2.0
|
||||||
|
completed:
|
||||||
|
- !type:SpawnPrototype
|
||||||
|
prototype: SheetSteel1
|
||||||
|
amount: 1
|
||||||
|
- !type:SpawnPrototype
|
||||||
|
prototype: SheetGlass1
|
||||||
|
amount: 1
|
||||||
|
- !type:DeleteEntity {}
|
||||||
|
|||||||
@@ -1456,6 +1456,24 @@
|
|||||||
# Same here. - 20kdc
|
# Same here. - 20kdc
|
||||||
- !type:TileNotBlocked
|
- !type:TileNotBlocked
|
||||||
|
|
||||||
|
- type: construction
|
||||||
|
name: emergency light
|
||||||
|
id: EmergencyLightFixture
|
||||||
|
graph: LightFixture
|
||||||
|
startNode: start
|
||||||
|
targetNode: emergencyLight
|
||||||
|
category: construction-category-structures
|
||||||
|
description: An emergency light.
|
||||||
|
icon:
|
||||||
|
sprite: Structures/Wallmounts/Lighting/emergency_light.rsi
|
||||||
|
state: base
|
||||||
|
objectType: Structure
|
||||||
|
placementMode: SnapgridCenter
|
||||||
|
canRotate: true
|
||||||
|
canBuildInImpassable: false
|
||||||
|
conditions:
|
||||||
|
- !type:TileNotBlocked
|
||||||
|
|
||||||
- type: construction
|
- type: construction
|
||||||
name: ground light post
|
name: ground light post
|
||||||
id: LightGroundFixture
|
id: LightGroundFixture
|
||||||
|
|||||||
@@ -1779,6 +1779,67 @@
|
|||||||
FoodOrange: 1
|
FoodOrange: 1
|
||||||
FoodAmbrosiaVulgaris: 1
|
FoodAmbrosiaVulgaris: 1
|
||||||
|
|
||||||
|
# Muffins
|
||||||
|
|
||||||
|
- type: microwaveMealRecipe
|
||||||
|
id: RecipeMuffin
|
||||||
|
name: muffin recipe
|
||||||
|
result: FoodBakedMuffin
|
||||||
|
time: 15
|
||||||
|
solids:
|
||||||
|
FoodPlateMuffinTin: 1
|
||||||
|
FoodDoughSlice: 1
|
||||||
|
reagents:
|
||||||
|
Sugar: 10
|
||||||
|
|
||||||
|
- type: microwaveMealRecipe
|
||||||
|
id: RecipeMuffinChocolate
|
||||||
|
name: chocolate muffin recipe
|
||||||
|
result: FoodBakedMuffinChocolate
|
||||||
|
time: 15
|
||||||
|
solids:
|
||||||
|
FoodPlateMuffinTin: 1
|
||||||
|
FoodDoughSlice: 1
|
||||||
|
FoodSnackChocolateBar: 1
|
||||||
|
reagents:
|
||||||
|
Sugar: 10
|
||||||
|
|
||||||
|
- type: microwaveMealRecipe
|
||||||
|
id: RecipeMuffinBerry
|
||||||
|
name: berry muffin recipe
|
||||||
|
result: FoodBakedMuffinBerry
|
||||||
|
time: 15
|
||||||
|
solids:
|
||||||
|
FoodPlateMuffinTin: 1
|
||||||
|
FoodDoughSlice: 1
|
||||||
|
FoodBerries: 1
|
||||||
|
reagents:
|
||||||
|
Sugar: 10
|
||||||
|
|
||||||
|
- type: microwaveMealRecipe
|
||||||
|
id: RecipeMuffinBanana
|
||||||
|
name: banana muffin recipe
|
||||||
|
result: FoodBakedMuffinBanana
|
||||||
|
time: 15
|
||||||
|
solids:
|
||||||
|
FoodPlateMuffinTin: 1
|
||||||
|
FoodDoughSlice: 1
|
||||||
|
FoodBanana: 1
|
||||||
|
reagents:
|
||||||
|
Sugar: 10
|
||||||
|
|
||||||
|
- type: microwaveMealRecipe
|
||||||
|
id: RecipeMuffinCherry
|
||||||
|
name: cherry muffin recipe
|
||||||
|
result: FoodBakedMuffinCherry
|
||||||
|
time: 15
|
||||||
|
solids:
|
||||||
|
FoodPlateMuffinTin: 1
|
||||||
|
FoodDoughSlice: 1
|
||||||
|
FoodCherry: 3
|
||||||
|
reagents:
|
||||||
|
Sugar: 10
|
||||||
|
|
||||||
# NOT ACTUAL FOOD
|
# NOT ACTUAL FOOD
|
||||||
|
|
||||||
- type: microwaveMealRecipe
|
- type: microwaveMealRecipe
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
steps:
|
steps:
|
||||||
- material: Cloth
|
- material: Cloth
|
||||||
amount: 2
|
amount: 2
|
||||||
doAfter: 10
|
doAfter: 3
|
||||||
- node: gauze
|
- node: gauze
|
||||||
entity: Gauze1
|
entity: Gauze1
|
||||||
|
|||||||
@@ -41,13 +41,13 @@
|
|||||||
- material: WebSilk
|
- material: WebSilk
|
||||||
amount: 12
|
amount: 12
|
||||||
doAfter: 6
|
doAfter: 6
|
||||||
|
|
||||||
- to: boots
|
- to: boots
|
||||||
steps:
|
steps:
|
||||||
- material: WebSilk
|
- material: WebSilk
|
||||||
amount: 2
|
amount: 2
|
||||||
doAfter: 4
|
doAfter: 4
|
||||||
|
|
||||||
# Deconstruction
|
# Deconstruction
|
||||||
- node: tile
|
- node: tile
|
||||||
entity: FloorTileItemWeb
|
entity: FloorTileItemWeb
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
|
# Base prototypes
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: MiniHoe
|
abstract: true
|
||||||
result: HydroponicsToolMiniHoe
|
parent: BaseToolRecipe
|
||||||
completetime: 2
|
id: BaseHydroToolRecipe
|
||||||
materials:
|
materials:
|
||||||
Steel: 200
|
Steel: 200
|
||||||
Plastic: 100
|
Plastic: 100
|
||||||
|
|
||||||
|
# Recipes
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: BaseHydroToolRecipe
|
||||||
|
id: HydroponicsToolMiniHoe
|
||||||
|
result: HydroponicsToolMiniHoe
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
parent: BaseHydroToolRecipe
|
||||||
id: HydroponicsToolScythe
|
id: HydroponicsToolScythe
|
||||||
result: HydroponicsToolScythe
|
result: HydroponicsToolScythe
|
||||||
completetime: 2
|
|
||||||
materials:
|
materials:
|
||||||
Steel: 300
|
Steel: 300
|
||||||
Plastic: 200
|
Plastic: 200
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: BaseHydroToolRecipe
|
||||||
id: HydroponicsToolHatchet
|
id: HydroponicsToolHatchet
|
||||||
result: HydroponicsToolHatchet
|
result: HydroponicsToolHatchet
|
||||||
completetime: 2
|
|
||||||
materials:
|
|
||||||
Steel: 200
|
|
||||||
Plastic: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: Spade
|
parent: BaseHydroToolRecipe
|
||||||
|
id: HydroponicsToolSpade
|
||||||
result: HydroponicsToolSpade
|
result: HydroponicsToolSpade
|
||||||
completetime: 2
|
|
||||||
materials:
|
|
||||||
Steel: 200
|
|
||||||
Plastic: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: Clippers
|
parent: BaseHydroToolRecipe
|
||||||
|
id: HydroponicsToolClippers
|
||||||
result: HydroponicsToolClippers
|
result: HydroponicsToolClippers
|
||||||
completetime: 2
|
|
||||||
materials:
|
|
||||||
Steel: 200
|
|
||||||
Plastic: 100
|
|
||||||
|
|||||||
@@ -1,67 +1,65 @@
|
|||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: BaseToolRecipe
|
||||||
id: ButchCleaver
|
id: ButchCleaver
|
||||||
result: ButchCleaver
|
result: ButchCleaver
|
||||||
completetime: 2
|
|
||||||
materials:
|
materials:
|
||||||
Steel: 300
|
Steel: 300
|
||||||
Plastic: 50
|
Plastic: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: BaseToolRecipe
|
||||||
id: KitchenKnife
|
id: KitchenKnife
|
||||||
result: KitchenKnife
|
result: KitchenKnife
|
||||||
completetime: 2
|
|
||||||
materials:
|
materials:
|
||||||
Steel: 200
|
Steel: 200
|
||||||
Plastic: 50
|
Plastic: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: DrinkMug
|
abstract: true
|
||||||
result: DrinkMug
|
id: BaseGlasswareRecipe
|
||||||
completetime: 0.8
|
completetime: 0.8
|
||||||
materials:
|
materials:
|
||||||
Glass: 100
|
Glass: 100
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: BaseGlasswareRecipe
|
||||||
|
id: DrinkMug
|
||||||
|
result: DrinkMug
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
parent: DrinkMug
|
||||||
id: DrinkMugMetal
|
id: DrinkMugMetal
|
||||||
result: DrinkMugMetal
|
result: DrinkMugMetal
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
materials:
|
||||||
Steel: 100
|
Steel: 100
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: DrinkMug
|
||||||
id: DrinkGlass
|
id: DrinkGlass
|
||||||
result: DrinkGlass
|
result: DrinkGlass
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
|
||||||
Glass: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: DrinkMug
|
||||||
id: DrinkShotGlass
|
id: DrinkShotGlass
|
||||||
result: DrinkShotGlass
|
result: DrinkShotGlass
|
||||||
completetime: 0.4
|
completetime: 0.4
|
||||||
materials:
|
|
||||||
Glass: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: DrinkMug
|
||||||
id: DrinkGlassCoupeShaped
|
id: DrinkGlassCoupeShaped
|
||||||
result: DrinkGlassCoupeShaped
|
result: DrinkGlassCoupeShaped
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
|
||||||
Glass: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
|
||||||
id: CustomDrinkJug
|
|
||||||
result: CustomDrinkJug
|
|
||||||
completetime: 2
|
|
||||||
materials:
|
|
||||||
Plastic: 200
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
id: CustomDrinkJug
|
||||||
|
result: CustomDrinkJug
|
||||||
|
completetime: 2
|
||||||
|
materials:
|
||||||
|
Plastic: 200
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
parent: BaseGlasswareRecipe
|
||||||
id: FoodPlate
|
id: FoodPlate
|
||||||
result: FoodPlate
|
result: FoodPlate
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
|
||||||
Glass: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: FoodPlateSmall
|
id: FoodPlateSmall
|
||||||
@@ -71,25 +69,23 @@
|
|||||||
Glass: 50
|
Glass: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: FoodPlate
|
||||||
id: FoodPlatePlastic
|
id: FoodPlatePlastic
|
||||||
result: FoodPlatePlastic
|
result: FoodPlatePlastic
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
materials:
|
||||||
Plastic: 100
|
Plastic: 100
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: FoodPlateSmall
|
||||||
id: FoodPlateSmallPlastic
|
id: FoodPlateSmallPlastic
|
||||||
result: FoodPlateSmallPlastic
|
result: FoodPlateSmallPlastic
|
||||||
completetime: 0.4
|
|
||||||
materials:
|
materials:
|
||||||
Plastic: 50
|
Plastic: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
|
parent: FoodPlate
|
||||||
id: FoodBowlBig
|
id: FoodBowlBig
|
||||||
result: FoodBowlBig
|
result: FoodBowlBig
|
||||||
completetime: 0.8
|
|
||||||
materials:
|
|
||||||
Glass: 100
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: FoodPlateTin
|
id: FoodPlateTin
|
||||||
@@ -98,6 +94,13 @@
|
|||||||
materials:
|
materials:
|
||||||
Steel: 100
|
Steel: 100
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
parent: FoodPlateTin
|
||||||
|
id: FoodPlateMuffinTin
|
||||||
|
result: FoodPlateMuffinTin
|
||||||
|
materials:
|
||||||
|
Steel: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: FoodKebabSkewer
|
id: FoodKebabSkewer
|
||||||
result: FoodKebabSkewer
|
result: FoodKebabSkewer
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user