Merge remote-tracking branch 'upstream/master' into upstream-sync

# Conflicts:
#	Content.Client/Preferences/UI/HumanoidProfileEditor.xaml
#	Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
#	Resources/Prototypes/Species/slime.yml
#	Resources/Textures/Interface/Actions/meta.json
#	Resources/Textures/Interface/Alerts/human_alive.rsi/health4.png
#	Resources/Textures/Interface/Alerts/human_alive.rsi/meta.json
#	Resources/Textures/Structures/Piping/disposal.rsi/conmailing.png
#	Resources/Textures/Structures/Piping/disposal.rsi/mailing-charging.png
#	Resources/Textures/Structures/Piping/disposal.rsi/mailing-flush.png
#	Resources/Textures/Structures/Piping/disposal.rsi/mailing.png
#	Resources/Textures/Structures/Piping/disposal.rsi/mailover-handle.png
#	Resources/Textures/Structures/Piping/disposal.rsi/meta.json
This commit is contained in:
Morb0 2024-01-03 13:37:55 +03:00
commit fd12440582
169 changed files with 5410 additions and 4184 deletions

View file

@ -0,0 +1,48 @@
using Content.Shared.Construction;
using Content.Shared.Construction.Components;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.Client.Construction;
/// <inheritdoc/>
public sealed class FlatpackSystem : SharedFlatpackSystem
{
[Dependency] private readonly AppearanceSystem _appearance = default!;
/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FlatpackComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(Entity<FlatpackComponent> ent, ref AppearanceChangeEvent args)
{
var (_, comp) = ent;
if (!_appearance.TryGetData<string>(ent, FlatpackVisuals.Machine, out var machineBoardId) || args.Sprite == null)
return;
if (!PrototypeManager.TryIndex<EntityPrototype>(machineBoardId, out var machineBoardPrototype))
return;
if (!machineBoardPrototype.TryGetComponent<SpriteComponent>(out var sprite))
return;
Color? color = null;
foreach (var layer in sprite.AllLayers)
{
if (layer.RsiState.Name is not { } spriteState)
continue;
if (!comp.BoardColors.TryGetValue(spriteState, out var c))
continue;
color = c;
break;
}
if (color != null)
args.Sprite.LayerSetColor(FlatpackVisualLayers.Overlay, color.Value);
}
}

View file

@ -0,0 +1,40 @@
using Content.Shared.Construction.Components;
using JetBrains.Annotations;
namespace Content.Client.Construction.UI
{
[UsedImplicitly]
public sealed class FlatpackCreatorBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private FlatpackCreatorMenu? _menu;
public FlatpackCreatorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = new FlatpackCreatorMenu(Owner);
_menu.OnClose += Close;
_menu.PackButtonPressed += () =>
{
SendMessage(new FlatpackCreatorStartPackBuiMessage());
};
_menu.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}
}

View file

@ -0,0 +1,43 @@
<controls:FancyWindow
xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:ui="clr-namespace:Content.Client.Materials.UI"
Title="{Loc 'flatpacker-ui-title'}"
MinSize="550 350">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True" Margin="10">
<BoxContainer SizeFlagsStretchRatio="2" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical">
<SpriteView Name="MachineSprite" Scale="4 4" HorizontalAlignment="Center" MinSize="128 128"/>
<RichTextLabel Name="MachineNameLabel" HorizontalAlignment="Center" StyleClasses="LabelKeyText"/>
</BoxContainer>
<Control MinHeight="10"/>
<Button Name="PackButton" Text="{Loc 'flatpacker-ui-pack-button'}" MaxWidth="150" Margin="0 0 0 10"/>
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<Label Name="CostHeaderLabel" Text="{Loc 'flatpacker-ui-cost-label'}" HorizontalAlignment="Left"/>
<PanelContainer VerticalExpand="True"
HorizontalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<RichTextLabel Name="CostLabel" HorizontalAlignment="Center"/>
</BoxContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
<Control MinWidth="10"/>
<BoxContainer SizeFlagsStretchRatio="3" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<Label Text="{Loc 'flatpacker-ui-materials-label'}" HorizontalAlignment="Center" Margin="0 0 0 5"/>
<PanelContainer
VerticalExpand="True"
HorizontalExpand="True"
RectClipContent="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
</PanelContainer.PanelOverride>
<ui:MaterialStorageControl Name="MaterialStorageControl"/>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View file

@ -0,0 +1,147 @@
using System.Linq;
using Content.Client.Materials;
using Content.Client.Message;
using Content.Client.UserInterface.Controls;
using Content.Shared.Construction.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Materials;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Construction.UI;
[GenerateTypedNameReferences]
public sealed partial class FlatpackCreatorMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly ItemSlotsSystem _itemSlots;
private readonly FlatpackSystem _flatpack;
private readonly MaterialStorageSystem _materialStorage;
private readonly SpriteSystem _spriteSystem;
private readonly EntityUid _owner;
private EntityUid? _currentBoard = EntityUid.Invalid;
private EntityUid? _machinePreview;
public event Action? PackButtonPressed;
public FlatpackCreatorMenu(EntityUid uid)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_itemSlots = _entityManager.System<ItemSlotsSystem>();
_flatpack = _entityManager.System<FlatpackSystem>();
_materialStorage = _entityManager.System<MaterialStorageSystem>();
_spriteSystem = _entityManager.System<SpriteSystem>();
_owner = uid;
PackButton.OnPressed += _ => PackButtonPressed?.Invoke();
MaterialStorageControl.SetOwner(uid);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_machinePreview is not { } && _entityManager.Deleted(_machinePreview))
{
_machinePreview = null;
MachineSprite.SetEntity(_machinePreview);
}
if (!_entityManager.TryGetComponent<FlatpackCreatorComponent>(_owner, out var flatpacker) ||
!_itemSlots.TryGetSlot(_owner, flatpacker.SlotId, out var itemSlot))
return;
if (flatpacker.Packing)
{
PackButton.Disabled = true;
}
else if (_currentBoard != null)
{
//todo double trycomp is kinda stinky.
if (_entityManager.TryGetComponent<MachineBoardComponent>(_currentBoard, out var board) &&
board.Prototype != null)
{
var cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker),
(_currentBoard.Value, board));
PackButton.Disabled = !_materialStorage.CanChangeMaterialAmount(_owner, cost);
}
}
if (_currentBoard == itemSlot.Item)
return;
if (_machinePreview != null)
_entityManager.DeleteEntity(_machinePreview);
_currentBoard = itemSlot.Item;
CostHeaderLabel.Visible = _currentBoard != null;
if (_currentBoard != null &&
_entityManager.TryGetComponent<MachineBoardComponent>(_currentBoard, out var machineBoard) &&
machineBoard.Prototype != null)
{
var proto = _prototypeManager.Index<EntityPrototype>(machineBoard.Prototype);
_machinePreview = _entityManager.Spawn(proto.ID);
_spriteSystem.ForceUpdate(_machinePreview.Value);
MachineNameLabel.SetMessage(proto.Name);
var cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker),
(_currentBoard.Value, machineBoard));
CostLabel.SetMarkup(GetCostString(cost));
}
else
{
_machinePreview = null;
MachineNameLabel.SetMessage(" ");
CostLabel.SetMessage(Loc.GetString("flatpacker-ui-no-board-label"));
PackButton.Disabled = true;
}
MachineSprite.SetEntity(_machinePreview);
}
//todo beautify
private string GetCostString(Dictionary<string, int> costs)
{
var orderedCosts = costs.OrderBy(p => p.Value);
var msg = new FormattedMessage();
foreach (var (mat, amount) in orderedCosts)
{
var matProto = _prototypeManager.Index<MaterialPrototype>(mat);
var sheetVolume = _materialStorage.GetSheetVolume(matProto);
var sheets = (float) -amount / sheetVolume;
var amountText = Loc.GetString("lathe-menu-material-amount",
("amount", sheets),
("unit", Loc.GetString(matProto.Unit)));
var text = Loc.GetString("lathe-menu-tooltip-display",
("amount", amountText),
("material", Loc.GetString(matProto.Name)));
msg.AddMarkup(text);
msg.PushNewline();
}
msg.Pop();
return msg.ToMarkup();
}
public override void Close()
{
base.Close();
_entityManager.DeleteEntity(_machinePreview);
_machinePreview = null;
}
}

View file

@ -82,8 +82,10 @@ namespace Content.Client.Eye.Blinding
if (_entityManager.TryGetComponent<EyeComponent>(playerEntity, out var content))
{
_circleMaskShader?.SetParameter("ZOOM", content.Zoom.X);
_circleMaskShader?.SetParameter("Zoom", content.Zoom.X);
}
_circleMaskShader?.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_greyscaleShader?.SetParameter("SCREEN_TEXTURE", ScreenTexture);
var worldHandle = args.WorldHandle;

View file

@ -1,9 +1,10 @@
using Robust.Client.Graphics;
using Robust.Client.Player;
using Content.Shared.CCVar;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Content.Shared.Eye.Blinding;
using Content.Shared.Eye.Blinding.Components;
using Robust.Shared.Configuration;
namespace Content.Client.Eye.Blinding
{
@ -11,24 +12,45 @@ namespace Content.Client.Eye.Blinding
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _cataractsShader;
private readonly ShaderInstance _circleMaskShader;
private float _magnitude;
private float _correctionPower = 2.0f;
private const float Distortion_Pow = 2.0f; // Exponent for the distortion effect
private const float Cloudiness_Pow = 1.0f; // Exponent for the cloudiness effect
private const float NoMotion_Radius = 30.0f; // Base radius for the nomotion variant at its full strength
private const float NoMotion_Pow = 0.2f; // Exponent for the nomotion variant's gradient
private const float NoMotion_Max = 8.0f; // Max value for the nomotion variant's gradient
private const float NoMotion_Mult = 0.75f; // Multiplier for the nomotion variant
public BlurryVisionOverlay()
{
IoCManager.InjectDependencies(this);
_cataractsShader = _prototypeManager.Index<ShaderPrototype>("Cataracts").InstanceUnique();
_circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
_circleMaskShader.SetParameter("CircleMinDist", 0.0f);
_circleMaskShader.SetParameter("CirclePow", NoMotion_Pow);
_circleMaskShader.SetParameter("CircleMax", NoMotion_Max);
_circleMaskShader.SetParameter("CircleMult", NoMotion_Mult);
}
protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (!_entityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out EyeComponent? eyeComp))
if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
return false;
if (args.Viewport.Eye != eyeComp.Eye)
return false;
var playerEntity = _playerManager.LocalPlayer?.ControlledEntity;
var playerEntity = _playerManager.LocalSession?.AttachedEntity;
if (playerEntity == null)
return false;
@ -44,21 +66,52 @@ namespace Content.Client.Eye.Blinding
return false;
_magnitude = blurComp.Magnitude;
_correctionPower = blurComp.CorrectionPower;
return true;
}
protected override void Draw(in OverlayDrawArgs args)
{
// TODO make this better.
// This is a really shitty effect.
// Maybe gradually shrink the view-size?
// Make the effect only apply to the edge of the viewport?
// Actually make it blurry??
var opacity = 1f * _magnitude / BlurryVisionComponent.MaxMagnitude;
if (ScreenTexture == null)
return;
var playerEntity = _playerManager.LocalSession?.AttachedEntity;
var worldHandle = args.WorldHandle;
var viewport = args.WorldBounds;
worldHandle.SetTransform(Matrix3.Identity);
worldHandle.DrawRect(viewport, Color.Black.WithAlpha(opacity));
var strength = (float) Math.Pow(Math.Min(_magnitude / BlurryVisionComponent.MaxMagnitude, 1.0f), _correctionPower);
var zoom = 1.0f;
if (_entityManager.TryGetComponent<EyeComponent>(playerEntity, out var eyeComponent))
{
zoom = eyeComponent.Zoom.X;
}
// While the cataracts shader is designed to be tame enough to keep motion sickness at bay, the general waviness means that those who are particularly sensitive to motion sickness will probably hurl.
// So the reasonable alternative here is to replace it with a static effect! Specifically, one that replicates the blindness effect seen across most SS13 servers.
if (_configManager.GetCVar(CCVars.ReducedMotion))
{
_circleMaskShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_circleMaskShader.SetParameter("Zoom", zoom);
_circleMaskShader.SetParameter("CircleRadius", NoMotion_Radius / strength);
worldHandle.UseShader(_circleMaskShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
return;
}
_cataractsShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_cataractsShader.SetParameter("LIGHT_TEXTURE", args.Viewport.LightRenderTarget.Texture); // this is a little hacky but we spent way longer than we'd like to admit trying to do this a cleaner way to no avail
_cataractsShader.SetParameter("Zoom", zoom);
_cataractsShader.SetParameter("DistortionScalar", (float) Math.Pow(strength, Distortion_Pow));
_cataractsShader.SetParameter("CloudinessScalar", (float) Math.Pow(strength, Cloudiness_Pow));
worldHandle.UseShader(_cataractsShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
}

View file

@ -30,6 +30,9 @@ public sealed class PoweredLightVisualizerSystem : VisualizerSystem<PoweredLight
if (comp.SpriteStateMap.TryGetValue(state, out var spriteState))
args.Sprite.LayerSetState(PoweredLightLayers.Base, spriteState);
if (args.Sprite.LayerExists(PoweredLightLayers.Glow))
args.Sprite.LayerSetVisible(PoweredLightLayers.Glow, state == PoweredLightState.On);
SetBlinkingAnimation(
uid,
state == PoweredLightState.On

View file

@ -16,7 +16,6 @@
</BoxContainer>
<BoxContainer Name="Content"
Orientation="Horizontal"
HorizontalExpand="True"
HorizontalAlignment="Right">
<!--Here go buttons which added in c#-->
</BoxContainer>

View file

@ -37,9 +37,9 @@ public sealed partial class MaterialStorageControl : BoxContainer
if (_owner == null)
return;
if (!_entityManager.TryGetComponent<MaterialStorageComponent>(_owner, out var materialStorage))
if (_entityManager.Deleted(_owner) || !_entityManager.TryGetComponent<MaterialStorageComponent>(_owner, out var materialStorage))
{
Dispose();
_owner = null;
return;
}

View file

@ -18,6 +18,10 @@
<Control MinSize="4 0" />
<OptionButton Name="HudLayoutOption" />
</BoxContainer>
<Label Text="{Loc 'ui-options-general-accessibility'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<Label Text="{Loc 'ui-options-general-discord'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>

View file

@ -62,6 +62,7 @@ namespace Content.Client.Options.UI.Tabs
OpaqueStorageWindowCheckBox.OnToggled += OnCheckBoxToggled;
FancySpeechBubblesCheckBox.OnToggled += OnCheckBoxToggled;
FancyNameBackgroundsCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
StaticStorageUI.OnToggled += OnCheckBoxToggled;
@ -109,6 +110,7 @@ namespace Content.Client.Options.UI.Tabs
_cfg.SetCVar(CCVars.LoocAboveHeadShow, ShowLoocAboveHeadCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
_cfg.SetCVar(CCVars.StaticStorageUI, StaticStorageUI.Pressed);
@ -132,6 +134,7 @@ namespace Content.Client.Options.UI.Tabs
var isLoocShowSame = ShowLoocAboveHeadCheckBox.Pressed == _cfg.GetCVar(CCVars.LoocAboveHeadShow);
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
var isStaticStorageUISame = StaticStorageUI.Pressed == _cfg.GetCVar(CCVars.StaticStorageUI);
@ -144,6 +147,7 @@ namespace Content.Client.Options.UI.Tabs
isLoocShowSame &&
isFancyChatSame &&
isFancyBackgroundSame &&
isReducedMotionSame &&
// isToggleWalkSame &&
isStaticStorageUISame;
}

View file

@ -54,6 +54,30 @@
<!-- appearanceList -->
<BoxContainer Orientation="Vertical">
<BoxContainer Margin="10" Orientation="Vertical" HorizontalExpand="True">
<!-- Species -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-species-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Age -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-age-label'}" />
<Control HorizontalExpand="True"/>
<LineEdit Name="CAgeEdit" MinSize="40 0" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Sex -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-sex-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CSexButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Pronouns -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-pronouns-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CPronounsButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Show clothing -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-clothing'}" />
@ -72,30 +96,6 @@
<Control HorizontalExpand="True"/>
<OptionButton Name="CBackpackButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Sex -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-sex-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CSexButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Pronouns -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-pronouns-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CPronounsButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Age -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-age-label'}" />
<Control HorizontalExpand="True"/>
<LineEdit Name="CAgeEdit" MinSize="40 0" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Species -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-species-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Corvax-TTS-Start -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-voice-label'}" />

View file

@ -5,6 +5,7 @@ using Content.Shared.Item;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
using ItemToggleComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleComponent;
namespace Content.Client.Tools.UI;

View file

@ -1,7 +0,0 @@
using Content.Shared.Weapons.Reflect;
namespace Content.Client.Weapons.Reflect;
public sealed class ReflectSystem : SharedReflectSystem
{
}

View file

@ -27,9 +27,9 @@ public sealed class ConfigPresetTests
originalCVars.Add((cvar, value));
}
var originalCvarsStream = new MemoryStream();
config.SaveToTomlStream(originalCvarsStream, config.GetRegisteredCVars());
originalCvarsStream.Position = 0;
var originalCVarsStream = new MemoryStream();
config.SaveToTomlStream(originalCVarsStream, config.GetRegisteredCVars());
originalCVarsStream.Position = 0;
var presets = resources.ContentFindFiles(EntryPoint.ConfigPresetsDir);
Assert.Multiple(() =>
@ -41,7 +41,12 @@ public sealed class ConfigPresetTests
}
});
config.LoadDefaultsFromTomlStream(originalCvarsStream);
config.LoadDefaultsFromTomlStream(originalCVarsStream);
foreach (var (cvar, value) in originalCVars)
{
config.SetCVar(cvar, value);
}
foreach (var originalCVar in originalCVars)
{

View file

@ -23,6 +23,7 @@ using Robust.Shared.Input;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using ItemToggleComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleComponent;
namespace Content.IntegrationTests.Tests.Interaction;

View file

@ -1,24 +0,0 @@
using Content.Shared.Tools;
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Ame.Components;
/// <summary>
/// Packaged AME machinery that can be deployed to construct an AME.
/// </summary>
[RegisterComponent]
public sealed partial class AmePartComponent : Component
{
/// <summary>
/// The sound played when the AME shielding is unpacked.
/// </summary>
[DataField("unwrapSound")]
public SoundSpecifier UnwrapSound = new SoundPathSpecifier("/Audio/Effects/unwrap.ogg");
/// <summary>
/// The tool quality required to deploy the packaged AME shielding.
/// </summary>
[DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
public string QualityNeeded = "Pulsing";
}

View file

@ -1,53 +0,0 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Ame.Components;
using Content.Server.Popups;
using Content.Server.Tools;
using Content.Shared.Database;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
namespace Content.Server.Ame.EntitySystems;
public sealed class AmePartSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly ToolSystem _toolSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AmePartComponent, InteractUsingEvent>(OnPartInteractUsing);
}
private void OnPartInteractUsing(EntityUid uid, AmePartComponent component, InteractUsingEvent args)
{
if (!_toolSystem.HasQuality(args.Used, component.QualityNeeded))
return;
if (!_mapManager.TryGetGrid(args.ClickLocation.GetGridUid(EntityManager), out var mapGrid))
return; // No AME in space.
var snapPos = mapGrid.TileIndicesFor(args.ClickLocation);
if (mapGrid.GetAnchoredEntities(snapPos).Any(sc => HasComp<AmeShieldComponent>(sc)))
{
_popupSystem.PopupEntity(Loc.GetString("ame-part-component-shielding-already-present"), uid, args.User);
return;
}
var ent = Spawn("AmeShielding", mapGrid.GridTileToLocal(snapPos));
_adminLogger.Add(LogType.Construction, LogImpact.Low, $"{ToPrettyString(args.User):player} unpacked {ToPrettyString(ent)} at {Transform(ent).Coordinates} from {ToPrettyString(uid)}");
_audioSystem.PlayPvs(component.UnwrapSound, uid);
QueueDel(uid);
}
}

View file

@ -36,7 +36,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
SubscribeLocalEvent<GasFilterComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<GasFilterComponent, AtmosDeviceUpdateEvent>(OnFilterUpdated);
SubscribeLocalEvent<GasFilterComponent, AtmosDeviceDisabledEvent>(OnFilterLeaveAtmosphere);
SubscribeLocalEvent<GasFilterComponent, InteractHandEvent>(OnFilterInteractHand);
SubscribeLocalEvent<GasFilterComponent, ActivateInWorldEvent>(OnFilterActivate);
SubscribeLocalEvent<GasFilterComponent, GasAnalyzerScanEvent>(OnFilterAnalyzed);
// Bound UI subscriptions
SubscribeLocalEvent<GasFilterComponent, GasFilterChangeRateMessage>(OnTransferRateChangeMessage);
@ -101,7 +101,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
_userInterfaceSystem.TryCloseAll(uid, GasFilterUiKey.Key);
}
private void OnFilterInteractHand(EntityUid uid, GasFilterComponent filter, InteractHandEvent args)
private void OnFilterActivate(EntityUid uid, GasFilterComponent filter, ActivateInWorldEvent args)
{
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;

View file

@ -35,7 +35,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
SubscribeLocalEvent<GasMixerComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<GasMixerComponent, AtmosDeviceUpdateEvent>(OnMixerUpdated);
SubscribeLocalEvent<GasMixerComponent, InteractHandEvent>(OnMixerInteractHand);
SubscribeLocalEvent<GasMixerComponent, ActivateInWorldEvent>(OnMixerActivate);
SubscribeLocalEvent<GasMixerComponent, GasAnalyzerScanEvent>(OnMixerAnalyzed);
// Bound UI subscriptions
SubscribeLocalEvent<GasMixerComponent, GasMixerChangeOutputPressureMessage>(OnOutputPressureChangeMessage);
@ -147,7 +147,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
_userInterfaceSystem.TryCloseAll(uid, GasFilterUiKey.Key);
}
private void OnMixerInteractHand(EntityUid uid, GasMixerComponent mixer, InteractHandEvent args)
private void OnMixerActivate(EntityUid uid, GasMixerComponent mixer, ActivateInWorldEvent args)
{
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;

View file

@ -1,29 +1,27 @@
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
namespace Content.Server.Chemistry.Components
namespace Content.Server.Chemistry.Components;
/// <summary>
/// On colliding with an entity that has a bloodstream will dump its solution onto them.
/// </summary>
[RegisterComponent]
public sealed partial class SolutionInjectOnCollideComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("transferAmount")]
public FixedPoint2 TransferAmount = FixedPoint2.New(1);
[ViewVariables(VVAccess.ReadWrite)]
public float TransferEfficiency { get => _transferEfficiency; set => _transferEfficiency = Math.Clamp(value, 0, 1); }
[DataField("transferEfficiency")]
private float _transferEfficiency = 1f;
/// <summary>
/// On colliding with an entity that has a bloodstream will dump its solution onto them.
/// If anything covers any of these slots then the injection fails.
/// </summary>
[RegisterComponent]
internal sealed partial class SolutionInjectOnCollideComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("transferAmount")]
public FixedPoint2 TransferAmount { get; set; } = FixedPoint2.New(1);
[ViewVariables(VVAccess.ReadWrite)]
public float TransferEfficiency { get => _transferEfficiency; set => _transferEfficiency = Math.Clamp(value, 0, 1); }
[DataField("transferEfficiency")]
private float _transferEfficiency = 1f;
/// <summary>
/// If anything covers any of these slots then the injection fails.
/// </summary>
[DataField("blockSlots"), ViewVariables(VVAccess.ReadWrite)]
public SlotFlags BlockSlots = SlotFlags.MASK;
}
[DataField("blockSlots"), ViewVariables(VVAccess.ReadWrite)]
public SlotFlags BlockSlots = SlotFlags.MASK;
}

View file

@ -6,48 +6,47 @@ using Content.Shared.Inventory;
using JetBrains.Annotations;
using Robust.Shared.Physics.Events;
namespace Content.Server.Chemistry.EntitySystems
namespace Content.Server.Chemistry.EntitySystems;
public sealed class SolutionInjectOnCollideSystem : EntitySystem
{
[UsedImplicitly]
internal sealed class SolutionInjectOnCollideSystem : EntitySystem
[Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
public override void Initialize()
{
[Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
base.Initialize();
SubscribeLocalEvent<SolutionInjectOnCollideComponent, StartCollideEvent>(HandleInjection);
}
public override void Initialize()
private void HandleInjection(Entity<SolutionInjectOnCollideComponent> ent, ref StartCollideEvent args)
{
var component = ent.Comp;
var target = args.OtherEntity;
if (!args.OtherBody.Hard ||
!args.OurBody.Hard ||
!EntityManager.TryGetComponent<BloodstreamComponent>(target, out var bloodstream) ||
!_solutionContainersSystem.TryGetInjectableSolution(ent.Owner, out var solution, out _))
{
base.Initialize();
SubscribeLocalEvent<SolutionInjectOnCollideComponent, StartCollideEvent>(HandleInjection);
return;
}
private void HandleInjection(Entity<SolutionInjectOnCollideComponent> ent, ref StartCollideEvent args)
if (component.BlockSlots != 0x0)
{
var component = ent.Comp;
var target = args.OtherEntity;
var containerEnumerator = _inventorySystem.GetSlotEnumerator(target, component.BlockSlots);
if (!args.OtherBody.Hard ||
!EntityManager.TryGetComponent<BloodstreamComponent>(target, out var bloodstream) ||
!_solutionContainersSystem.TryGetInjectableSolution(ent.Owner, out var solution, out _))
{
// TODO add a helper method for this?
if (containerEnumerator.MoveNext(out _))
return;
}
if (component.BlockSlots != 0x0)
{
var containerEnumerator = _inventorySystem.GetSlotEnumerator(target, component.BlockSlots);
// TODO add a helper method for this?
if (containerEnumerator.MoveNext(out _))
return;
}
var solRemoved = _solutionContainersSystem.SplitSolution(solution.Value, component.TransferAmount);
var solRemovedVol = solRemoved.Volume;
var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency);
_bloodstreamSystem.TryAddToChemicals(target, solToInject, bloodstream);
}
var solRemoved = _solutionContainersSystem.SplitSolution(solution.Value, component.TransferAmount);
var solRemovedVol = solRemoved.Volume;
var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency);
_bloodstreamSystem.TryAddToChemicals(target, solToInject, bloodstream);
}
}

View file

@ -0,0 +1,98 @@
using Content.Server.Audio;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Construction;
using Content.Shared.Construction.Components;
using Content.Shared.Containers.ItemSlots;
using Robust.Shared.Timing;
namespace Content.Server.Construction;
/// <inheritdoc/>
public sealed class FlatpackSystem : SharedFlatpackSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly AmbientSoundSystem _ambientSound = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FlatpackCreatorComponent, FlatpackCreatorStartPackBuiMessage>(OnStartPack);
SubscribeLocalEvent<FlatpackCreatorComponent, PowerChangedEvent>(OnPowerChanged);
}
private void OnStartPack(Entity<FlatpackCreatorComponent> ent, ref FlatpackCreatorStartPackBuiMessage args)
{
var (uid, comp) = ent;
if (!this.IsPowered(ent, EntityManager) || comp.Packing)
return;
if (!_itemSlots.TryGetSlot(uid, comp.SlotId, out var itemSlot) || itemSlot.Item is not { } machineBoard)
return;
if (!TryComp<MachineBoardComponent>(machineBoard, out var boardComp))
return;
if (!MaterialStorage.CanChangeMaterialAmount(uid, GetFlatpackCreationCost(ent, (machineBoard, boardComp))))
return;
comp.Packing = true;
comp.PackEndTime = _timing.CurTime + comp.PackDuration;
Appearance.SetData(uid, FlatpackCreatorVisuals.Packing, true);
_ambientSound.SetAmbience(uid, true);
Dirty(uid, comp);
}
private void OnPowerChanged(Entity<FlatpackCreatorComponent> ent, ref PowerChangedEvent args)
{
if (args.Powered)
return;
FinishPacking(ent, true);
}
private void FinishPacking(Entity<FlatpackCreatorComponent> ent, bool interrupted)
{
var (uid, comp) = ent;
comp.Packing = false;
Appearance.SetData(uid, FlatpackCreatorVisuals.Packing, false);
_ambientSound.SetAmbience(uid, false);
Dirty(uid, comp);
if (interrupted)
return;
if (!_itemSlots.TryGetSlot(uid, comp.SlotId, out var itemSlot) || itemSlot.Item is not { } machineBoard)
return;
if (!TryComp<MachineBoardComponent>(machineBoard, out var boardComp))
return;
var materialCost = GetFlatpackCreationCost(ent, (machineBoard, boardComp));
if (!MaterialStorage.TryChangeMaterialAmount((ent, null), materialCost))
return;
var flatpack = Spawn(comp.BaseFlatpackPrototype, Transform(ent).Coordinates);
SetupFlatpack(flatpack, (machineBoard, boardComp));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<FlatpackCreatorComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (!comp.Packing)
continue;
if (_timing.CurTime < comp.PackEndTime)
continue;
FinishPacking((uid, comp), false);
}
}
}

View file

@ -6,6 +6,7 @@ using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Interaction;
using Content.Shared.Tools.Components;
using ItemToggleComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleComponent;
namespace Content.Server.Damage.Systems
{

View file

@ -5,6 +5,7 @@ using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Tools.Components;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Item.ItemToggle.Components;
namespace Content.Server.Eye.Blinding.EyeProtection
{
@ -18,7 +19,7 @@ namespace Content.Server.Eye.Blinding.EyeProtection
{
base.Initialize();
SubscribeLocalEvent<RequiresEyeProtectionComponent, ToolUseAttemptEvent>(OnUseAttempt);
SubscribeLocalEvent<RequiresEyeProtectionComponent, ItemToggleDoneEvent>(OnWelderToggled);
SubscribeLocalEvent<RequiresEyeProtectionComponent, ItemToggledEvent>(OnWelderToggled);
SubscribeLocalEvent<EyeProtectionComponent, GetEyeProtectionEvent>(OnGetProtection);
SubscribeLocalEvent<EyeProtectionComponent, InventoryRelayedEvent<GetEyeProtectionEvent>>(OnGetRelayedProtection);
@ -52,12 +53,12 @@ namespace Content.Server.Eye.Blinding.EyeProtection
// Add permanent eye damage if they had zero protection, also somewhat scale their temporary blindness by
// how much damage they already accumulated.
_blindingSystem.AdjustEyeDamage(args.User, 1, blindable);
_blindingSystem.AdjustEyeDamage((args.User, blindable), 1);
var statusTimeSpan = TimeSpan.FromSeconds(time * MathF.Sqrt(blindable.EyeDamage));
_statusEffectsSystem.TryAddStatusEffect(args.User, TemporaryBlindnessSystem.BlindingStatusEffect,
statusTimeSpan, false, TemporaryBlindnessSystem.BlindingStatusEffect);
}
private void OnWelderToggled(EntityUid uid, RequiresEyeProtectionComponent component, ItemToggleDoneEvent args)
private void OnWelderToggled(EntityUid uid, RequiresEyeProtectionComponent component, ItemToggledEvent args)
{
component.Toggled = _itemToggle.IsActivated(uid);
}

View file

@ -7,7 +7,6 @@ using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.NPC.Components;
using Content.Server.NPC.Systems;
using Content.Server.Objectives;
using Content.Server.Popups;
using Content.Server.Revolutionary.Components;
using Content.Server.Roles;
@ -43,7 +42,6 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleCo
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly ObjectivesSystem _objectives = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
@ -104,15 +102,24 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleCo
ev.AddLine(Loc.GetString(Outcomes[index]));
ev.AddLine(Loc.GetString("rev-headrev-count", ("initialCount", headrev.HeadRevs.Count)));
foreach (var player in headrev.HeadRevs.Values)
foreach (var player in headrev.HeadRevs)
{
var title = _objectives.GetTitle(player);
if (title == null)
continue;
// TODO: when role entities are a thing this has to change
var count = CompOrNull<RevolutionaryRoleComponent>(player)?.ConvertedCount ?? 0;
ev.AddLine(Loc.GetString("rev-headrev-player", ("title", title), ("count", count)));
var count = CompOrNull<RevolutionaryRoleComponent>(player.Value)?.ConvertedCount ?? 0;
_mind.TryGetSession(player.Value, out var session);
var username = session?.Name;
if (username != null)
{
ev.AddLine(Loc.GetString("rev-headrev-name-user",
("name", player.Key),
("username", username), ("count", count)));
}
else
{
ev.AddLine(Loc.GetString("rev-headrev-name",
("name", player.Key), ("count", count)));
}
// TODO: someone suggested listing all alive? revs maybe implement at some point
}

View file

@ -2,6 +2,8 @@ using Content.Shared.Item;
using Content.Server.CombatMode.Disarm;
using Content.Server.Kitchen.Components;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Item.ItemToggle.Components;
using ItemToggleComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleComponent;
namespace Content.Server.Item;
@ -11,10 +13,10 @@ public sealed class ItemToggleSystem : SharedItemToggleSystem
{
base.Initialize();
SubscribeLocalEvent<ItemToggleComponent, ItemToggleDoneEvent>(Toggle);
SubscribeLocalEvent<ItemToggleComponent, ItemToggledEvent>(Toggle);
}
private void Toggle(EntityUid uid, ItemToggleComponent comp, ref ItemToggleDoneEvent args)
private void Toggle(EntityUid uid, ItemToggleComponent comp, ref ItemToggledEvent args)
{
if (args.Activated == true)
{

View file

@ -78,7 +78,7 @@ namespace Content.Server.Light.EntitySystems
if (TryComp<ItemComponent>(ent, out var item))
{
_item.SetHeldPrefix(ent, "unlit", item);
_item.SetHeldPrefix(ent, "unlit", component: item);
}
break;
@ -96,7 +96,7 @@ namespace Content.Server.Light.EntitySystems
{
if (TryComp<ItemComponent>(ent, out var item))
{
_item.SetHeldPrefix(ent, "lit", item);
_item.SetHeldPrefix(ent, "lit", component: item);
}
component.CurrentState = ExpendableLightState.Lit;
@ -163,7 +163,7 @@ namespace Content.Server.Light.EntitySystems
{
if (TryComp<ItemComponent>(uid, out var item))
{
_item.SetHeldPrefix(uid, "unlit", item);
_item.SetHeldPrefix(uid, "unlit", component: item);
}
component.CurrentState = ExpendableLightState.BrandNew;

View file

@ -107,10 +107,10 @@ namespace Content.Server.Light.EntitySystems
switch (component.CurrentState)
{
case SmokableState.Lit:
_item.SetHeldPrefix(uid, "lit", item);
_item.SetHeldPrefix(uid, "lit", component: item);
break;
default:
_item.SetHeldPrefix(uid, "unlit", item);
_item.SetHeldPrefix(uid, "unlit", component: item);
break;
}
}

View file

@ -70,7 +70,8 @@ public sealed class SpreaderSystem : EntitySystem
foreach (var neighbor in neighbors)
{
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
if (!TerminatingOrDeleted(neighbor))
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
}
}

View file

@ -7,6 +7,7 @@ using Content.Shared.Damage.Events;
using Content.Shared.Examine;
using Content.Shared.Item;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
@ -28,7 +29,7 @@ namespace Content.Server.Stunnable.Systems
SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
SubscribeLocalEvent<StunbatonComponent, ItemToggleActivateAttemptEvent>(TryTurnOn);
SubscribeLocalEvent<StunbatonComponent, ItemToggleDoneEvent>(ToggleDone);
SubscribeLocalEvent<StunbatonComponent, ItemToggledEvent>(ToggleDone);
}
private void OnStaminaHitAttempt(Entity<StunbatonComponent> entity, ref StaminaDamageOnHitAttemptEvent args)
@ -58,12 +59,12 @@ namespace Content.Server.Stunnable.Systems
args.PushMarkup(chargeMessage);
}
private void ToggleDone(Entity<StunbatonComponent> entity, ref ItemToggleDoneEvent args)
private void ToggleDone(Entity<StunbatonComponent> entity, ref ItemToggledEvent args)
{
if (!TryComp<ItemComponent>(entity, out var item))
return;
_item.SetHeldPrefix(entity.Owner, args.Activated ? "on" : "off", item);
_item.SetHeldPrefix(entity.Owner, args.Activated ? "on" : "off", component: item);
}
private void TryTurnOn(Entity<StunbatonComponent> entity, ref ItemToggleActivateAttemptEvent args)

View file

@ -12,6 +12,7 @@ using Content.Shared.Item.ItemToggle;
using Content.Shared.Tools.Components;
using Robust.Shared.GameStates;
using System.Linq;
using Content.Shared.Item.ItemToggle.Components;
namespace Content.Server.Tools
{

View file

@ -1,20 +0,0 @@
using Content.Shared.Item;
using Content.Shared.Weapons.Reflect;
namespace Content.Server.Weapons.Reflect;
public sealed class ReflectSystem : SharedReflectSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ReflectComponent, ItemToggleReflectUpdateEvent>(ToggleReflect);
}
private void ToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggleReflectUpdateEvent args)
{
comp.Enabled = args.Activated;
Dirty(uid, comp);
}
}

View file

@ -258,7 +258,7 @@ namespace Content.Shared.CCVar
/// Whether or not panic bunker is currently enabled.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnabled =
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED);
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Whether or not the panic bunker will disable when an admin comes online.
@ -1505,6 +1505,18 @@ namespace Content.Shared.CCVar
CVarDef.Create("ui.separated_chat_size", "0.6,0", CVar.CLIENTONLY | CVar.ARCHIVE);
/*
* Accessibility
*/
/// <summary>
/// Toggle for visual effects that may potentially cause motion sickness.
/// Where reasonable, effects affected by this CVar should use an alternate effect.
/// Please do not use this CVar as a bandaid for effects that could otherwise be made accessible without issue.
/// </summary>
public static readonly CVarDef<bool> ReducedMotion =
CVarDef.Create("accessibility.reduced_motion", false, CVar.CLIENTONLY | CVar.ARCHIVE);
/*
* CHAT
*/

View file

@ -4,7 +4,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.Clothing.Components;
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class LoadoutComponent : Component
{
/// <summary>

View file

@ -57,7 +57,7 @@ public abstract class SharedMagbootsSystem : EntitySystem
if (TryComp<ItemComponent>(uid, out var item))
{
_item.SetHeldPrefix(uid, magboots.On ? "on" : null, item);
_item.SetHeldPrefix(uid, magboots.On ? "on" : null, component: item);
_clothing.SetEquippedPrefix(uid, magboots.On ? "on" : null);
}

View file

@ -0,0 +1,51 @@
using Content.Shared.Tools;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Construction.Components;
/// <summary>
/// This is used for an object that can instantly create a machine upon having a tool applied to it.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedFlatpackSystem))]
public sealed partial class FlatpackComponent : Component
{
/// <summary>
/// The tool quality that, upon used to interact with this object, will create the <see cref="Entity"/>
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public ProtoId<ToolQualityPrototype> QualityNeeded = "Pulsing";
/// <summary>
/// The entity that is spawned when this object is unpacked.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public EntProtoId? Entity;
/// <summary>
/// Sound effect played upon the object being unpacked.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public SoundSpecifier UnpackSound = new SoundPathSpecifier("/Audio/Effects/unwrap.ogg");
/// <summary>
/// A dictionary relating a machine board sprite state to a color used for the overlay.
/// Kinda shitty but it gets the job done.
/// </summary>
[DataField]
public Dictionary<string, Color> BoardColors = new();
}
[Serializable, NetSerializable]
public enum FlatpackVisuals : byte
{
Machine
}
public enum FlatpackVisualLayers : byte
{
Overlay
}

View file

@ -0,0 +1,69 @@
using Content.Shared.Materials;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Construction.Components;
/// <summary>
/// This is used for a machine that creates flatpacks at the cost of materials
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedFlatpackSystem))]
[AutoGenerateComponentState]
public sealed partial class FlatpackCreatorComponent : Component
{
/// <summary>
/// Whether or not packing is occuring
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public bool Packing;
/// <summary>
/// The time at which packing ends
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public TimeSpan PackEndTime;
/// <summary>
/// How long packing lasts.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan PackDuration = TimeSpan.FromSeconds(3);
/// <summary>
/// The prototype used when spawning a flatpack.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public EntProtoId BaseFlatpackPrototype = "BaseFlatpack";
/// <summary>
/// A default cost applied to all flatpacks outside of the cost of constructing the machine.
/// </summary>
[DataField]
public Dictionary<ProtoId<MaterialPrototype>, int> BaseMaterialCost = new();
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string SlotId = "board_slot";
}
[Serializable, NetSerializable]
public enum FlatpackCreatorUIKey : byte
{
Key
}
[Serializable, NetSerializable]
public enum FlatpackCreatorVisuals : byte
{
Packing
}
[Serializable, NetSerializable]
public sealed class FlatpackCreatorStartPackBuiMessage : BoundUserInterfaceMessage
{
}

View file

@ -1,6 +1,10 @@
using System.Linq;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Examine;
using Content.Shared.Lathe;
using Content.Shared.Materials;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
namespace Content.Shared.Construction
@ -11,6 +15,7 @@ namespace Content.Shared.Construction
public sealed class MachinePartSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedLatheSystem _lathe = default!;
public override void Initialize()
{
@ -61,5 +66,87 @@ namespace Content.Shared.Construction
args.PushMarkup(Loc.GetString("machine-part-component-on-examine-type-text", ("type",
Loc.GetString(_prototype.Index<MachinePartPrototype>(component.PartType).Name))));
}
public Dictionary<string, int> GetMachineBoardMaterialCost(Entity<MachineBoardComponent> entity, int coefficient = 1)
{
var (_, comp) = entity;
var materials = new Dictionary<string, int>();
foreach (var (partId, amount) in comp.Requirements)
{
var partProto = _prototype.Index<MachinePartPrototype>(partId);
if (!_lathe.TryGetRecipesFromEntity(partProto.StockPartPrototype, out var recipes))
continue;
var partRecipe = recipes[0];
if (recipes.Count > 1)
partRecipe = recipes.MinBy(p => p.RequiredMaterials.Values.Sum());
foreach (var (mat, matAmount) in partRecipe!.RequiredMaterials)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
foreach (var (stackId, amount) in comp.MaterialIdRequirements)
{
var stackProto = _prototype.Index<StackPrototype>(stackId);
if (_prototype.TryIndex(stackProto.Spawn, out var defaultProto) &&
defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
{
foreach (var (mat, matAmount) in physComp.MaterialComposition)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
else if (_lathe.TryGetRecipesFromEntity(stackProto.Spawn, out var recipes))
{
var partRecipe = recipes[0];
if (recipes.Count > 1)
partRecipe = recipes.MinBy(p => p.RequiredMaterials.Values.Sum());
foreach (var (mat, matAmount) in partRecipe!.RequiredMaterials)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
}
var genericPartInfo = comp.ComponentRequirements.Values.Concat(comp.ComponentRequirements.Values);
foreach (var info in genericPartInfo)
{
var amount = info.Amount;
var defaultProtoId = info.DefaultPrototype;
if (_lathe.TryGetRecipesFromEntity(defaultProtoId, out var recipes))
{
var partRecipe = recipes[0];
if (recipes.Count > 1)
partRecipe = recipes.MinBy(p => p.RequiredMaterials.Values.Sum());
foreach (var (mat, matAmount) in partRecipe!.RequiredMaterials)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
else if (_prototype.TryIndex(defaultProtoId, out var defaultProto) &&
defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
{
foreach (var (mat, matAmount) in physComp.MaterialComposition)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
}
return materials;
}
}
}

View file

@ -0,0 +1,150 @@
using System.Numerics;
using Content.Shared.Construction.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Materials;
using Content.Shared.Popups;
using Content.Shared.Tools.Systems;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
namespace Content.Shared.Construction;
public abstract class SharedFlatpackSystem : EntitySystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] protected readonly MachinePartSystem MachinePart = default!;
[Dependency] protected readonly SharedMaterialStorageSystem MaterialStorage = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedToolSystem _tool = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<FlatpackComponent, InteractUsingEvent>(OnFlatpackInteractUsing);
SubscribeLocalEvent<FlatpackComponent, ExaminedEvent>(OnFlatpackExamined);
SubscribeLocalEvent<FlatpackCreatorComponent, ContainerIsRemovingAttemptEvent>(OnCreatorRemovingAttempt);
SubscribeLocalEvent<FlatpackCreatorComponent, EntityUnpausedEvent>(OnCreatorUnpaused);
}
private void OnFlatpackInteractUsing(Entity<FlatpackComponent> ent, ref InteractUsingEvent args)
{
var (uid, comp) = ent;
if (!_tool.HasQuality(args.Used, comp.QualityNeeded) || _container.IsEntityInContainer(ent))
return;
var xform = Transform(ent);
if (xform.GridUid is not { } grid || !TryComp<MapGridComponent>(grid, out var gridComp))
return;
args.Handled = true;
if (comp.Entity == null)
{
Log.Error($"No entity prototype present for flatpack {ToPrettyString(ent)}.");
if (_net.IsServer)
QueueDel(ent);
return;
}
var buildPos = _map.TileIndicesFor(grid, gridComp, xform.Coordinates);
var intersecting = _entityLookup.GetEntitiesIntersecting(buildPos.ToEntityCoordinates(grid, _mapManager).Offset(new Vector2(0.5f, 0.5f))
, LookupFlags.Dynamic | LookupFlags.Static);
// todo make this logic smarter.
// This should eventually allow for shit like building microwaves on tables and such.
foreach (var intersect in intersecting)
{
if (!TryComp<PhysicsComponent>(intersect, out var intersectBody))
continue;
if (!intersectBody.Hard || !intersectBody.CanCollide)
continue;
// this popup is on the server because the mispredicts on the intersection is crazy
if (_net.IsServer)
_popup.PopupEntity(Loc.GetString("flatpack-unpack-no-room"), uid, args.User);
return;
}
if (_net.IsServer)
{
var spawn = Spawn(comp.Entity, _map.GridTileToLocal(grid, gridComp, buildPos));
_adminLogger.Add(LogType.Construction, LogImpact.Low,
$"{ToPrettyString(args.User):player} unpacked {ToPrettyString(spawn):entity} at {xform.Coordinates} from {ToPrettyString(uid):entity}");
QueueDel(uid);
}
_audio.PlayPredicted(comp.UnpackSound, args.Used, args.User);
}
private void OnFlatpackExamined(Entity<FlatpackComponent> ent, ref ExaminedEvent args)
{
if (!args.IsInDetailsRange)
return;
args.PushMarkup(Loc.GetString("flatpack-examine"));
}
private void OnCreatorRemovingAttempt(Entity<FlatpackCreatorComponent> ent, ref ContainerIsRemovingAttemptEvent args)
{
if (args.Container.ID == ent.Comp.SlotId && ent.Comp.Packing)
args.Cancel();
}
private void OnCreatorUnpaused(Entity<FlatpackCreatorComponent> ent, ref EntityUnpausedEvent args)
{
ent.Comp.PackEndTime += args.PausedTime;
}
public void SetupFlatpack(Entity<FlatpackComponent?> ent, Entity<MachineBoardComponent?> machineBoard)
{
if (!Resolve(ent, ref ent.Comp) || !Resolve(machineBoard, ref machineBoard.Comp))
return;
if (machineBoard.Comp.Prototype is not { } machinePrototypeId)
return;
var comp = ent.Comp!;
var machinePrototype = PrototypeManager.Index(machinePrototypeId);
var meta = MetaData(ent);
_metaData.SetEntityName(ent, Loc.GetString("flatpack-entity-name", ("name", machinePrototype.Name)), meta);
_metaData.SetEntityDescription(ent, Loc.GetString("flatpack-entity-description", ("name", machinePrototype.Name)), meta);
comp.Entity = machinePrototypeId;
Dirty(ent, comp);
Appearance.SetData(ent, FlatpackVisuals.Machine, MetaData(machineBoard).EntityPrototype?.ID ?? string.Empty);
}
public Dictionary<string, int> GetFlatpackCreationCost(Entity<FlatpackCreatorComponent> entity, Entity<MachineBoardComponent> machineBoard)
{
var cost = MachinePart.GetMachineBoardMaterialCost(machineBoard, -1);
foreach (var (mat, amount) in entity.Comp.BaseMaterialCost)
{
cost.TryAdd(mat, 0);
cost[mat] -= amount;
}
return cost;
}
}

View file

@ -1,6 +1,8 @@
using Robust.Shared.GameStates;
namespace Content.Shared.ContainerHeld;
[RegisterComponent]
[RegisterComponent, NetworkedComponent]
public sealed partial class ContainerHeldComponent: Component
{
/// <summary>

View file

@ -23,7 +23,7 @@ public sealed class ContainerHeldSystem : EntitySystem
private void OnContainerModified(EntityUid uid, ContainerHeldComponent comp, ContainerModifiedMessage args)
{
if (!(TryComp<StorageComponent>(uid, out var storage)
if (!(HasComp<StorageComponent>(uid)
&& TryComp<AppearanceComponent>(uid, out var appearance)
&& TryComp<ItemComponent>(uid, out var item)))
{
@ -31,12 +31,12 @@ public sealed class ContainerHeldSystem : EntitySystem
}
if (_storage.GetCumulativeItemAreas(uid) >= comp.Threshold)
{
_item.SetHeldPrefix(uid, "full", item);
_item.SetHeldPrefix(uid, "full", component: item);
_appearance.SetData(uid, ToggleVisuals.Toggled, true, appearance);
}
else
{
_item.SetHeldPrefix(uid, "empty", item);
_item.SetHeldPrefix(uid, "empty", component: item);
_appearance.SetData(uid, ToggleVisuals.Toggled, false, appearance);
}
}

View file

@ -265,6 +265,9 @@ namespace Content.Shared.Containers.ItemSlots
return false;
}
if (swap && slot.HasItem && !CanEject(uid, user, slot))
return false;
var ev = new ItemSlotInsertAttemptEvent(uid, usedUid, user, slot);
RaiseLocalEvent(uid, ref ev);
RaiseLocalEvent(usedUid, ref ev);

View file

@ -38,6 +38,8 @@ namespace Content.Shared.Examine
public const float ExamineRange = 16f;
protected const float ExamineDetailsRange = 3f;
protected const float ExamineBlurrinessMult = 2.5f;
/// <summary>
/// Creates a new examine tooltip with arbitrary info.
/// </summary>
@ -125,7 +127,7 @@ namespace Content.Shared.Examine
return CritExamineRange;
if (TryComp<BlurryVisionComponent>(examiner, out var blurry))
return Math.Clamp(ExamineRange - blurry.Magnitude, 2, ExamineRange);
return Math.Clamp(ExamineRange - blurry.Magnitude * ExamineBlurrinessMult, 2, ExamineRange);
}
return ExamineRange;
}

View file

@ -24,7 +24,7 @@ public sealed partial class BlindableComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("EyeDamage"), AutoNetworkedField]
public int EyeDamage = 0;
public const int MaxDamage = 3;
public const int MaxDamage = 9;
/// <description>
/// Used to ensure that this doesn't break with sandbox or admin tools.

View file

@ -17,5 +17,12 @@ public sealed partial class BlurryVisionComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("magnitude"), AutoNetworkedField]
public float Magnitude;
public const float MaxMagnitude = 3;
/// <summary>
/// Exponent that controls the magnitude of the effect.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("correctionPower"), AutoNetworkedField]
public float CorrectionPower;
public const float MaxMagnitude = 6;
public const float DefaultCorrectionPower = 2f;
}

View file

@ -0,0 +1,50 @@
using Content.Shared.Eye.Blinding.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Eye.Blinding.Components;
/// <summary>
/// Allows mobs to toggle their eyes between being closed and being not closed.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
public sealed partial class EyeClosingComponent : Component
{
/// <summary>
/// The prototype to grant to enable eye-toggling action.
/// </summary>
[DataField("eyeToggleAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string EyeToggleAction = "ActionToggleEyes";
/// <summary>
/// The actual eye toggling action entity itself.
/// </summary>
[DataField]
public EntityUid? EyeToggleActionEntity;
/// <summary>
/// Path to sound to play when opening eyes
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public string EyeOpenSound = "/Audio/Effects/eye_open.ogg";
/// <summary>
/// Path to sound to play when closing eyes
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public string EyeCloseSound = "/Audio/Effects/eye_close.ogg";
/// <summary>
/// Toggles whether the eyes are open or closed. This is really just exactly what it says on the tin. Honest.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public bool EyesClosed;
[ViewVariables(VVAccess.ReadOnly), DataField]
public bool PreviousEyelidPosition;
[ViewVariables(VVAccess.ReadOnly), DataField]
public bool NaturallyCreated;
}

View file

@ -9,6 +9,15 @@ namespace Content.Shared.Eye.Blinding.Components;
[NetworkedComponent, AutoGenerateComponentState]
public sealed partial class VisionCorrectionComponent : Component
{
/// <summary>
/// Amount of effective eye damage to add when this item is worn
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("visionBonus"), AutoNetworkedField]
public float VisionBonus = 3f;
public float VisionBonus = 0f;
/// <summary>
/// Controls the exponent of the blur effect when worn
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("correctionPower"), AutoNetworkedField]
public float CorrectionPower = 2f;
}

View file

@ -7,57 +7,67 @@ namespace Content.Shared.Eye.Blinding.Systems;
public sealed class BlindableSystem : EntitySystem
{
[Dependency] private readonly BlurryVisionSystem _blurriness = default!;
[Dependency] private readonly EyeClosingSystem _eyelids = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BlindableComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<BlindableComponent, EyeDamageChangedEvent>(OnDamageChanged);
}
private void OnRejuvenate(EntityUid uid, BlindableComponent component, RejuvenateEvent args)
private void OnRejuvenate(Entity<BlindableComponent> ent, ref RejuvenateEvent args)
{
AdjustEyeDamage(uid, -component.EyeDamage, component);
AdjustEyeDamage((ent.Owner, ent.Comp), -ent.Comp.EyeDamage);
}
private void OnDamageChanged(Entity<BlindableComponent> ent, ref EyeDamageChangedEvent args)
{
_blurriness.UpdateBlurMagnitude((ent.Owner, ent.Comp));
_eyelids.UpdateEyesClosable((ent.Owner, ent.Comp));
}
[PublicAPI]
public void UpdateIsBlind(EntityUid uid, BlindableComponent? blindable = null)
public void UpdateIsBlind(Entity<BlindableComponent?> blindable)
{
if (!Resolve(uid, ref blindable, false))
if (!Resolve(blindable, ref blindable.Comp, false))
return;
var old = blindable.IsBlind;
var old = blindable.Comp.IsBlind;
// Don't bother raising an event if the eye is too damaged.
if (blindable.EyeDamage >= BlindableComponent.MaxDamage)
if (blindable.Comp.EyeDamage >= BlindableComponent.MaxDamage)
{
blindable.IsBlind = true;
blindable.Comp.IsBlind = true;
}
else
{
var ev = new CanSeeAttemptEvent();
RaiseLocalEvent(uid, ev);
blindable.IsBlind = ev.Blind;
RaiseLocalEvent(blindable.Owner, ev);
blindable.Comp.IsBlind = ev.Blind;
}
if (old == blindable.IsBlind)
if (old == blindable.Comp.IsBlind)
return;
var changeEv = new BlindnessChangedEvent(blindable.IsBlind);
RaiseLocalEvent(uid, ref changeEv);
var changeEv = new BlindnessChangedEvent(blindable.Comp.IsBlind);
RaiseLocalEvent(blindable.Owner, ref changeEv);
Dirty(blindable);
}
public void AdjustEyeDamage(EntityUid uid, int amount, BlindableComponent? blindable = null)
public void AdjustEyeDamage(Entity<BlindableComponent?> blindable, int amount)
{
if (!Resolve(uid, ref blindable, false) || amount == 0)
if (!Resolve(blindable, ref blindable.Comp, false) || amount == 0)
return;
blindable.EyeDamage += amount;
blindable.EyeDamage = Math.Clamp(blindable.EyeDamage, 0, BlindableComponent.MaxDamage);
blindable.Comp.EyeDamage += amount;
blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, 0, BlindableComponent.MaxDamage);
Dirty(blindable);
UpdateIsBlind(uid, blindable);
UpdateIsBlind(blindable);
var ev = new EyeDamageChangedEvent(blindable.EyeDamage);
RaiseLocalEvent(uid, ref ev);
var ev = new EyeDamageChangedEvent(blindable.Comp.EyeDamage);
RaiseLocalEvent(blindable.Owner, ref ev);
}
}
@ -71,7 +81,7 @@ public record struct BlindnessChangedEvent(bool Blind);
/// This event is raised when an entity's eye damage changes
/// </summary>
[ByRefEvent]
public record struct EyeDamageChangedEvent(int Damage);
public record struct EyeDamageChangedEvent(int Damage);
/// <summary>
/// Raised directed at an entity to see whether the entity is currently blind or not.

View file

@ -17,17 +17,17 @@ public sealed class BlindfoldSystem : EntitySystem
SubscribeLocalEvent<BlindfoldComponent, InventoryRelayedEvent<CanSeeAttemptEvent>>(OnBlindfoldTrySee);
}
private void OnBlindfoldTrySee(EntityUid uid, BlindfoldComponent component, InventoryRelayedEvent<CanSeeAttemptEvent> args)
private void OnBlindfoldTrySee(Entity<BlindfoldComponent> blindfold, ref InventoryRelayedEvent<CanSeeAttemptEvent> args)
{
args.Args.Cancel();
}
private void OnEquipped(EntityUid uid, BlindfoldComponent component, GotEquippedEvent args)
private void OnEquipped(Entity<BlindfoldComponent> blindfold, ref GotEquippedEvent args)
{
_blindableSystem.UpdateIsBlind(args.Equipee);
}
private void OnUnequipped(EntityUid uid, BlindfoldComponent component, GotUnequippedEvent args)
private void OnUnequipped(Entity<BlindfoldComponent> blindfold, ref GotUnequippedEvent args)
{
_blindableSystem.UpdateIsBlind(args.Equipee);
}

View file

@ -6,54 +6,52 @@ namespace Content.Shared.Eye.Blinding.Systems;
public sealed class BlurryVisionSystem : EntitySystem
{
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BlindableComponent, EyeDamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<VisionCorrectionComponent, GotEquippedEvent>(OnGlassesEquipped);
SubscribeLocalEvent<VisionCorrectionComponent, GotUnequippedEvent>(OnGlassesUnequipped);
SubscribeLocalEvent<VisionCorrectionComponent, InventoryRelayedEvent<GetBlurEvent>>(OnGetBlur);
}
private void OnGetBlur(EntityUid uid, VisionCorrectionComponent component, InventoryRelayedEvent<GetBlurEvent> args)
private void OnGetBlur(Entity<VisionCorrectionComponent> glasses, ref InventoryRelayedEvent<GetBlurEvent> args)
{
args.Args.Blur += component.VisionBonus;
args.Args.Blur += glasses.Comp.VisionBonus;
args.Args.CorrectionPower *= glasses.Comp.CorrectionPower;
}
private void OnDamageChanged(EntityUid uid, BlindableComponent component, ref EyeDamageChangedEvent args)
public void UpdateBlurMagnitude(Entity<BlindableComponent?> ent)
{
UpdateBlurMagnitude(uid, component);
}
private void UpdateBlurMagnitude(EntityUid uid, BlindableComponent? component = null)
{
if (!Resolve(uid, ref component, false))
if (!Resolve(ent.Owner, ref ent.Comp, false))
return;
var ev = new GetBlurEvent(component.EyeDamage);
RaiseLocalEvent(uid, ev);
var ev = new GetBlurEvent(ent.Comp.EyeDamage);
RaiseLocalEvent(ent, ev);
var blur = Math.Clamp(0, ev.Blur, BlurryVisionComponent.MaxMagnitude);
var blur = Math.Clamp(ev.Blur, 0, BlurryVisionComponent.MaxMagnitude);
if (blur <= 0)
{
RemCompDeferred<BlurryVisionComponent>(uid);
RemCompDeferred<BlurryVisionComponent>(ent);
return;
}
var blurry = EnsureComp<BlurryVisionComponent>(uid);
var blurry = EnsureComp<BlurryVisionComponent>(ent);
blurry.Magnitude = blur;
Dirty(blurry);
blurry.CorrectionPower = ev.CorrectionPower;
Dirty(ent, blurry);
}
private void OnGlassesEquipped(EntityUid uid, VisionCorrectionComponent component, GotEquippedEvent args)
private void OnGlassesEquipped(Entity<VisionCorrectionComponent> glasses, ref GotEquippedEvent args)
{
UpdateBlurMagnitude(uid);
UpdateBlurMagnitude(args.Equipee);
}
private void OnGlassesUnequipped(EntityUid uid, VisionCorrectionComponent component, GotUnequippedEvent args)
private void OnGlassesUnequipped(Entity<VisionCorrectionComponent> glasses, ref GotUnequippedEvent args)
{
UpdateBlurMagnitude(uid);
UpdateBlurMagnitude(args.Equipee);
}
}
@ -61,6 +59,7 @@ public sealed class GetBlurEvent : EntityEventArgs, IInventoryRelayEvent
{
public readonly float BaseBlur;
public float Blur;
public float CorrectionPower = BlurryVisionComponent.DefaultCorrectionPower;
public GetBlurEvent(float blur)
{

View file

@ -0,0 +1,141 @@
using Content.Shared.Actions;
using Content.Shared.Eye.Blinding.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Shared.Eye.Blinding.Systems;
public sealed class EyeClosingSystem : EntitySystem
{
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EyeClosingComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<EyeClosingComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<EyeClosingComponent, ToggleEyesActionEvent>(OnToggleAction);
SubscribeLocalEvent<EyeClosingComponent, CanSeeAttemptEvent>(OnTrySee);
SubscribeLocalEvent<EyeClosingComponent, AfterAutoHandleStateEvent>(OnHandleState);
}
private void OnMapInit(Entity<EyeClosingComponent> eyelids, ref MapInitEvent args)
{
_actionsSystem.AddAction(eyelids, ref eyelids.Comp.EyeToggleActionEntity, eyelids.Comp.EyeToggleAction);
Dirty(eyelids);
}
private void OnShutdown(Entity<EyeClosingComponent> eyelids, ref ComponentShutdown args)
{
_actionsSystem.RemoveAction(eyelids, eyelids.Comp.EyeToggleActionEntity);
SetEyelids((eyelids.Owner, eyelids.Comp), false);
}
private void OnToggleAction(Entity<EyeClosingComponent> eyelids, ref ToggleEyesActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
SetEyelids((eyelids.Owner, eyelids.Comp), !eyelids.Comp.EyesClosed);
}
private void OnHandleState(Entity<EyeClosingComponent> eyelids, ref AfterAutoHandleStateEvent args)
{
DoAudioFeedback((eyelids.Owner, eyelids.Comp), eyelids.Comp.EyesClosed);
}
private void OnTrySee(Entity<EyeClosingComponent> eyelids, ref CanSeeAttemptEvent args)
{
if (eyelids.Comp.EyesClosed)
args.Cancel();
}
/// <summary>
/// Checks whether or not the entity's eyelids are closed.
/// </summary>
/// <param name="eyelids">The entity that contains an EyeClosingComponent</param>
/// <returns>Exactly what this function says on the tin. True if eyes are closed, false if they're open.</returns>
public bool AreEyesClosed(Entity<EyeClosingComponent?> eyelids)
{
return Resolve(eyelids, ref eyelids.Comp, false) && eyelids.Comp.EyesClosed;
}
/// <summary>
/// Sets whether or not the entity's eyelids are closed.
/// </summary>
/// <param name="eyelids">The entity that contains an EyeClosingComponent</param>
/// <param name="value">Set to true to close the entity's eyes. Set to false to open them</param>
public void SetEyelids(Entity<EyeClosingComponent?> eyelids, bool value)
{
if (!Resolve(eyelids, ref eyelids.Comp))
return;
if (eyelids.Comp.EyesClosed == value)
return;
eyelids.Comp.EyesClosed = value;
Dirty(eyelids);
if (eyelids.Comp.EyeToggleActionEntity != null)
_actionsSystem.SetToggled(eyelids.Comp.EyeToggleActionEntity, eyelids.Comp.EyesClosed);
_blindableSystem.UpdateIsBlind(eyelids.Owner);
DoAudioFeedback(eyelids, eyelids.Comp.EyesClosed);
}
public void DoAudioFeedback(Entity<EyeClosingComponent?> eyelids, bool eyelidTarget)
{
if (!Resolve(eyelids, ref eyelids.Comp))
return;
if (!_net.IsClient || !_timing.IsFirstTimePredicted)
return;
if (eyelids.Comp.PreviousEyelidPosition == eyelidTarget)
return;
eyelids.Comp.PreviousEyelidPosition = eyelidTarget;
if (_playerManager.TryGetSessionByEntity(eyelids, out var session))
_audio.PlayGlobal(eyelidTarget ? eyelids.Comp.EyeCloseSound : eyelids.Comp.EyeOpenSound, session);
}
public void UpdateEyesClosable(Entity<BlindableComponent?> blindable)
{
if (!Resolve(blindable, ref blindable.Comp, false))
return;
var ev = new GetBlurEvent(blindable.Comp.EyeDamage);
RaiseLocalEvent(blindable.Owner, ev);
if (_entityManager.TryGetComponent<EyeClosingComponent>(blindable, out var eyelids) && !eyelids.NaturallyCreated)
return;
if (ev.Blur < BlurryVisionComponent.MaxMagnitude || ev.Blur >= BlindableComponent.MaxDamage)
{
RemCompDeferred<EyeClosingComponent>(blindable);
return;
}
var naturalEyelids = EnsureComp<EyeClosingComponent>(blindable);
naturalEyelids.NaturallyCreated = true;
Dirty(blindable);
}
}
public sealed partial class ToggleEyesActionEvent : InstantActionEvent
{
}

View file

@ -12,10 +12,10 @@ namespace Content.Shared.Item;
/// </summary>
[RegisterComponent]
[NetworkedComponent]
[Access(typeof(SharedItemSystem))]
[Access(typeof(SharedItemSystem)), AutoGenerateComponentState(true)]
public sealed partial class ItemComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
[Access(typeof(SharedItemSystem))]
public ProtoId<ItemSizePrototype> Size = "Small";
@ -25,7 +25,7 @@ public sealed partial class ItemComponent : Component
[Access(typeof(SharedItemSystem))]
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
[DataField, AutoNetworkedField]
public string? HeldPrefix;
/// <summary>
@ -56,19 +56,6 @@ public sealed partial class ItemComponent : Component
public float StoredRotation = 0;
}
[Serializable, NetSerializable]
public sealed class ItemComponentState : ComponentState
{
public ProtoId<ItemSizePrototype> Size { get; }
public string? HeldPrefix { get; }
public ItemComponentState(ProtoId<ItemSizePrototype> size, string? heldPrefix)
{
Size = size;
HeldPrefix = heldPrefix;
}
}
/// <summary>
/// Raised when an item's visual state is changed. The event is directed at the entity that contains this item, so
/// that it can properly update its hands or inventory sprites and GUI.

View file

@ -1,16 +1,16 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Item;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Handles the active sound being played continuously with some items that are activated (ie e-sword hum).
/// </summary>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ItemToggleActiveSoundComponent : Component
{
/// <summary>
/// The continuous noise this item makes when it's activated (like an e-sword's hum). This loops.
/// The continuous noise this item makes when it's activated (like an e-sword's hum).
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public SoundSpecifier? ActiveSound;
@ -18,17 +18,6 @@ public sealed partial class ItemToggleActiveSoundComponent : Component
/// <summary>
/// Used when the item emits sound while active.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
[ViewVariables(VVAccess.ReadWrite), DataField]
public EntityUid? PlayingStream;
}
/// <summary>
/// Raised in order to effect changes upon the ActiveSound of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleActiveSoundUpdateEvent(bool Activated, bool Predicted, EntityUid? User)
{
public bool Activated = Activated;
public bool Predicted = Predicted;
public EntityUid? User = User;
}

View file

@ -1,7 +1,7 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Item;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Handles generic item toggles, like a welder turning on and off, or an e-sword.
@ -54,7 +54,7 @@ public sealed partial class ItemToggleComponent : Component
public record struct ItemToggleActivateAttemptEvent(EntityUid? User)
{
public bool Cancelled = false;
public EntityUid? User = User;
public readonly EntityUid? User = User;
}
/// <summary>
@ -64,63 +64,34 @@ public record struct ItemToggleActivateAttemptEvent(EntityUid? User)
public record struct ItemToggleDeactivateAttemptEvent(EntityUid? User)
{
public bool Cancelled = false;
public EntityUid? User = User;
public readonly EntityUid? User = User;
}
/// <summary>
/// Raised directed on an entity any sort of toggle is complete.
/// </summary>
[ByRefEvent]
public record struct ItemToggleDoneEvent(bool Activated, EntityUid? User)
public readonly record struct ItemToggledEvent(bool Predicted, bool Activated, EntityUid? User)
{
public bool Activated = Activated;
public EntityUid? User = User;
public readonly bool Predicted = Predicted;
public readonly bool Activated = Activated;
public readonly EntityUid? User = User;
}
/// <summary>
/// Raised in order to play a toggle sound effect.
/// Raised directed on an entity when an itemtoggle is activated.
/// </summary>
[ByRefEvent]
public record struct ItemTogglePlayToggleSoundEvent(bool Activated, bool Predicted, EntityUid? User)
public readonly record struct ItemToggleActivatedEvent(EntityUid? User)
{
public bool Activated = Activated;
public bool Predicted = Predicted;
public EntityUid? User = User;
public readonly EntityUid? User = User;
}
/// <summary>
/// Raised in order to play a failure to toggle sound effect.
/// Raised directed on an entity when an itemtoggle is deactivated.
/// </summary>
[ByRefEvent]
public record struct ItemTogglePlayFailSoundEvent(bool Predicted, EntityUid? User)
public readonly record struct ItemToggleDeactivatedEvent(EntityUid? User)
{
public bool Predicted = Predicted;
public EntityUid? User = User;
}
/// <summary>
/// Raised in order to effect changes upon the Light component of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleLightUpdateEvent(bool Activated)
{
public bool Activated = Activated;
}
/// <summary>
/// Raised in order to effect changes upon the Appearance component of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleAppearanceUpdateEvent(bool Activated)
{
public bool Activated = Activated;
}
/// <summary>
/// Raised in order to effect changes upon the Reflect component of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleReflectUpdateEvent(bool Activated)
{
public bool Activated = Activated;
public readonly EntityUid? User = User;
}

View file

@ -1,11 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Item;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Handles whether the item is hot when toggled on.
/// Handles whether the item is hot when toggled on.
/// </summary>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ItemToggleHotComponent : Component
{
/// <summary>

View file

@ -1,16 +1,16 @@
using Robust.Shared.GameStates;
using Robust.Shared.Audio;
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Item;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Handles the changes to the melee weapon component when the item is toggled.
/// Handles the changes to the melee weapon component when the item is toggled.
/// </summary>
/// <remarks>
/// You can change the damage, sound on hit, on swing, as well as hidden status while activated.
/// </remarks>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ItemToggleMeleeWeaponComponent : Component
{
/// <summary>
@ -67,13 +67,3 @@ public sealed partial class ItemToggleMeleeWeaponComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public bool DeactivatedSecret = false;
}
/// <summary>
/// Raised in order to effect changes upon the MeleeWeaponComponent of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleMeleeWeaponUpdateEvent(bool Activated)
{
public bool Activated = Activated;
}

View file

@ -1,15 +1,15 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Item;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Handles the changes to the item size when toggled.
/// Handles the changes to the item size when toggled.
/// </summary>
/// <remarks>
/// You can change the size when activated or not. By default the sizes are copied from the item.
/// </remarks>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ItemToggleSizeComponent : Component
{
/// <summary>
@ -24,12 +24,3 @@ public sealed partial class ItemToggleSizeComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public ProtoId<ItemSizePrototype>? DeactivatedSize = null;
}
/// <summary>
/// Raised in order to effect changes upon the MeleeWeaponComponent of the entity.
/// </summary>
[ByRefEvent]
public record struct ItemToggleSizeUpdateEvent(bool Activated)
{
public bool Activated = Activated;
}

View file

@ -1,11 +1,10 @@
using Content.Shared.Interaction.Events;
using Content.Shared.Toggleable;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Temperature;
using Content.Shared.Toggleable;
using Content.Shared.Wieldable;
using Content.Shared.Wieldable.Components;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Network;
namespace Content.Shared.Item.ItemToggle;
@ -29,12 +28,10 @@ public abstract class SharedItemToggleSystem : EntitySystem
SubscribeLocalEvent<ItemToggleComponent, ItemUnwieldedEvent>(TurnOffonUnwielded);
SubscribeLocalEvent<ItemToggleComponent, ItemWieldedEvent>(TurnOnonWielded);
SubscribeLocalEvent<ItemToggleComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<ItemToggleHotComponent, IsHotEvent>(OnIsHotEvent);
SubscribeLocalEvent<ItemToggleActiveSoundComponent, ItemToggleActiveSoundUpdateEvent>(UpdateActiveSound);
SubscribeLocalEvent<AppearanceComponent, ItemToggleAppearanceUpdateEvent>(UpdateAppearance);
SubscribeLocalEvent<ItemToggleComponent, ItemToggleLightUpdateEvent>(UpdateLight);
SubscribeLocalEvent<ItemToggleComponent, ItemTogglePlayToggleSoundEvent>(PlayToggleSound);
SubscribeLocalEvent<ItemToggleComponent, ItemTogglePlayFailSoundEvent>(PlayFailToggleSound);
SubscribeLocalEvent<ItemToggleActiveSoundComponent, ItemToggledEvent>(UpdateActiveSound);
}
private void OnUseInHand(EntityUid uid, ItemToggleComponent itemToggle, UseInHandEvent args)
@ -48,7 +45,7 @@ public abstract class SharedItemToggleSystem : EntitySystem
}
/// <summary>
/// Used when an item is attempted to be toggled.
/// Used when an item is attempted to be toggled.
/// </summary>
public void Toggle(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null)
{
@ -81,9 +78,10 @@ public abstract class SharedItemToggleSystem : EntitySystem
if (attempt.Cancelled)
{
//Raises the event to play the failure to activate noise.
var evPlayFailToggleSound = new ItemTogglePlayFailSoundEvent(Predicted: predicted, user);
RaiseLocalEvent(uid, ref evPlayFailToggleSound);
if (predicted)
_audio.PlayPredicted(itemToggle.SoundFailToActivate, uid, user);
else
_audio.PlayPvs(itemToggle.SoundFailToActivate, uid);
return false;
}
@ -92,16 +90,7 @@ public abstract class SharedItemToggleSystem : EntitySystem
if (predicted == false && _netManager.IsClient)
return true;
Activate(uid, itemToggle);
var evPlayToggleSound = new ItemTogglePlayToggleSoundEvent(Activated: true, Predicted: predicted, user);
RaiseLocalEvent(uid, ref evPlayToggleSound);
var evActiveSound = new ItemToggleActiveSoundUpdateEvent(Activated: true, Predicted: predicted, user);
RaiseLocalEvent(uid, ref evActiveSound);
var toggleUsed = new ItemToggleDoneEvent(Activated: true, user);
RaiseLocalEvent(uid, ref toggleUsed);
Activate(uid, itemToggle, predicted, user);
return true;
}
@ -129,61 +118,78 @@ public abstract class SharedItemToggleSystem : EntitySystem
if (predicted == false && _netManager.IsClient)
return true;
Deactivate(uid, itemToggle);
var evPlayToggleSound = new ItemTogglePlayToggleSoundEvent(Activated: false, Predicted: predicted, user);
RaiseLocalEvent(uid, ref evPlayToggleSound);
var evActiveSound = new ItemToggleActiveSoundUpdateEvent(Activated: false, Predicted: predicted, user);
RaiseLocalEvent(uid, ref evActiveSound);
var toggleUsed = new ItemToggleDoneEvent(Activated: false, user);
RaiseLocalEvent(uid, ref toggleUsed);
Deactivate(uid, itemToggle, predicted, user);
return true;
}
/// <summary>
/// Used to make the actual changes to the item's components on activation.
/// </summary>
private void Activate(EntityUid uid, ItemToggleComponent itemToggle)
private void Activate(EntityUid uid, ItemToggleComponent itemToggle, bool predicted, EntityUid? user = null)
{
UpdateComponents(uid, itemToggle.Activated = true);
// TODO: Fix this hardcoding
TryComp(uid, out AppearanceComponent? appearance);
_appearance.SetData(uid, ToggleableLightVisuals.Enabled, true, appearance);
_appearance.SetData(uid, ToggleVisuals.Toggled, true, appearance);
if (_light.TryGetLight(uid, out var light))
{
_light.SetEnabled(uid, true, light);
}
SoundSpecifier? soundToPlay = itemToggle.SoundActivate;
if (soundToPlay == null)
return;
if (predicted)
_audio.PlayPredicted(soundToPlay, uid, user);
else
_audio.PlayPvs(soundToPlay, uid);
// END FIX HARDCODING
var toggleUsed = new ItemToggledEvent(predicted, Activated: true, user);
RaiseLocalEvent(uid, ref toggleUsed);
var activev = new ItemToggleActivatedEvent(user);
RaiseLocalEvent(uid, ref activev);
itemToggle.Activated = true;
Dirty(uid, itemToggle);
}
/// <summary>
/// Used to make the actual changes to the item's components on deactivation.
/// </summary>
private void Deactivate(EntityUid uid, ItemToggleComponent itemToggle)
private void Deactivate(EntityUid uid, ItemToggleComponent itemToggle, bool predicted, EntityUid? user = null)
{
UpdateComponents(uid, itemToggle.Activated = false);
// TODO: Fix this hardcoding
TryComp(uid, out AppearanceComponent? appearance);
_appearance.SetData(uid, ToggleableLightVisuals.Enabled, false, appearance);
_appearance.SetData(uid, ToggleVisuals.Toggled, false, appearance);
if (_light.TryGetLight(uid, out var light))
{
_light.SetEnabled(uid, false, light);
}
var soundToPlay = itemToggle.SoundDeactivate;
if (predicted)
_audio.PlayPredicted(soundToPlay, uid, user);
else
_audio.PlayPvs(soundToPlay, uid);
// END FIX HARDCODING
var toggleUsed = new ItemToggledEvent(predicted, Activated: false, user);
RaiseLocalEvent(uid, ref toggleUsed);
var activev = new ItemToggleDeactivatedEvent(user);
RaiseLocalEvent(uid, ref activev);
itemToggle.Activated = false;
Dirty(uid, itemToggle);
}
/// <summary>
/// Used to raise events to update components on toggle.
/// </summary>
private void UpdateComponents(EntityUid uid, bool activated)
{
var evSize = new ItemToggleSizeUpdateEvent(activated);
RaiseLocalEvent(uid, ref evSize);
var evMelee = new ItemToggleMeleeWeaponUpdateEvent(activated);
RaiseLocalEvent(uid, ref evMelee);
var evAppearance = new ItemToggleAppearanceUpdateEvent(activated);
RaiseLocalEvent(uid, ref evAppearance);
var evLight = new ItemToggleLightUpdateEvent(activated);
RaiseLocalEvent(uid, ref evLight);
var evReflect = new ItemToggleReflectUpdateEvent(activated);
RaiseLocalEvent(uid, ref evReflect);
}
/// <summary>
/// Used for items that require to be wielded in both hands to activate. For instance the dual energy sword will turn off if not wielded.
/// </summary>
@ -219,30 +225,10 @@ public abstract class SharedItemToggleSystem : EntitySystem
args.IsHot = IsActivated(uid);
}
/// <summary>
/// Used to update item appearance.
/// </summary>
private void UpdateAppearance(EntityUid uid, AppearanceComponent appearance, ref ItemToggleAppearanceUpdateEvent args)
{
_appearance.SetData(uid, ToggleableLightVisuals.Enabled, args.Activated, appearance);
_appearance.SetData(uid, ToggleVisuals.Toggled, args.Activated, appearance);
}
/// <summary>
/// Used to update light settings.
/// </summary>
private void UpdateLight(EntityUid uid, ItemToggleComponent comp, ref ItemToggleLightUpdateEvent args)
{
if (!_light.TryGetLight(uid, out var light))
return;
_light.SetEnabled(uid, args.Activated, light);
}
/// <summary>
/// Used to update the looping active sound linked to the entity.
/// </summary>
private void UpdateActiveSound(EntityUid uid, ItemToggleActiveSoundComponent activeSound, ref ItemToggleActiveSoundUpdateEvent args)
private void UpdateActiveSound(EntityUid uid, ItemToggleActiveSoundComponent activeSound, ref ItemToggledEvent args)
{
if (args.Activated)
{
@ -259,35 +245,4 @@ public abstract class SharedItemToggleSystem : EntitySystem
activeSound.PlayingStream = _audio.Stop(activeSound.PlayingStream);
}
}
/// <summary>
/// Used to play a toggle sound.
/// </summary>
private void PlayToggleSound(EntityUid uid, ItemToggleComponent itemToggle, ref ItemTogglePlayToggleSoundEvent args)
{
SoundSpecifier? soundToPlay;
if (args.Activated)
soundToPlay = itemToggle.SoundActivate;
else
soundToPlay = itemToggle.SoundDeactivate;
if (soundToPlay == null)
return;
if (args.Predicted)
_audio.PlayPredicted(soundToPlay, uid, args.User);
else
_audio.PlayPvs(soundToPlay, uid);
}
/// <summary>
/// Used to play a failure to toggle sound.
/// </summary>
private void PlayFailToggleSound(EntityUid uid, ItemToggleComponent itemToggle, ref ItemTogglePlayFailSoundEvent args)
{
if (args.Predicted)
_audio.PlayPredicted(itemToggle.SoundFailToActivate, uid, args.User);
else
_audio.PlayPvs(itemToggle.SoundFailToActivate, uid);
}
}

View file

@ -2,6 +2,7 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Verbs;
using Content.Shared.Examine;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Storage;
using JetBrains.Annotations;
using Robust.Shared.Containers;
@ -21,14 +22,17 @@ public abstract class SharedItemSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<ItemComponent, GetVerbsEvent<InteractionVerb>>(AddPickupVerb);
SubscribeLocalEvent<ItemComponent, InteractHandEvent>(OnHandInteract, before: new []{typeof(SharedItemSystem)});
SubscribeLocalEvent<ItemComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<ItemComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<ItemComponent, InteractHandEvent>(OnHandInteract);
SubscribeLocalEvent<ItemComponent, AfterAutoHandleStateEvent>(OnItemAutoState);
SubscribeLocalEvent<ItemComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<ItemToggleSizeComponent, ItemToggleSizeUpdateEvent>(OnItemToggle);
SubscribeLocalEvent<ItemToggleSizeComponent, ItemToggledEvent>(OnItemToggle);
}
private void OnItemAutoState(EntityUid uid, ItemComponent component, ref AfterAutoHandleStateEvent args)
{
SetHeldPrefix(uid, component.HeldPrefix, force: true, component);
}
#region Public API
@ -42,12 +46,12 @@ public abstract class SharedItemSystem : EntitySystem
Dirty(uid, component);
}
public void SetHeldPrefix(EntityUid uid, string? heldPrefix, ItemComponent? component = null)
public void SetHeldPrefix(EntityUid uid, string? heldPrefix, bool force = false, ItemComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return;
if (component.HeldPrefix == heldPrefix)
if (!force && component.HeldPrefix == heldPrefix)
return;
component.HeldPrefix = heldPrefix;
@ -81,20 +85,6 @@ public abstract class SharedItemSystem : EntitySystem
args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false);
}
private void OnHandleState(EntityUid uid, ItemComponent component, ref ComponentHandleState args)
{
if (args.Current is not ItemComponentState state)
return;
component.Size = state.Size;
SetHeldPrefix(uid, state.HeldPrefix, component);
}
private void OnGetState(EntityUid uid, ItemComponent component, ref ComponentGetState args)
{
args.State = new ItemComponentState(component.Size, component.HeldPrefix);
}
private void AddPickupVerb(EntityUid uid, ItemComponent component, GetVerbsEvent<InteractionVerb> args)
{
if (args.Hands == null ||
@ -211,7 +201,7 @@ public abstract class SharedItemSystem : EntitySystem
/// <summary>
/// Used to update the Item component on item toggle (specifically size).
/// </summary>
private void OnItemToggle(EntityUid uid, ItemToggleSizeComponent itemToggleSize, ItemToggleSizeUpdateEvent args)
private void OnItemToggle(EntityUid uid, ItemToggleSizeComponent itemToggleSize, ItemToggledEvent args)
{
if (!TryComp(uid, out ItemComponent? item))
return;

View file

@ -1,8 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Emag.Systems;
using Content.Shared.Materials;
using Content.Shared.Research.Prototypes;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared.Lathe;
@ -14,11 +16,15 @@ public abstract class SharedLatheSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
private readonly Dictionary<string, List<LatheRecipePrototype>> _inverseRecipeDictionary = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EmagLatheRecipesComponent, GotEmaggedEvent>(OnEmagged);
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
BuildInverseRecipeDictionary();
}
[PublicAPI]
@ -53,4 +59,28 @@ public abstract class SharedLatheSystem : EntitySystem
=> reduce ? (int) MathF.Ceiling(original * multiplier) : original;
protected abstract bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component);
private void OnPrototypesReloaded(PrototypesReloadedEventArgs obj)
{
if (!obj.WasModified<LatheRecipePrototype>())
return;
BuildInverseRecipeDictionary();
}
private void BuildInverseRecipeDictionary()
{
_inverseRecipeDictionary.Clear();
foreach (var latheRecipe in _proto.EnumeratePrototypes<LatheRecipePrototype>())
{
_inverseRecipeDictionary.GetOrNew(latheRecipe.Result).Add(latheRecipe);
}
}
public bool TryGetRecipesFromEntity(string prototype, [NotNullWhen(true)] out List<LatheRecipePrototype>? recipes)
{
recipes = new();
if (_inverseRecipeDictionary.TryGetValue(prototype, out var r))
recipes.AddRange(r);
return recipes.Count != 0;
}
}

View file

@ -21,6 +21,7 @@ namespace Content.Shared.Light
public enum PoweredLightLayers : byte
{
Base
Base,
Glow
}
}

View file

@ -81,7 +81,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
{
if (!Resolve(uid, ref component))
return 0; //you have nothing
return !component.Storage.TryGetValue(material, out var amount) ? 0 : amount;
return component.Storage.GetValueOrDefault(material, 0);
}
/// <summary>
@ -123,9 +123,35 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
{
if (!Resolve(uid, ref component))
return false;
return CanTakeVolume(uid, volume, component) &&
(component.MaterialWhiteList == null || component.MaterialWhiteList.Contains(materialId)) &&
(!component.Storage.TryGetValue(materialId, out var amount) || amount + volume >= 0);
if (!CanTakeVolume(uid, volume, component))
return false;
if (component.MaterialWhiteList != null && !component.MaterialWhiteList.Contains(materialId))
return false;
var amount = component.Storage.GetValueOrDefault(materialId);
return amount + volume >= 0;
}
/// <summary>
/// Checks if the specified materials can be changed by the specified volumes.
/// </summary>
/// <param name="entity"></param>
/// <param name="materials"></param>
/// <returns>If the amount can be changed</returns>
public bool CanChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
{
if (!Resolve(entity, ref entity.Comp))
return false;
foreach (var (material, amount) in materials)
{
if (!CanChangeMaterialAmount(entity, material, amount, entity.Comp))
return false;
}
return true;
}
/// <summary>
@ -136,20 +162,47 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
/// <param name="materialId"></param>
/// <param name="volume"></param>
/// <param name="component"></param>
/// <param name="dirty"></param>
/// <returns>If it was successful</returns>
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null)
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool dirty = true)
{
if (!Resolve(uid, ref component))
return false;
if (!CanChangeMaterialAmount(uid, materialId, volume, component))
return false;
if (!component.Storage.ContainsKey(materialId))
component.Storage.Add(materialId, 0);
component.Storage.TryAdd(materialId, 0);
component.Storage[materialId] += volume;
var ev = new MaterialAmountChangedEvent();
RaiseLocalEvent(uid, ref ev);
Dirty(component);
if (dirty)
Dirty(uid, component);
return true;
}
/// <summary>
/// Changes the amount of a specific material in the storage.
/// Still respects the filters in place.
/// </summary>
/// <param name="entity"></param>
/// <param name="materials"></param>
/// <returns>If the amount can be changed</returns>
public bool TryChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
{
if (!Resolve(entity, ref entity.Comp))
return false;
if (!CanChangeMaterialAmount(entity, materials))
return false;
foreach (var (material, amount) in materials)
{
if (!TryChangeMaterialAmount(entity, material, amount, entity.Comp, false))
return false;
}
Dirty(entity, entity.Comp);
return true;
}
@ -225,7 +278,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
insertingComp.MaterialColor = lastMat?.Color;
}
_appearance.SetData(receiver, MaterialStorageVisuals.Inserting, true);
Dirty(insertingComp);
Dirty(receiver, insertingComp);
var ev = new MaterialEntityInsertedEvent(material);
RaiseLocalEvent(receiver, ref ev);
@ -245,7 +298,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
var ev = new GetMaterialWhitelistEvent(uid);
RaiseLocalEvent(uid, ref ev);
component.MaterialWhiteList = ev.Whitelist;
Dirty(component);
Dirty(uid, component);
}
private void OnInteractUsing(EntityUid uid, MaterialStorageComponent component, InteractUsingEvent args)

View file

@ -13,7 +13,7 @@ namespace Content.Shared.Ninja.Components;
/// Component for ninja suit abilities and power consumption.
/// As an implementation detail, dashing with katana is a suit action which isn't ideal.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedNinjaSuitSystem))]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedNinjaSuitSystem)), AutoGenerateComponentState]
public sealed partial class NinjaSuitComponent : Component
{
/// <summary>

View file

@ -9,7 +9,7 @@ namespace Content.Shared.Sericulture;
/// Should be applied to any mob that you want to be able to produce any material with an action and the cost of hunger.
/// TODO: Probably adjust this to utilize organs?
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedSericultureSystem))]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedSericultureSystem)), AutoGenerateComponentState]
public sealed partial class SericultureComponent : Component
{
/// <summary>

View file

@ -7,7 +7,7 @@ namespace Content.Shared.Teleportation.Components;
/// Marks an entity as being a 'portal' which teleports entities sent through it to linked entities.
/// Relies on <see cref="LinkedEntityComponent"/> being set up.
/// </summary>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class PortalComponent : Component
{
/// <summary>

View file

@ -1,5 +1,5 @@
using Content.Shared.Examine;
using Content.Shared.Eye.Blinding;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.IdentityManagement;
using Robust.Shared.Network;
@ -12,6 +12,7 @@ namespace Content.Shared.Traits.Assorted;
public sealed class PermanentBlindnessSystem : EntitySystem
{
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly BlindableSystem _blinding = default!;
/// <inheritdoc/>
@ -19,31 +20,45 @@ public sealed class PermanentBlindnessSystem : EntitySystem
{
SubscribeLocalEvent<PermanentBlindnessComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<PermanentBlindnessComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<PermanentBlindnessComponent, CanSeeAttemptEvent>(OnTrySee);
SubscribeLocalEvent<PermanentBlindnessComponent, EyeDamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<PermanentBlindnessComponent, ExaminedEvent>(OnExamined);
}
private void OnExamined(EntityUid uid, PermanentBlindnessComponent component, ExaminedEvent args)
private void OnExamined(Entity<PermanentBlindnessComponent> blindness, ref ExaminedEvent args)
{
if (args.IsInDetailsRange && !_net.IsClient)
{
args.PushMarkup(Loc.GetString("permanent-blindness-trait-examined", ("target", Identity.Entity(uid, EntityManager))));
args.PushMarkup(Loc.GetString("permanent-blindness-trait-examined", ("target", Identity.Entity(blindness, EntityManager))));
}
}
private void OnShutdown(EntityUid uid, PermanentBlindnessComponent component, ComponentShutdown args)
private void OnShutdown(Entity<PermanentBlindnessComponent> blindness, ref ComponentShutdown args)
{
_blinding.UpdateIsBlind(uid);
_blinding.UpdateIsBlind(blindness.Owner);
}
private void OnStartup(EntityUid uid, PermanentBlindnessComponent component, ComponentStartup args)
private void OnStartup(Entity<PermanentBlindnessComponent> blindness, ref ComponentStartup args)
{
_blinding.UpdateIsBlind(uid);
if (!_entityManager.TryGetComponent<BlindableComponent>(blindness, out var blindable))
return;
var damageToDeal = (int) BlurryVisionComponent.MaxMagnitude - blindable.EyeDamage;
if (damageToDeal <= 0)
return;
_blinding.AdjustEyeDamage(blindness.Owner, damageToDeal);
}
private void OnTrySee(EntityUid uid, PermanentBlindnessComponent component, CanSeeAttemptEvent args)
private void OnDamageChanged(Entity<PermanentBlindnessComponent> blindness, ref EyeDamageChangedEvent args)
{
if (component.LifeStage <= ComponentLifeStage.Running)
args.Cancel();
if (args.Damage >= BlurryVisionComponent.MaxMagnitude)
return;
if (!_entityManager.TryGetComponent<BlindableComponent>(blindness, out var blindable))
return;
var damageRestoration = (int) BlurryVisionComponent.MaxMagnitude - args.Damage;
_blinding.AdjustEyeDamage(blindness.Owner, damageRestoration);
}
}

View file

@ -13,6 +13,7 @@ using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Weapons.Melee.Components;
@ -29,6 +30,7 @@ using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Toolshed.Syntax;
using ItemToggleMeleeWeaponComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleMeleeWeaponComponent;
namespace Content.Shared.Weapons.Melee;
@ -74,7 +76,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
SubscribeLocalEvent<ItemToggleMeleeWeaponComponent, ItemToggleMeleeWeaponUpdateEvent>(OnItemToggle);
SubscribeLocalEvent<ItemToggleMeleeWeaponComponent, ItemToggledEvent>(OnItemToggle);
SubscribeAllEvent<HeavyAttackEvent>(OnHeavyAttack);
SubscribeAllEvent<LightAttackEvent>(OnLightAttack);
@ -864,7 +866,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
/// <summary>
/// Used to update the MeleeWeapon component on item toggle.
/// </summary>
private void OnItemToggle(EntityUid uid, ItemToggleMeleeWeaponComponent itemToggleMelee, ItemToggleMeleeWeaponUpdateEvent args)
private void OnItemToggle(EntityUid uid, ItemToggleMeleeWeaponComponent itemToggleMelee, ItemToggledEvent args)
{
if (!TryComp(uid, out MeleeWeaponComponent? meleeWeapon))
return;

View file

@ -6,6 +6,7 @@ using Content.Shared.Database;
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Components;
@ -23,7 +24,7 @@ namespace Content.Shared.Weapons.Reflect;
/// <summary>
/// This handles reflecting projectiles and hitscan shots.
/// </summary>
public abstract class SharedReflectSystem : EntitySystem
public sealed class ReflectSystem : EntitySystem
{
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
@ -41,13 +42,14 @@ public abstract class SharedReflectSystem : EntitySystem
SubscribeLocalEvent<ReflectComponent, ProjectileReflectAttemptEvent>(OnReflectCollide);
SubscribeLocalEvent<ReflectComponent, HitScanReflectAttemptEvent>(OnReflectHitscan);
SubscribeLocalEvent<ReflectUserComponent, ProjectileReflectAttemptEvent>(OnReflectUserCollide);
SubscribeLocalEvent<ReflectUserComponent, HitScanReflectAttemptEvent>(OnReflectUserHitscan);
SubscribeLocalEvent<ReflectComponent, GotEquippedEvent>(OnReflectEquipped);
SubscribeLocalEvent<ReflectComponent, GotUnequippedEvent>(OnReflectUnequipped);
SubscribeLocalEvent<ReflectComponent, GotEquippedHandEvent>(OnReflectHandEquipped);
SubscribeLocalEvent<ReflectComponent, GotUnequippedHandEvent>(OnReflectHandUnequipped);
SubscribeLocalEvent<ReflectComponent, ItemToggledEvent>(OnToggleReflect);
SubscribeLocalEvent<ReflectUserComponent, ProjectileReflectAttemptEvent>(OnReflectUserCollide);
SubscribeLocalEvent<ReflectUserComponent, HitScanReflectAttemptEvent>(OnReflectUserHitscan);
}
private void OnReflectUserHitscan(EntityUid uid, ReflectUserComponent component, ref HitScanReflectAttemptEvent args)
@ -209,6 +211,12 @@ public abstract class SharedReflectSystem : EntitySystem
RefreshReflectUser(args.User);
}
private void OnToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggledEvent args)
{
comp.Enabled = args.Activated;
Dirty(uid, comp);
}
/// <summary>
/// Refreshes whether someone has reflection potential so we can raise directed events on them.
/// </summary>

View file

@ -177,7 +177,7 @@ public sealed class WieldableSystem : EntitySystem
if (TryComp<ItemComponent>(used, out var item))
{
component.OldInhandPrefix = item.HeldPrefix;
_itemSystem.SetHeldPrefix(used, component.WieldedInhandPrefix, item);
_itemSystem.SetHeldPrefix(used, component.WieldedInhandPrefix, component: item);
}
component.Wielded = true;
@ -229,7 +229,7 @@ public sealed class WieldableSystem : EntitySystem
if (TryComp<ItemComponent>(uid, out var item))
{
_itemSystem.SetHeldPrefix(uid, component.OldInhandPrefix, item);
_itemSystem.SetHeldPrefix(uid, component.OldInhandPrefix, component: item);
}
component.Wielded = false;

View file

@ -196,3 +196,8 @@
copyright: 'Sound effects from https://quicksounds.com"'
license: CC0-1.0
source: https://quicksounds.com/library/sounds/grenade
- files: ["eye_open.ogg", "eye_close.ogg"]
copyright: Bhijn and Myr (github username deathride58)
license: CC0-1.0
source: https://github.com/space-wizards/space-station-14/pull/23212

Binary file not shown.

Binary file not shown.

View file

@ -82,3 +82,8 @@
license: "CC0-1.0"
copyright: "Taken from ScreamStudio on freesound.org"
source: "https://freesound.org/people/ScreamStudio/sounds/392617/"
- files: ["pop.ogg"]
license: "CC0-1.0"
copyright: "Taken from 0ne_one111yt on freesound.org"
source: "https://freesound.org/people/0ne_one111yt/sounds/478213/"

Binary file not shown.

View file

@ -1,29 +1,4 @@
Entries:
- author: Vasilis
changes:
- message: Pneumatic Cannons can no longer shoot arrows.
type: Tweak
id: 5016
time: '2023-10-17T22:58:05.0000000+00:00'
- author: Vasilis
changes:
- message: Spears and arrows can now only hold up to 2u of liquids instead of 5u.
type: Tweak
id: 5017
time: '2023-10-17T23:01:25.0000000+00:00'
- author: notquitehadouken
changes:
- message: The grey stick that shows up when you wide swing a weapon now looks like
the weapon used.
type: Tweak
id: 5018
time: '2023-10-18T01:12:00.0000000+00:00'
- author: metalgearsloth
changes:
- message: Fix vaulting mispredict.
type: Fix
id: 5019
time: '2023-10-18T05:11:33.0000000+00:00'
- author: daerSeebaer
changes:
- message: The AME controller now shows the current load and maximum capacity.
@ -3586,3 +3561,35 @@ Entries:
id: 5516
time: '2024-01-02T18:53:35.0000000+00:00'
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23319
- author: themias
changes:
- message: Welders can be refilled directly from wall fuel dispensers
type: Tweak
id: 5517
time: '2024-01-02T21:11:10.0000000+00:00'
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23376
- author: Admiral-Obvious-001
changes:
- message: Added a few words to body bag descriptor so you know they stop rot.
type: Add
id: 5518
time: '2024-01-03T01:36:18.0000000+00:00'
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23407
- author: CaasGit
changes:
- message: Give slimes their custom speech bubble!
type: Tweak
id: 5519
time: '2024-01-03T05:12:56.0000000+00:00'
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23415
- author: zzylex
changes:
- message: You can now make plungers stick to walls.
type: Tweak
- message: A sound is made when a plunger gets stuck to something.
type: Add
- message: You can now shoot plungers with bows.
type: Tweak
id: 5520
time: '2024-01-03T05:36:17.0000000+00:00'
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23406

View file

@ -4,6 +4,9 @@
[game]
hostname = "[EN] Wizard's Den Leviathan [US East 1]"
panic_bunker.enabled = false
panic_bunker.disable_with_admins = false
panic_bunker.enable_without_admins = false
[hub]
tags = "lang:en,region:am_n_e,rp:low"

View file

@ -4,6 +4,9 @@
[game]
hostname = "[EN] Wizard's Den Lizard [US West]"
panic_bunker.enabled = false
panic_bunker.disable_with_admins = false
panic_bunker.enable_without_admins = false
[hub]
tags = "lang:en,region:am_n_w,rp:low"

View file

@ -5,6 +5,11 @@
desc = "Official English Space Station 14 servers. Vanilla, low roleplay."
lobbyenabled = true
soft_max_players = 80
panic_bunker.enabled = true
panic_bunker.disable_with_admins = true
panic_bunker.enable_without_admins = true
panic_bunker.show_reason = true
panic_bunker.custom_reason = "You have not played on Wizard's Den server long enough to connect to this server. Please play on Wizard's Den Lizard or Wizard's Den Leviathan until you have more playtime."
[infolinks]
bug_report = "https://github.com/space-wizards/space-station-14/issues/new/choose"

View file

@ -0,0 +1,11 @@
flatpack-unpack-no-room = No room to unpack!
flatpack-examine = Use a [color=yellow]multitool[/color] to unpack this.
flatpack-entity-name = {$name} flatpack
flatpack-entity-description = A flatpack used for constructing {INDEFINITE($name)} {$name}.
flatpacker-item-slot-name = Machine board slot
flatpacker-ui-title = Flatpacker 1001
flatpacker-ui-materials-label = Materials
flatpacker-ui-cost-label = Packing Cost
flatpacker-ui-no-board-label = No board present!
flatpacker-ui-pack-button = Pack

View file

@ -19,6 +19,7 @@ ui-options-general-discord = Discord
ui-options-general-cursor = Cursor
ui-options-general-speech = Speech
ui-options-general-storage = Storage
ui-options-general-accessibility = Accessibility
## Audio menu
@ -44,6 +45,7 @@ ui-options-opaque-storage-window = Opaque storage window
ui-options-show-looc-on-head = Show LOOC chat above characters head
ui-options-fancy-speech = Show names in speech bubbles
ui-options-fancy-name-background = Add background to speech bubble names
ui-options-reduced-motion = Reduce motion of visual effects
ui-options-vsync = VSync
ui-options-fullscreen = Fullscreen
ui-options-lighting-label = Lighting Quality:

View file

@ -55,7 +55,12 @@ rev-headrev-count = {$initialCount ->
*[other] There were {$initialCount} Head Revolutionaries:
}
rev-headrev-player = {$title} converted {$count} {$count ->
rev-headrev-name-user = [color=#5e9cff]{$name}[/color] ([color=gray]{$username}[/color]) converted {$count} {$count ->
[one] person
*[other] people
}.
}
rev-headrev-name = [color=#5e9cff]{$name}[/color] converted {$count} {$count ->
[one] person
*[other] people
}

View file

@ -3,7 +3,7 @@
traitor-round-end-codewords = The codewords were: [color=White]{$codewords}[/color]
traitor-round-end-agent-name = traitor
objective-issuer-syndicate = [color=#87cefa]The Syndicate[/color]
objective-issuer-syndicate = [color=crimson]The Syndicate[/color]
# Shown at the end of a round of Traitor

View file

@ -8,6 +8,7 @@ research-discipline-civilian-services = Civilian Services
research-technology-fulton = Fultons
research-technology-salvage-equipment = Salvage Equipment
research-technology-advanced-powercells = Advanced Powercells
research-technology-mechanical-compression = Mechanical Compression
research-technology-compact-power = Compact Power
research-technology-industrial-engineering = Industrial Engineering
research-technology-power-generation = Power Generation

View file

@ -1,12 +1,12 @@
trait-blindness-name = Blindness
trait-blindness-desc = You lack vision
trait-blindness-desc = You are legally blind, and can't see clearly past a few meters in front of you.
trait-narcolepsy-name = Narcolepsy
trait-narcolepsy-decs = You fall asleep randomly
trait-pacifist-name = Pacifist
permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you.[/color]
permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you well, if at all.[/color]
trait-lightweight-name = Lightweight Drunk
trait-lightweight-desc = Alcohol has a stronger effect on you

View file

@ -36,6 +36,7 @@ wires-board-name-firelock = Firelock Control
wires-board-name-windoor = Windoor Control
wires-board-name-mech = Mech
wires-board-name-fatextractor = FatExtractor
wires-board-name-flatpacker = Flatpacker
# names that get displayed in the wire hacking hud & admin logs.

View file

@ -21758,13 +21758,6 @@ entities:
type: Transform
- canCollide: False
type: Physics
- proto: Dresser
entities:
- uid: 2458
components:
- pos: -19.5,-10.5
parent: 30
type: Transform
- proto: DresserCaptainFilled
entities:
- uid: 1639
@ -21824,6 +21817,13 @@ entities:
- pos: -26.5,21.5
parent: 30
type: Transform
- proto: DresserResearchDirectorFilled
entities:
- uid: 2458
components:
- pos: -19.5,-10.5
parent: 30
type: Transform
- proto: DrinkBottleOfNothingFull
entities:
- uid: 1601

File diff suppressed because it is too large Load diff

View file

@ -71431,13 +71431,6 @@ entities:
- pos: -29.5,-12.5
parent: 8364
type: Transform
- proto: CrateEngineeringAMEJar
entities:
- uid: 17715
components:
- pos: -10.5,-72.5
parent: 8364
type: Transform
- proto: CrateEngineeringAMEShielding
entities:
- uid: 17716
@ -81811,6 +81804,13 @@ entities:
- pos: -30.5,-24.5
parent: 8364
type: Transform
- proto: DresserResearchDirectorFilled
entities:
- uid: 17575
components:
- pos: 71.5,-33.5
parent: 8364
type: Transform
- proto: DrinkBeerBottleFull
entities:
- uid: 27600
@ -82191,6 +82191,11 @@ entities:
pos: 7.5,-90.5
parent: 8364
type: Transform
- uid: 15509
components:
- pos: -9.5,-65.5
parent: 8364
type: Transform
- uid: 17158
components:
- rot: -1.5707963267948966 rad
@ -144989,11 +144994,6 @@ entities:
- pos: -24.5,-68.5
parent: 8364
type: Transform
- uid: 21527
components:
- pos: -9.5,-65.5
parent: 8364
type: Transform
- uid: 22090
components:
- pos: -22.5,-71.5
@ -150285,11 +150285,6 @@ entities:
- pos: 30.5,-30.5
parent: 8364
type: Transform
- uid: 19213
components:
- pos: 71.5,-33.5
parent: 8364
type: Transform
- uid: 19286
components:
- rot: -1.5707963267948966 rad
@ -180760,13 +180755,6 @@ entities:
type: Transform
- proto: WarpPoint
entities:
- uid: 22214
components:
- pos: 66.5,-23.5
parent: 8364
type: Transform
- location: science
type: WarpPoint
- uid: 22219
components:
- pos: -49.5,18.5
@ -180825,20 +180813,6 @@ entities:
type: Transform
- location: Showroom
type: WarpPoint
- uid: 27706
components:
- pos: 70.5,-35.5
parent: 8364
type: Transform
- location: RD Office
type: WarpPoint
- uid: 27744
components:
- pos: -0.5,-12.5
parent: 8364
type: Transform
- location: AI Upload
type: WarpPoint
- proto: WaterCooler
entities:
- uid: 5522

View file

@ -17041,7 +17041,6 @@ entities:
- 25004
- 25944
- 23661
- 23792
type: DeviceList
- joinedGrid: 13329
type: AtmosDevice
@ -100266,29 +100265,6 @@ entities:
type: Transform
- proto: CrateEngineeringAMEJar
entities:
- uid: 23453
components:
- pos: 83.5,5.5
parent: 13329
type: Transform
- air:
volume: 200
immutable: False
temperature: 293.1495
moles:
- 3.0981817
- 11.655066
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
type: EntityStorage
- uid: 26563
components:
- pos: 74.5,-1.5
@ -111720,13 +111696,6 @@ entities:
- pos: 27.5,64.5
parent: 13329
type: Transform
- proto: DresserFilled
entities:
- uid: 26271
components:
- pos: 52.5,-37.5
parent: 13329
type: Transform
- proto: DresserHeadOfPersonnelFilled
entities:
- uid: 18915
@ -111748,6 +111717,13 @@ entities:
- pos: -5.5,-23.5
parent: 13329
type: Transform
- proto: DresserResearchDirectorFilled
entities:
- uid: 23453
components:
- pos: 52.5,-37.5
parent: 13329
type: Transform
- proto: DrinkAbsintheBottleFull
entities:
- uid: 1176
@ -118268,21 +118244,6 @@ entities:
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- uid: 23670
components:
- name: Air Mixer
type: MetaData
- rot: 1.5707963267948966 rad
pos: 76.5,-35.5
parent: 13329
type: Transform
- inletTwoConcentration: 0.22000003
inletOneConcentration: 0.78
type: GasMixer
- joinedGrid: 13329
type: AtmosDevice
- color: '#03FCD3FF'
type: AtmosPipeColor
- proto: GasOutletInjector
entities:
- uid: 5631
@ -120052,25 +120013,14 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23667
components:
- rot: 1.5707963267948966 rad
pos: 72.5,-35.5
parent: 13329
type: Transform
- uid: 23678
components:
- pos: 78.5,-35.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23680
- uid: 23665
components:
- rot: -1.5707963267948966 rad
pos: 77.5,-38.5
pos: 80.5,-32.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23696
components:
- rot: -1.5707963267948966 rad
@ -120095,30 +120045,6 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23719
components:
- rot: -1.5707963267948966 rad
pos: 81.5,-38.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23736
components:
- rot: -1.5707963267948966 rad
pos: 83.5,-35.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23737
components:
- rot: 1.5707963267948966 rad
pos: 81.5,-35.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23738
components:
- rot: 1.5707963267948966 rad
@ -120164,6 +120090,8 @@ entities:
pos: 79.5,-29.5
parent: 13329
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23833
components:
- pos: 101.5,-35.5
@ -141926,12 +141854,6 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23662
components:
- rot: 3.141592653589793 rad
pos: 72.5,-38.5
parent: 13329
type: Transform
- uid: 23663
components:
- rot: 3.141592653589793 rad
@ -141940,50 +141862,26 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23671
- uid: 23667
components:
- rot: 1.5707963267948966 rad
pos: 74.5,-35.5
- pos: 80.5,-29.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23672
- uid: 23668
components:
- rot: 1.5707963267948966 rad
pos: 75.5,-35.5
- pos: 80.5,-30.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23673
components:
- pos: 76.5,-36.5
- pos: 80.5,-31.5
parent: 13329
type: Transform
- uid: 23674
components:
- rot: -1.5707963267948966 rad
pos: 77.5,-35.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23675
components:
- rot: 3.141592653589793 rad
pos: 78.5,-36.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23676
components:
- rot: 3.141592653589793 rad
pos: 78.5,-37.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23682
components:
@ -142015,22 +141913,6 @@ entities:
pos: 90.5,-41.5
parent: 13329
type: Transform
- uid: 23720
components:
- rot: 3.141592653589793 rad
pos: 81.5,-37.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23721
components:
- rot: 3.141592653589793 rad
pos: 81.5,-36.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23722
components:
- rot: 1.5707963267948966 rad
@ -142075,49 +141957,6 @@ entities:
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23729
components:
- pos: 83.5,-29.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23730
components:
- pos: 83.5,-30.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23731
components:
- pos: 83.5,-31.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23733
components:
- pos: 83.5,-33.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23734
components:
- pos: 83.5,-34.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23743
components:
- rot: -1.5707963267948966 rad
pos: 80.5,-28.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23744
components:
- rot: -1.5707963267948966 rad
@ -142392,30 +142231,6 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23789
components:
- rot: -1.5707963267948966 rad
pos: 82.5,-32.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23790
components:
- rot: -1.5707963267948966 rad
pos: 81.5,-32.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23791
components:
- rot: -1.5707963267948966 rad
pos: 80.5,-32.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23821
components:
- rot: 1.5707963267948966 rad
@ -151621,18 +151436,13 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23666
- uid: 23670
components:
- rot: 1.5707963267948966 rad
pos: 72.5,-36.5
parent: 13329
type: Transform
- uid: 23679
components:
- rot: 1.5707963267948966 rad
pos: 76.5,-38.5
- pos: 80.5,-28.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23681
components:
- rot: 1.5707963267948966 rad
@ -151641,14 +151451,6 @@ entities:
type: Transform
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23685
components:
- rot: 1.5707963267948966 rad
pos: 80.5,-38.5
parent: 13329
type: Transform
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23701
components:
- rot: 3.141592653589793 rad
@ -151665,14 +151467,6 @@ entities:
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23732
components:
- rot: -1.5707963267948966 rad
pos: 83.5,-32.5
parent: 13329
type: Transform
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23741
components:
- rot: 3.141592653589793 rad
@ -152869,72 +152663,54 @@ entities:
type: AtmosDevice
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23662
components:
- rot: 3.141592653589793 rad
pos: 72.5,-38.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- uid: 23664
components:
- name: Nitro Pump
type: MetaData
- rot: 3.141592653589793 rad
pos: 72.5,-37.5
- pos: 70.5,-38.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- uid: 23665
- uid: 23666
components:
- name: Oxygen to Air Mixer
type: MetaData
- rot: 3.141592653589793 rad
pos: 76.5,-37.5
pos: 83.5,-29.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- uid: 23668
components:
- name: Nitro to Mix
type: MetaData
- rot: 1.5707963267948966 rad
pos: 73.5,-36.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#947507FF'
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23669
components:
- name: Nitro to Air Mixer
type: MetaData
- rot: 1.5707963267948966 rad
pos: 73.5,-35.5
- pos: 74.5,-38.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23684
- uid: 23672
components:
- name: Oxygen to Mix
type: MetaData
- rot: 3.141592653589793 rad
pos: 77.5,-37.5
pos: 76.5,-38.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- uid: 23686
- uid: 23674
components:
- name: Air to Mix
type: MetaData
- rot: 3.141592653589793 rad
pos: 80.5,-37.5
pos: 80.5,-38.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23700
components:
- name: CO2 Pump
@ -152961,6 +152737,8 @@ entities:
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23709
components:
- name: H2O Pump
@ -153007,18 +152785,6 @@ entities:
type: AtmosDevice
- color: '#03FCD3FF'
type: AtmosPipeColor
- uid: 23735
components:
- name: Distro Pump
type: MetaData
- rot: 1.5707963267948966 rad
pos: 82.5,-35.5
parent: 13329
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23817
components:
- rot: -1.5707963267948966 rad
@ -153027,6 +152793,8 @@ entities:
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23838
components:
- rot: -1.5707963267948966 rad
@ -153035,6 +152803,8 @@ entities:
type: Transform
- joinedGrid: 13329
type: AtmosDevice
- color: '#FF1212FF'
type: AtmosPipeColor
- uid: 23861
components:
- name: Mixer Out Pump
@ -154911,7 +154681,7 @@ entities:
type: AtmosDevice
- color: '#0335FCFF'
type: AtmosPipeColor
- uid: 23792
- uid: 23671
components:
- rot: 1.5707963267948966 rad
pos: 79.5,-32.5
@ -170172,32 +169942,36 @@ entities:
- pos: 29.527367,-48.423893
parent: 13329
type: Transform
- proto: ParticleAcceleratorControlBoxUnfinished
- proto: ParticleAcceleratorControlBox
entities:
- uid: 23875
- uid: 23675
components:
- pos: 98.5,-8.5
- rot: 1.5707963267948966 rad
pos: 95.5,-6.5
parent: 13329
type: Transform
- proto: ParticleAcceleratorEmitterForeUnfinished
entities:
- uid: 23881
- uid: 23680
components:
- pos: 96.5,-8.5
- rot: 1.5707963267948966 rad
pos: 97.5,-5.5
parent: 13329
type: Transform
- proto: ParticleAcceleratorEmitterPortUnfinished
entities:
- uid: 23882
- uid: 23679
components:
- pos: 97.5,-8.5
- rot: 1.5707963267948966 rad
pos: 97.5,-4.5
parent: 13329
type: Transform
- proto: ParticleAcceleratorEmitterStarboardUnfinished
entities:
- uid: 23884
- uid: 23676
components:
- pos: 95.5,-8.5
- rot: 1.5707963267948966 rad
pos: 97.5,-6.5
parent: 13329
type: Transform
- proto: ParticleAcceleratorEndCapUnfinished
@ -170218,9 +169992,10 @@ entities:
type: Transform
- proto: ParticleAcceleratorPowerBoxUnfinished
entities:
- uid: 23874
- uid: 23678
components:
- pos: 97.5,-2.5
- rot: 1.5707963267948966 rad
pos: 96.5,-5.5
parent: 13329
type: Transform
- proto: PartRodMetal

View file

@ -55416,35 +55416,6 @@ entities:
- pos: 23.5,-3.5
parent: 30
type: Transform
- proto: CrateEngineeringAMEJar
entities:
- uid: 9475
components:
- pos: -15.5,-28.5
parent: 30
type: Transform
- containers:
- EntityStorageComponent
- entity_storage
type: Construction
- air:
volume: 200
immutable: False
temperature: 293.1496
moles:
- 3.4430928
- 12.952587
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
type: EntityStorage
- proto: CrateEngineeringAMEShielding
entities:
- uid: 9478
@ -55692,6 +55663,27 @@ entities:
- 0
- 0
type: EntityStorage
- proto: CrateEngineeringTeslaCoil
entities:
- uid: 20617
components:
- pos: -12.5,-69.5
parent: 30
type: Transform
- proto: CrateEngineeringTeslaGenerator
entities:
- uid: 9475
components:
- pos: -13.5,-69.5
parent: 30
type: Transform
- proto: CrateEngineeringTeslaGroundingRod
entities:
- uid: 20618
components:
- pos: -11.5,-69.5
parent: 30
type: Transform
- proto: CrateFilledSpawner
entities:
- uid: 3505
@ -62232,13 +62224,6 @@ entities:
- pos: -12.5,-16.5
parent: 30
type: Transform
- proto: DresserFilled
entities:
- uid: 20615
components:
- pos: 29.5,15.5
parent: 30
type: Transform
- proto: DresserHeadOfPersonnelFilled
entities:
- uid: 5715
@ -62260,6 +62245,13 @@ entities:
- pos: 23.5,2.5
parent: 30
type: Transform
- proto: DresserResearchDirectorFilled
entities:
- uid: 20615
components:
- pos: 29.5,15.5
parent: 30
type: Transform
- proto: DrinkBeepskySmashGlass
entities:
- uid: 21365

File diff suppressed because it is too large Load diff

View file

@ -31933,6 +31933,13 @@ entities:
- pos: 26.5,10.5
parent: 31
type: Transform
- proto: DresserResearchDirectorFilled
entities:
- uid: 5153
components:
- pos: -5.5,-19.5
parent: 31
type: Transform
- proto: DrinkBottleRum
entities:
- uid: 10630
@ -33185,7 +33192,7 @@ entities:
- pos: 38.5,-5.5
parent: 31
type: Transform
- secondsUntilStateChange: -5658.055
- secondsUntilStateChange: -5678.821
state: Closing
type: Door
- uid: 4019
@ -50126,11 +50133,6 @@ entities:
type: AtmosDevice
- proto: NitrogenTankFilled
entities:
- uid: 9624
components:
- pos: -5.613141,-19.356611
parent: 31
type: Transform
- uid: 10652
components:
- pos: 43.475277,-13.455894
@ -53709,11 +53711,6 @@ entities:
- pos: 59.5,6.5
parent: 31
type: Transform
- uid: 5153
components:
- pos: -5.5,-19.5
parent: 31
type: Transform
- uid: 6853
components:
- pos: 29.5,16.5
@ -74531,11 +74528,6 @@ entities:
- pos: 59.472126,6.503501
parent: 31
type: Transform
- uid: 7422
components:
- pos: -5.4065356,-19.504105
parent: 31
type: Transform
- uid: 7794
components:
- pos: -23.521854,22.535301

View file

@ -274,3 +274,15 @@
icon: { sprite: Objects/Fun/bikehorn.rsi, state: icon }
event: !type:ActivateImplantEvent
useDelay: 1
- type: entity
id: ActionToggleEyes
name: Open/Close eyes
description: Close your eyes to protect your peepers, or open your eyes to enjoy the pretty lights.
noSpawn: true
components:
- type: InstantAction
icon: Interface/Actions/eyeopen.png
iconOn: Interface/Actions/eyeclose.png
event: !type:ToggleEyesActionEvent
useDelay: 1 # so u cant give yourself and observers eyestrain by rapidly spamming the action

View file

@ -200,6 +200,7 @@
tags:
- ShoesRequiredStepTriggerImmune
- DoorBumpOpener
- CanPilot
- type: Emoting
- type: GuideHelp
guides:

View file

@ -120,6 +120,8 @@
description: ghost-role-information-slimes-description
- type: Speech
speechVerb: Slime
- type: TypingIndicator
proto: slime
- type: TTS # Corvax-TTS
voice: Chen

View file

@ -20,6 +20,8 @@
- type: Speech
speechVerb: Slime
speechSounds: Slime
- type: TypingIndicator
proto: slime
- type: Vocal
sounds:
Male: MaleSlime

View file

@ -982,6 +982,19 @@
DefaultPrototype: ForkPlastic
ExamineName: Utensil
- type: entity
parent: BaseMachineCircuitboard
id: FlatpackerMachineCircuitboard
name: Flatpacker 1001 machine board
components:
- type: MachineBoard
prototype: MachineFlatpacker
requirements:
Manipulator: 2
MatterBin: 1
materialRequirements:
Steel: 1
- type: entity
id: EmitterCircuitboard
parent: BaseMachineCircuitboard

View file

@ -0,0 +1,33 @@
- type: entity
parent: BaseItem
id: BaseFlatpack
name: base flatpack
description: A flatpack used for constructing something.
categories:
- hideSpawnMenu
components:
- type: Item
size: Normal
- type: Sprite
sprite: Objects/Devices/flatpack.rsi
layers:
- state: base
- state: overlay
color: "#cec8ac"
map: ["enum.FlatpackVisualLayers.Overlay"]
- state: icon-default
- type: Appearance
- type: Flatpack
boardColors:
command: "#334E6D"
medical: "#52B4E9"
service: "#9FED58"
engineering: "#EFB341"
security: "#DE3A3A"
science: "#D381C9"
supply: "#A46106"
- type: StaticPrice
price: 500
- type: Tag
tags:
- DroneUsable

View file

@ -97,7 +97,7 @@
- type: entity
parent: BaseItem
id: StationBeaconPart
name: station beacon assembly
name: station beacon flatpack
description: A flatpack used for constructing a station beacon.
components:
- type: Item

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