diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs
index 6478973a22..6a07034f75 100644
--- a/Content.Client/Entry/EntryPoint.cs
+++ b/Content.Client/Entry/EntryPoint.cs
@@ -135,6 +135,7 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("wireLayout");
_prototypeManager.RegisterIgnore("alertLevels");
_prototypeManager.RegisterIgnore("nukeopsRole");
+ _prototypeManager.RegisterIgnore("stationGoal"); // WD
_prototypeManager.RegisterIgnore("ghostRoleRaffleDecider");
//WD-EDIT
diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs
index 0ae569b392..376774cad1 100644
--- a/Content.Server/Strip/StrippableSystem.cs
+++ b/Content.Server/Strip/StrippableSystem.cs
@@ -22,6 +22,7 @@ using Content.Shared._White.MagGloves;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Utility;
+using Content.Shared._White._Engi.BucketHelmet;
namespace Content.Server.Strip
{
@@ -135,6 +136,16 @@ namespace Content.Server.Strip
}
// WD EDIT END
+ // WD EDIT START
+ if (args.Slot == "ears" && TryComp(strippable, out PreventStrippingFromEarsComponent? _))
+ {
+ var message = Loc.GetString("buckethelmet-cant-strip");
+ _popupSystem.PopupEntity(message, user, user);
+ return;
+ }
+ // WD EDIT END
+
+
if (args.IsHand)
{
StripHand((user, userHands), (strippable.Owner, null), args.Slot, strippable);
@@ -605,7 +616,7 @@ namespace Content.Server.Strip
if (ev.Event.InventoryOrHand)
{
- if ( ev.Event.InsertOrRemove && !CanStripInsertInventory((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) ||
+ if (ev.Event.InsertOrRemove && !CanStripInsertInventory((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) ||
!ev.Event.InsertOrRemove && !CanStripRemoveInventory(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName))
{
ev.Cancel();
@@ -613,7 +624,7 @@ namespace Content.Server.Strip
}
else
{
- if ( ev.Event.InsertOrRemove && !CanStripInsertHand((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) ||
+ if (ev.Event.InsertOrRemove && !CanStripInsertHand((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) ||
!ev.Event.InsertOrRemove && !CanStripRemoveHand(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName))
{
ev.Cancel();
@@ -634,14 +645,14 @@ namespace Content.Server.Strip
if (ev.InventoryOrHand)
{
if (ev.InsertOrRemove)
- StripInsertInventory((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName);
- else StripRemoveInventory(entity.Owner, ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
+ StripInsertInventory((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName);
+ else StripRemoveInventory(entity.Owner, ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
}
else
{
if (ev.InsertOrRemove)
- StripInsertHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
- else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
+ StripInsertHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
+ else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden);
}
}
}
diff --git a/Content.Server/_White/_Engi/BucketHelmet/BucketHelmetSystem.cs b/Content.Server/_White/_Engi/BucketHelmet/BucketHelmetSystem.cs
new file mode 100644
index 0000000000..1b3c0f4d64
--- /dev/null
+++ b/Content.Server/_White/_Engi/BucketHelmet/BucketHelmetSystem.cs
@@ -0,0 +1,30 @@
+using Content.Shared.Inventory.Events;
+using Content.Shared._White._Engi.BucketHelmet;
+
+namespace Content.Server._White._Engi.BucketHelmet;
+
+///
+/// WD.
+/// This handles placemet of PreventStrippingFromEarsComponent when bucket helmet is in use.
+///
+public sealed class BucketHelmetSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnGotEquipped);
+ SubscribeLocalEvent(OnGotUnequipped);
+ }
+
+
+ public void OnGotUnequipped(EntityUid uid, BucketHelmetComponent component, GotUnequippedEvent args)
+ {
+ RemComp(args.Equipee);
+ }
+
+ public void OnGotEquipped(EntityUid uid, BucketHelmetComponent component, GotEquippedEvent args)
+ {
+ if (args.Slot == "head")
+ EnsureComp(args.Equipee);
+ }
+
+}
diff --git a/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionComponent.cs b/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionComponent.cs
new file mode 100644
index 0000000000..320f17e3a8
--- /dev/null
+++ b/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionComponent.cs
@@ -0,0 +1,15 @@
+using Robust.Shared.Audio;
+
+namespace Content.Server._White._Engi.PacifiedOnChaplainAction
+{
+ ///
+ /// WD.
+ /// Adds verb for chaplain to pacify entity.
+ ///
+ [RegisterComponent]
+ public sealed partial class PacifiedOnChaplainActionComponent : Component
+ {
+ [DataField]
+ public SoundSpecifier ActionSound = new SoundPathSpecifier("/Audio/Effects/holy.ogg");
+ }
+}
diff --git a/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionSystem.cs b/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionSystem.cs
new file mode 100644
index 0000000000..f86ca2054f
--- /dev/null
+++ b/Content.Server/_White/_Engi/PacifiedOnChaplainAction/PacifiedOnChaplainActionSystem.cs
@@ -0,0 +1,113 @@
+using Content.Shared.ActionBlocker;
+using Content.Server.Popups;
+using Robust.Shared.Audio.Systems;
+using Content.Shared.Interaction;
+using Content.Shared.Verbs;
+using Content.Server.Bible.Components;
+using Content.Shared.Timing;
+using Content.Shared.CombatMode.Pacification;
+using Content.Server.Administration.Logs;
+using Content.Shared.Database;
+
+namespace Content.Server._White._Engi.PacifiedOnChaplainAction
+{
+ ///
+ /// WD
+ ///
+ public sealed class PacifiedOnChaplainAction : EntitySystem
+ {
+ [Dependency] private readonly ActionBlockerSystem _blocker = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly UseDelaySystem _delay = default!;
+ [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnAfterInteract);
+ SubscribeLocalEvent>(AddPacifiedOnChaplainVerb);
+ }
+
+ private void Action(PacifiedOnChaplainActionComponent component, EntityUid target, EntityUid user)
+ {
+ var popup = "";
+
+ if (HasComp(target))
+ {
+ popup = "unpacified-by-chaplain";
+ RemComp(target);
+ }
+ else
+ {
+ popup = "pacified-by-chaplain";
+ EnsureComp(target);
+ }
+
+ _adminLogger.Add(LogType.Verb,
+ LogImpact.Medium,
+ $"{ToPrettyString(target):target} {popup} {ToPrettyString(user):user}");
+
+ _popupSystem.PopupEntity(Loc.GetString(popup, ("target", target)), user, user);
+
+ _audio.PlayPvs(component.ActionSound, user);
+
+ }
+
+ private void OnAfterInteract(EntityUid uid, PacifiedOnChaplainActionComponent component, AfterInteractEvent args)
+ {
+ if (!args.CanReach)
+ return;
+
+ if (!TryComp(uid, out UseDelayComponent? useDelay) || _delay.IsDelayed((uid, useDelay)))
+ return;
+
+ if (args.Target == null)
+ return;
+
+ if (!HasComp(args.User))
+ return;
+
+ Action(component, (EntityUid) args.Target, args.User);
+
+ _delay.TryResetDelay((uid, useDelay));
+
+ return;
+ }
+ private void AddPacifiedOnChaplainVerb(EntityUid uid, PacifiedOnChaplainActionComponent component, GetVerbsEvent args)
+ {
+ if (!args.CanInteract || !args.CanAccess)
+ return;
+
+ if (!HasComp(args.User))
+ return;
+
+ if (!_blocker.CanInteract(args.User, uid))
+ return;
+
+ var verbName = "";
+
+ if (HasComp(args.Target))
+ verbName = Loc.GetString("unpacify-by-chaplain");
+ else
+ verbName = Loc.GetString("pacify-by-chaplain");
+
+ AlternativeVerb verb = new()
+ {
+ Act = () =>
+ {
+ if (!TryComp(uid, out UseDelayComponent? useDelay) || _delay.IsDelayed((uid, useDelay)))
+ return;
+
+ Action(component, args.Target, args.User);
+
+ _delay.TryResetDelay((uid, useDelay));
+ },
+ Text = verbName,
+ Priority = 2
+ };
+ args.Verbs.Add(verb);
+ }
+ }
+}
diff --git a/Content.Server/_White/_Engi/StationGoalCommand/StationGoalCommand.cs b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalCommand.cs
new file mode 100644
index 0000000000..d8458197f5
--- /dev/null
+++ b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalCommand.cs
@@ -0,0 +1,66 @@
+using System.Linq;
+using Content.Server.Administration;
+using Content.Server.Commands;
+using Content.Shared.Administration;
+using Robust.Shared.Console;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server._White._Engi.StationGoal
+{
+ [AdminCommand(AdminFlags.Fun)]
+ public sealed class StationGoalCommand : IConsoleCommand
+ {
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ public string Command => "sendstationgoal";
+ public string Description => Loc.GetString("send-station-goal-command-description");
+ public string Help => Loc.GetString("send-station-goal-command-help-text", ("command", Command));
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ if (args.Length != 2)
+ {
+ shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
+ return;
+ }
+
+ if (!NetEntity.TryParse(args[0], out var euidNet) || !_entManager.TryGetEntity(euidNet, out var euid))
+ {
+ shell.WriteError($"Failed to parse euid '{args[0]}'.");
+ return;
+ }
+
+ var protoId = args[1];
+ var prototypeManager = IoCManager.Resolve();
+ if (!prototypeManager.TryIndex(protoId, out var proto))
+ {
+ shell.WriteError($"No station goal found with ID {protoId}!");
+ return;
+ }
+
+ var stationGoalPaper = IoCManager.Resolve().System();
+ if (!stationGoalPaper.SendStationGoal(euid, protoId))
+ {
+ shell.WriteError("Station goal was not sent");
+ return;
+ }
+ }
+
+ public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
+ {
+ switch (args.Length)
+ {
+ case 1:
+ var stations = ContentCompletionHelper.StationIds(_entManager);
+ return CompletionResult.FromHintOptions(stations, "[StationId]");
+ case 2:
+ var options = IoCManager.Resolve()
+ .EnumeratePrototypes()
+ .Select(p => new CompletionOption(p.ID));
+
+ return CompletionResult.FromHintOptions(options, Loc.GetString("send-station-goal-command-arg-id"));
+ }
+ return CompletionResult.Empty;
+ }
+ }
+}
diff --git a/Content.Server/_White/_Engi/StationGoalCommand/StationGoalComponent.cs b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalComponent.cs
new file mode 100644
index 0000000000..0252059942
--- /dev/null
+++ b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalComponent.cs
@@ -0,0 +1,15 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Server._White._Engi.StationGoal
+{
+ ///
+ /// WD.
+ /// If attached to a station prototype, will send the station a random goal from the list.
+ ///
+ [RegisterComponent]
+ public sealed partial class StationGoalComponent : Component
+ {
+ [DataField]
+ public List> Goals = new();
+ }
+}
diff --git a/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperComponent.cs b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperComponent.cs
new file mode 100644
index 0000000000..d90da2e7fc
--- /dev/null
+++ b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Server._White._Engi.StationGoal
+{
+ ///
+ /// WD.
+ /// Paper with a written station goal in it.
+ ///
+ [RegisterComponent]
+ public sealed partial class StationGoalPaperComponent : Component
+ {
+ }
+}
diff --git a/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperSystem.cs b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperSystem.cs
new file mode 100644
index 0000000000..c5ec51faa8
--- /dev/null
+++ b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPaperSystem.cs
@@ -0,0 +1,132 @@
+using Content.Server.Fax;
+using Content.Server.GameTicking.Events;
+using Content.Server.Station.Components;
+using Content.Server.Station.Systems;
+using Content.Shared.Fax.Components;
+using Content.Shared.Paper;
+using Robust.Server.Player;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Content.Server.RandomMetadata;
+
+namespace Content.Server._White._Engi.StationGoal
+{
+ ///
+ /// WD.
+ /// System to spawn paper with station goal.
+ ///
+ public sealed class StationGoalPaperSystem : EntitySystem
+ {
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly FaxSystem _fax = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly StationSystem _station = default!;
+ [Dependency] private readonly RandomMetadataSystem _randomMeta = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnRoundStarting);
+ }
+
+ private void OnRoundStarting(RoundStartingEvent ev)
+ {
+ var playerCount = _playerManager.PlayerCount;
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var station))
+ {
+ var tempGoals = new List>(station.Goals);
+ StationGoalPrototype? selGoal = null;
+ while (tempGoals.Count > 0)
+ {
+ var goalId = _random.Pick(tempGoals);
+ var goalProto = _proto.Index(goalId);
+
+ if (playerCount > goalProto.MaxPlayers ||
+ playerCount < goalProto.MinPlayers)
+ {
+ tempGoals.Remove(goalId);
+ continue;
+ }
+
+ selGoal = goalProto;
+ break;
+ }
+
+ if (selGoal is null)
+ return;
+
+ if (SendStationGoal(uid, selGoal))
+ {
+ Log.Info($"Goal {selGoal.ID} has been sent to station {MetaData(uid).EntityName}");
+ }
+ }
+ }
+
+ public bool SendStationGoal(EntityUid? ent, ProtoId goal)
+ {
+ return SendStationGoal(ent, _proto.Index(goal));
+ }
+
+ ///
+ /// Send a station goal on selected station to all faxes which are authorized to receive it.
+ ///
+ /// True if at least one fax received paper
+ public bool SendStationGoal(EntityUid? ent, StationGoalPrototype goal)
+ {
+ if (ent is null)
+ return false;
+
+ if (!TryComp(ent, out var stationData))
+ return false;
+
+ var today = DateTime.Today.ToString("dd.MM");
+ var namesList = new List
+ {
+ "names_first_male",
+ "names_last_male"
+ };
+ var operatorName = _randomMeta.GetRandomFromSegments(namesList, " ");
+
+ var faxContent = Loc.GetString("engi-station-goal-form",
+ ("station", MetaData(ent.Value).EntityName),
+ ("date", today),
+ ("operator", operatorName),
+ ("text", Loc.GetString(goal.Text)));
+
+ var printout = new FaxPrintout(
+ faxContent,
+ Loc.GetString("engi-station-goal-fax-paper-name"),
+ null,
+ null,
+ "paper_stamp-centcom",
+ new List
+ {
+ new() { StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), StampedColor = Color.FromHex("#006600") },
+ });
+
+ var wasSent = false;
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var faxUid, out var fax))
+ {
+ if (!fax.ReceiveStationGoal)
+ continue;
+
+ var largestGrid = _station.GetLargestGrid(stationData);
+ var grid = Transform(faxUid).GridUid;
+ if (grid is not null && largestGrid == grid.Value)
+ {
+ _fax.Receive(faxUid, printout, null, fax);
+ foreach (var spawnEnt in goal.Spawns)
+ {
+ SpawnAtPosition(spawnEnt, Transform(faxUid).Coordinates);
+ }
+ wasSent = true;
+ }
+ }
+ return wasSent;
+ }
+ }
+}
diff --git a/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPrototype.cs b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPrototype.cs
new file mode 100644
index 0000000000..04a2e0807a
--- /dev/null
+++ b/Content.Server/_White/_Engi/StationGoalCommand/StationGoalPrototype.cs
@@ -0,0 +1,29 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Server._White._Engi.StationGoal
+{
+ ///
+ /// WD
+ ///
+ [Serializable, Prototype("stationGoal")]
+ public sealed class StationGoalPrototype : IPrototype
+ {
+ [IdDataField]
+ public string ID { get; } = default!;
+
+ [DataField]
+ public string Text { get; set; } = string.Empty;
+
+ [DataField]
+ public int? MinPlayers;
+
+ [DataField]
+ public int? MaxPlayers;
+
+ ///
+ /// Goal may require certain items to complete. These items will appear near the receving fax machine at the start of the round.
+ ///
+ [DataField]
+ public List Spawns = new();
+ }
+}
diff --git a/Content.Shared/Fax/Components/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs
index 6664ce023d..ba6491303a 100644
--- a/Content.Shared/Fax/Components/FaxMachineComponent.cs
+++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs
@@ -59,6 +59,14 @@ public sealed partial class FaxMachineComponent : Component
[DataField]
public bool ReceiveNukeCodes { get; set; } = false;
+ ///
+ /// WD.
+ /// Should that fax receive station goal info
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("receiveStationGoal")]
+ public bool ReceiveStationGoal { get; set; } = false;
+
///
/// Sound to play when fax has been emagged
///
diff --git a/Content.Shared/_White/_Engi/BucketHelmet/BucketHelmetComponent.cs b/Content.Shared/_White/_Engi/BucketHelmet/BucketHelmetComponent.cs
new file mode 100644
index 0000000000..dced0423a6
--- /dev/null
+++ b/Content.Shared/_White/_Engi/BucketHelmet/BucketHelmetComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Shared._White._Engi.BucketHelmet;
+
+///
+/// WD.
+/// This is used for bucket helmet.
+///
+[RegisterComponent]
+public sealed partial class BucketHelmetComponent : Component
+{
+
+}
diff --git a/Content.Shared/_White/_Engi/BucketHelmet/PreventStrippingFromEarsComponent.cs b/Content.Shared/_White/_Engi/BucketHelmet/PreventStrippingFromEarsComponent.cs
new file mode 100644
index 0000000000..843e7cf0cc
--- /dev/null
+++ b/Content.Shared/_White/_Engi/BucketHelmet/PreventStrippingFromEarsComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Shared._White._Engi.BucketHelmet;
+
+///
+/// WD.
+/// This is used to block stripping headsets when bucket helmet is on.
+///
+[RegisterComponent]
+public sealed partial class PreventStrippingFromEarsComponent : Component
+{
+
+}
diff --git a/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingComponent.cs b/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingComponent.cs
new file mode 100644
index 0000000000..72a9f95515
--- /dev/null
+++ b/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingComponent.cs
@@ -0,0 +1,26 @@
+using Content.Shared.Damage;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._White._Engi.DamageableClothing;
+
+///
+/// WD.
+/// This component goes on an equippable item that should take damage while in use.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class DamageableClothingComponent : Component
+{
+
+ ///
+ /// The entity that's wearing the item.
+ ///
+ [ViewVariables, AutoNetworkedField]
+ public EntityUid? User;
+
+ ///
+ /// The damage modifier to use on item.
+ ///
+ [DataField]
+ public DamageModifierSet DamageModifier = default!;
+
+}
diff --git a/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingUserComponent.cs b/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingUserComponent.cs
new file mode 100644
index 0000000000..f4db76ddef
--- /dev/null
+++ b/Content.Shared/_White/_Engi/DamageableClothing/Components/DamageableClothingUserComponent.cs
@@ -0,0 +1,16 @@
+namespace Content.Shared._White._Engi.DamageableClothing;
+
+///
+/// WD.
+/// This component gets dynamically added to an Entity via the .
+///
+[RegisterComponent]
+public sealed partial class DamageableClothingUserComponent : Component
+{
+ ///
+ /// The entity that's also being damaged.
+ ///
+ [DataField]
+ public EntityUid? ItemId;
+
+}
diff --git a/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingSystem.cs b/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingSystem.cs
new file mode 100644
index 0000000000..04db92c521
--- /dev/null
+++ b/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingSystem.cs
@@ -0,0 +1,46 @@
+using Robust.Shared.Timing;
+using Content.Shared.Inventory.Events;
+
+namespace Content.Shared._White._Engi.DamageableClothing;
+
+///
+/// WD
+///
+public sealed partial class DamageableClothingSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ InitializeUser();
+
+ SubscribeLocalEvent(OnEquipped);
+ SubscribeLocalEvent(OnUnequipped);
+ SubscribeLocalEvent(OnShutdown);
+ }
+
+ private void OnEquipped(EntityUid uid, DamageableClothingComponent component, GotEquippedEvent args)
+ {
+ if (_gameTiming.ApplyingState)
+ return;
+ component.User = args.Equipee;
+ var userComp = EnsureComp(args.Equipee);
+ userComp.ItemId = args.Equipment;
+ }
+
+ private void OnUnequipped(EntityUid uid, DamageableClothingComponent component, GotUnequippedEvent args)
+ {
+ RemCompDeferred(args.Equipee);
+ component.User = null;
+ }
+
+ private void OnShutdown(EntityUid uid, DamageableClothingComponent component, ComponentShutdown args)
+ {
+ if (component.User != null)
+ {
+ RemCompDeferred(component.User.Value);
+ component.User = null;
+ }
+ }
+}
diff --git a/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingUserSystem.cs b/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingUserSystem.cs
new file mode 100644
index 0000000000..c83154a58a
--- /dev/null
+++ b/Content.Shared/_White/_Engi/DamageableClothing/DamageableClothingUserSystem.cs
@@ -0,0 +1,49 @@
+using Content.Shared.Damage;
+
+namespace Content.Shared._White._Engi.DamageableClothing;
+
+///
+/// WD
+///
+public sealed partial class DamageableClothingSystem
+{
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+
+ private void InitializeUser()
+ {
+ SubscribeLocalEvent(OnUserDamageModified);
+ SubscribeLocalEvent(OnDamageModified);
+ SubscribeLocalEvent(OnEntityTerminating);
+ }
+
+ private void OnUserDamageModified(EntityUid uid, DamageableClothingUserComponent component, DamageModifyEvent args)
+ {
+ if (TryComp(component.ItemId, out var blocking))
+ {
+ if (args.Damage.GetTotal() <= 0)
+ return;
+
+ if (!TryComp(component.ItemId, out var dmgComp))
+ return;
+
+ var blockFraction = 1;
+ blockFraction = Math.Clamp(blockFraction, 0, 1);
+ _damageable.TryChangeDamage(component.ItemId, blockFraction * args.OriginalDamage);
+ }
+ }
+
+ private void OnDamageModified(EntityUid uid, DamageableClothingComponent component, DamageModifyEvent args)
+ {
+ var modifier = component.DamageModifier;
+ args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modifier);
+ }
+
+ private void OnEntityTerminating(EntityUid uid, DamageableClothingUserComponent component, ref EntityTerminatingEvent args)
+ {
+ if (!TryComp(component.ItemId, out var blockingComponent))
+ return;
+
+ RemCompDeferred(uid);
+ }
+
+}
diff --git a/Resources/Locale/ru-RU/White/bucket-helmet.ftl b/Resources/Locale/ru-RU/White/bucket-helmet.ftl
new file mode 100644
index 0000000000..689992ad27
--- /dev/null
+++ b/Resources/Locale/ru-RU/White/bucket-helmet.ftl
@@ -0,0 +1,4 @@
+ent-ClothingHeadBucketHelmet = шлем из ведра
+ .desc = Обычное ведро с двумя прорезями для глаз. При ношении на голове что-то липкое внутри цепляется за гарнитуру.
+
+buckethelmet-cant-strip = Шлем из ведра не позволяет это сделать
diff --git a/Resources/Locale/ru-RU/White/clothing-outer-armor-reflective-ghetto.ftl b/Resources/Locale/ru-RU/White/clothing-outer-armor-reflective-ghetto.ftl
new file mode 100644
index 0000000000..491be27338
--- /dev/null
+++ b/Resources/Locale/ru-RU/White/clothing-outer-armor-reflective-ghetto.ftl
@@ -0,0 +1,2 @@
+ent-ClothingOuterArmorReflectiveGhetto = самодельный отражающий жилет
+ .desc = Два зеркала соединённые проводами для сомнительной защиты от лазеров.
diff --git a/Resources/Locale/ru-RU/White/ghetto-mirror-shield.ftl b/Resources/Locale/ru-RU/White/ghetto-mirror-shield.ftl
new file mode 100644
index 0000000000..0a5b6a25db
--- /dev/null
+++ b/Resources/Locale/ru-RU/White/ghetto-mirror-shield.ftl
@@ -0,0 +1,2 @@
+ent-MirrorShieldGhetto = самодельный зеркальный щит
+ .desc = Сделанное на скорую руку зеркало с рукояткой для использования как сомнительная защита от лазеров.
diff --git a/Resources/Locale/ru-RU/_Engi/pacified-on-chaplain-action.ftl b/Resources/Locale/ru-RU/_Engi/pacified-on-chaplain-action.ftl
new file mode 100644
index 0000000000..d3dea6a291
--- /dev/null
+++ b/Resources/Locale/ru-RU/_Engi/pacified-on-chaplain-action.ftl
@@ -0,0 +1,5 @@
+pacified-by-chaplain = {$target} пасифицирован.
+unpacified-by-chaplain = {$target} освобождён.
+
+pacify-by-chaplain = Пасифицировать
+unpacify-by-chaplain = Освободить
diff --git a/Resources/Locale/ru-RU/_Engi/possesed-blade.ftl b/Resources/Locale/ru-RU/_Engi/possesed-blade.ftl
new file mode 100644
index 0000000000..ab2376b0e7
--- /dev/null
+++ b/Resources/Locale/ru-RU/_Engi/possesed-blade.ftl
@@ -0,0 +1,3 @@
+ghost-role-information-possessed-blade-name = Одержимый Клинок
+ghost-role-information-possessed-blade-description = Вы - Одержимый Клинок. Подчиняйтесь своему владельцу.
+ghost-role-information-possessed-blade-rules = Вы не имеете право атаковать своего владельца. Право собственности может быть передано только вашим владельцем.
diff --git a/Resources/Locale/ru-RU/_Engi/station-goal.ftl b/Resources/Locale/ru-RU/_Engi/station-goal.ftl
new file mode 100644
index 0000000000..d05b015eb6
--- /dev/null
+++ b/Resources/Locale/ru-RU/_Engi/station-goal.ftl
@@ -0,0 +1,251 @@
+ent-StationGoalPaper = цель станции от Центком
+ .desc = Похоже у вас будет много работы.
+
+engi-station-goal-fax-paper-name = цель станции от Центком
+
+engi-station-goal-form = Постановление Центрального Командования
+ ---------------------------------------------------------------------
+ Утверждение цели и задачи для станции { $station }
+ Центральным Командованием № 2562-CU-2
+ Дата: { $date }.2562 года
+ ---------------------------------------------------------------------
+ Утвердить следующие цели для космической станции:
+
+ { $text }
+ ---------------------------------------------------------------------
+ 1. Командование станции обязано строго следовать данной цели и заданию, а также предоставить все необходимые ресурсы и усилия для успешного выполнения миссии.
+
+ 2. Право отменить данное постановление имеет исключительно Центральное Командование.
+
+ 3. Сотрудникам станции запрещено покидать объект до момента выполнения цели. Исключение - станция находится в критическом состоянии и не является пригодной для жизни.
+ ---------------------------------------------------------------------
+ Данное Постановление выписано:
+ И.Ф: { $operator }
+ Должность: Оператор Центрального Командования
+ Печать:
+
+engi-station-goal-singularity = [bold]Постройка генератора, основанного на сингулярности.[/bold]
+
+ Все детали для цели должны быть заказаны или собраны на станции. Категорически запрещено использовать уже имеющиеся компоненты.
+
+ Для успешного выполнения цели необходимо сделать запуск сингулярности.
+
+ После окончания смены вся конструкция будет отсоединена от станции и транспортирована на другой объект.
+
+engi-station-goal-solar-panels = [bold]Постройка сети солнечных панелей.[/bold]
+
+ Требования:
+ - Сеть должна состоять из минимум двух ветвей, расположенных на противоположных концах станции.
+ - Каждая ветвь должна состоять из минимум 36 солнечных панелей.
+ - Каждая ветвь должна иметь минимум два СМЭСа, несоединённых со станцией.
+
+engi-station-goal-artifacts = [bold]Нахождение и исследование артефактов.[/bold]
+
+ Экипаж станции должен найти минимум три артефакта любым способом, отличным от покупки.
+
+ Сотрудники научного отдела должны изучить найденные артефакты и задокументировать их свойства.
+
+ В качестве документации могут быть приняты отчёты о каждом узле (печатаются на специальной консоли) и отдельный документ с описанием в доступной форме схемы артефакта.
+
+ Каждый документ должен быть подтверждён печатью научного руководителя или капитана. Артефакты с документацией должны быть доставлены на станцию центрального командования.
+
+engi-station-goal-bank = [bold]Постройка орбитального хранилища с припасами и технологиями.[/bold]
+
+ Хранилище должно быть размещено в космосе, отдельно от основной станции, защищено от метеоритов и иметь автономное питание.
+
+ В хранилище должно быть минимум четыре ящика:
+ - ящик с продвинутыми медикаментами;
+ - ящик с запасами лучших семян;
+ - ящик-холодильник еды с высокой питательной ценностью;
+ - ящик с ценными, но не уникальными платами.
+
+engi-station-goal-zoo = [bold]Улучшение рекреации персонала станции.[/bold]
+
+ Для этого инженерный отдел должен построить зоопарк с как минимум 3 (тремя) вольерами. На каждый вольер один вид. Каждый вольер должен быть обеспечен едой для конкретного вида и роботом-уборщиком. Площадь каждого вольера как минимум 16 м².
+
+ Животные должны быть заказаны в отделе снабжения.
+
+engi-station-goal-mining-outpost = [bold]Постройка орбитального шахтёрского аванпоста.[/bold]
+
+ Аванпост должен быть размещен в космосе, отдельно от основной станции, защищён от метеоритов и иметь автономное питание, гравитацию и атмосферу.
+
+ Аванпост должен иметь как минимум две жилые комнаты с освещением и окнами. Оборудование для проведения работ: как минимум по две кирки, сумки для руды. Как минимум два шахтёрских скафандра.
+
+ На территории аванпоста должен быть склад для размещения добытого сырья и припасов: как минимум 500u (пятьсот единиц) пива в ящике-холодильнике для закусок. Как минимум по четыре набора медикаментов от механических повреждений.
+
+engi-station-goal-tesla = [bold]Постройка генератора, основанного на Тесле.[/bold]
+
+ Все детали для цели должны быть заказаны или собраны на станции. Категорически запрещено использовать уже имеющиеся компоненты.
+
+ Для успешного выполнения цели необходимо сделать запуск Теслы.
+
+ После окончания смены вся конструкция будет отсоединена от станции и транспортирована на другой объект.
+
+engi-station-goal-security = [bold]Постройка и снабжение тренировочного комплекса для Службы Безопасности, с последующей проверкой состава.[/bold]
+
+ В будущем данная станция будет передислоцирована в сектор граничащий с небезопасным.
+
+ Задачей Инженерного отдела является постройка тренировочного комплекса, представляющего из себя полосу препятствий. Минимальное время на прохождение среднестатистического, подготовленного офицера, примерно 30 секунд.
+ Данная полоса должна включать в себя следующее:
+ - Змееобразные коридоры стекла.
+ - Различные препятствия для перелезания.
+ - Деревянную постройку с мишенями, имитирующую захват случайного отдела.
+ Инженерный отдел в праве строить и другие безопасные виды препятствий.
+
+ Задачей Медицинского отдела является изготовление партии таблеток Эфедрина, дозировкой 10u каждая, в минимальном количестве 10 шт, с последующей передачей на хранение в защищенном контейнере Смотрителю станции.
+
+ Задачей Службы Безопасности является проведение для каждого члена своего отдела тренировки на данной полосе с письменной фиксацией результатов. В результатах должно быть описано Имя и Фамилия сотрудника, а так же время за которое им была пройдена полоса. Лучшие сотрудники получат шанс на контракт о последующей работе на следующей смене данной станции. Результаты каждого сотрудника будет необходимо указать в отчете о состоянии цели.
+
+engi-station-goal-shuttle-med = [bold]Постройка пилотируемого медицинского шаттла.[/bold]
+
+ Шаттл должен соответствовать следующим требованиям:
+ 1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
+ 2. Уметь совершать следующие движения: крен, тангаж и рысканье.
+ 3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
+ 4. Иметь на борту химическую лабораторию с соответствующим оборудованием, рассчитанным минимум на одного сотрудника.
+ 5. Иметь отсек для медицинских коек, рассчитанным минимум на десять человек.
+ 6. Иметь на борту отсек с запасами медикаментов и провизии.
+
+ Справочная информация для неквалифицированного персонала:
+ Крен — вращательное движение.
+ Тангаж — поступательное движение "вперёд" и "назад".
+ Рысканье — поступательное движение "боком".
+
+engi-station-goal-shuttle-sec = [bold]Постройка пилотируемого десантного шаттла.[/bold]
+
+ Шаттл должен соответствовать следующим требованиям:
+ 1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
+ 2. Уметь совершать следующие движения: крен, тангаж и рысканье.
+ 3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
+ 4. Иметь на борту места и снаряжение как минимум на пять офицеров СБ.
+ Снаряжение для каждого офицера должно представлять из себя хотя бы один вид легального огнестрельного оружия, полученного не из арсенала, бронежилет, шлем, униформу.
+ 5. Иметь на борту отсек с запасами медикаментов и провизии минимум на пять человек.
+
+ Справочная информация для неквалифицированного персонала:
+ Крен — вращательное движение.
+ Тангаж — поступательное движение "вперёд" и "назад".
+ Рысканье — поступательное движение "боком".
+
+engi-station-goal-shuttle-rnd = [bold]Постройка пилотируемого исследовательского шаттла.[/bold]
+
+ Шаттл должен соответствовать следующим требованиям:
+ 1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
+ 2. Уметь совершать следующие движения: крен, тангаж и рысканье.
+ 3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
+ 4. Иметь на борту следующие устройства и снаряжение: М.А.К.А.К. (x1), М.А.Р.Т.Ы.Х. (х2), синхронизатор аномалий (x1), магнитные сапоги (х2) и экспериментальный сосуд аномалии (х1), а также как минимум два скафандра EVA и два костюма радиационной защиты.
+
+ Справочная информация для неквалифицированного персонала:
+ Крен — вращательное движение.
+ Тангаж — поступательное движение "вперёд" и "назад".
+ Рысканье — поступательное движение "боком".
+
+engi-station-goal-shuttle-srv = [bold]Постройка пилотируемого пассажирского шаттла.[/bold]
+
+ Шаттл должен соответствовать следующим требованиям:
+ 1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
+ 2. Уметь совершать следующие движения: крен, тангаж и рысканье.
+ 3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
+ 4. Иметь на борту полностью обустроенный бар, в котором должен быть раздатчик безалкоголя, раздатчик алкоголя, бочка кваса, ящик барных принадлежностей, ящик пополнения раздатчика алкоголя, ящик пополнения раздатчика безалкоголя.
+ 5. Иметь на борту обустроенную кухню, в которой должен быть ящик кухонных припасов и ящик кухонных принадлежностей. А также один гидропонный лоток и холодильник.
+ 6. На борту должны быть приватные комнаты для комфортного проживания как минимум четверых человек.
+ 7. На борту должен быть музыкальный автомат и ящик настольных игр.
+
+ Справочная информация для неквалифицированного персонала:
+ Крен — вращательное движение.
+ Тангаж — поступательное движение "вперёд" и "назад".
+ Рысканье — поступательное движение "боком".
+
+engi-station-goal-shuttle-emergency = [bold]Постройка пилотируемого спасательного шаттла.[/bold]
+
+ Шаттл должен соответствовать следующим требованиям:
+ 1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
+ 2. Уметь совершать следующие движения: крен, тангаж и рысканье.
+ 3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
+ 4. Иметь на борту ящик медицинских припасов, продвинутый аварийный набор, два ящика с наборами EVA, ящик стекла, два ящика стали, ящик пластали, ящик джетпаков, ящик ИРП.
+
+ Справочная информация для неквалифицированного персонала:
+ Крен — вращательное движение.
+ Тангаж — поступательное движение "вперёд" и "назад".
+ Рысканье — поступательное движение "боком".
+
+engi-station-goal-theatre = [bold]Постройка театральной зоны.[/bold]
+
+ На данной станции пройдут переговоры с крупными компаниями для заключения партнёрских соглашений.
+
+ Театральная зона должна включать в себя:
+ 1. Сцена с минимальным размером в 28м².
+ 2. Минимальная вместимость зала в 21 персону.
+ 3. Закулисье с различными нарядами, музыкальными инструментами, несколькими ящиками игрушек и мехом модели Х.О.Н.К.
+ 4. Комнату или комнаты для четырех актеров. На каждого актера должно приходится по пять любых пирогов.
+
+ Материалы для клоунских скафандров вы можете получить из ящика театрального снаряжения.
+ В случае проведения тестового представления сервисный отдел и командование станции получат вознаграждение по прибытию на Станцию ЦК.
+ По окончании работ ЦК может прислать представителя для проведения тестового представления.
+
+engi-station-goal-ai = [bold]Постройка автономного отсека ИИ.[/bold]
+
+ По окончанию строительства отсек должен быть отстыкован от станции и отправлен дрейфовать в космосе.
+
+ Требования:
+ 1. Автономное питание на солнечных панелях или РИТЭГ, подключенные к СМЭС и Подстанции.
+ 2. Иметь отсек для позитронного мозга.
+ 3. Консоль сканера массы.
+ 4. Два борга без позитронного мозга: инженерного и научного назначения.
+ 5. Шлюз в отсек с командным доступом.
+ 6. Сервер коммуникации и маршрутизатор проводных камер.
+ 7. Снаружи отсек должен быть окружён контуром охлаждения.
+ Контур охлаждения должен представлять собой канал, шириной не менее одного метра, полностью заполненный любым газом, кроме обычной воздушной смеси, при температуре ниже -100 градусов по Цельсию и давлении как минимум в 3 раза превышающем атмосферное. Контур должен опоясывать не менее 80% модуля.
+
+ Рекомендуется предпринять дополнительные меры безопасности:
+ - Защиту от метеоритов.
+ - Сеть вокруг отсека под высоким напряжением.
+
+engi-station-goal-botany = [bold]Постройка теплиц и выведение приспособленных к температуре растений.[/bold]
+
+ На станции или вблизи неё требуется построить три отсека с контролируемым климатом:
+ - Отсек с температурой 5 градусов Цельсия.
+ - Отсек с температурой 25 градусов Цельсия.
+ - Отсек с температурой 45 градусов Цельсия.
+
+ Каждый отсек необходимо снабдить минимум шестью гидропонными лотками и полным резервуаром с водой.
+ В каждом отсеке должно находится хотя бы одно растение, приспособленное к температуре отсека.
+
+engi-station-goal-bunker = [bold]Приспособить станцию к мощным гиперэнергетическим потокам.[/bold]
+
+ Необходимо пристроить каждому отделу комнату, далее именуемой “бункер”, в которой экипаж станции мог бы укрыться от последствий гиперэнергетических потоков.
+
+ Требования к бункеру:
+ 1. Минимальный размер 25м².
+ 2. Укреплённые стены.
+ 3. Вход через два непрозрачных шлюза с соответствующим отделу доступом.
+ 4. От четырех кресел пилота.
+ 5. Содержать базовые лекарства в виде таблеток со справкой о их назначении и наборы от механических повреждений.
+ 6. Запасы провизии с расчетом на четыре человека, на срок от 72 часов.
+ 7. Автономное питание и канистры с воздухом и кислородом.
+ 8. Шкафчики со снаряжением для биологической и радиационной защиты. Так же аварийные скафандры EVA и костюм сапёра.
+ 9. Интерком с общим ключом шифрования.
+
+engi-station-goal-circus = [bold]Постройка полноценного цирка хомяков.[/bold]
+
+ На данной станции пройдут переговоры с крупными компаниями для заключения партнёрских соглашений.
+
+ Цирковая зона должна включать в себя:
+ 1. Сцена с минимальным размером в 10м².
+ 2. Минимальная вместимость зала в 10 персон.
+ 3. Закулисье с различными нарядами, музыкальными инструментами и несколькими ящиками игрушек.
+ 4. Комнату дял клеток с хомяками. На каждого актера должно приходится по два уникальных костюма.
+
+ В случае проведения тестового представления сервисный отдел и командование станции получат вознаграждение по прибытию на Станцию ЦК.
+ По окончании работ ЦК может прислать представителя для проведения тестового представления.
+
+station-goal-biodome = [bold]Постройка биокупола для исследования и выращивания аномальных организмов.[/bold]
+
+ Требования к проекту:
+
+ - Купол с регулируемой атмосферой для выращивания и изучения аномалии "Плоть" и/или "Цветок".
+ - Наличие системы безопасного входа/выхода для Купола.
+ - Наличие системы безопасности для защиты от биологических угроз и утечки опасных веществ.
+ - Наличие системы экстренной отчистки Купола от биологического материала.
+ - Создание научной группы для проведения экспериментов и анализов собранных образцов.
+
+ Проект считается завершённым при успешной реализации созданной Куполом продукции на 10000 (десять тысяч) кредитов.
diff --git a/Resources/Locale/ru-RU/white/station-goal/station-goal-command.ftl b/Resources/Locale/ru-RU/white/station-goal/station-goal-command.ftl
index 0108153e31..10d87709f0 100644
--- a/Resources/Locale/ru-RU/white/station-goal/station-goal-command.ftl
+++ b/Resources/Locale/ru-RU/white/station-goal/station-goal-command.ftl
@@ -1,3 +1,3 @@
-send-station-goal-command-description = Отправляет выбранную цель станции на всех факсы способные её принять
+send-station-goal-command-description = WD. Отправляет выбранную цель станции на все факсы способные её принять
send-station-goal-command-help-text = Использование: { $command }
send-station-goal-command-arg-id =
diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
index b6a7ae38e3..bf94bea6a5 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
@@ -66,3 +66,7 @@
- type: PhysicalComposition
materialComposition:
Plastic: 50
+ - type: Construction # WD
+ deconstructionTarget: null
+ graph: ClothingHeadBucketHelmet
+ node: start
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml
index 2a39c20089..3f76e689d5 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml
@@ -28,3 +28,7 @@
storedRotation: -44 # WD
shape: # WD
- 0,0,1,3
+ - type: KnockDownOnHit
+ knockDownBehavior: NoDrop
+ knockdownTime: 0.8
+ requireWield: true
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/tagilla_hammer.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/tagilla_hammer.yml
index 52b02eb7e2..b4564143ff 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/tagilla_hammer.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/tagilla_hammer.yml
@@ -39,3 +39,7 @@
isBloodDagger: false
- type: UseDelay
delay: 1
+ - type: KnockDownOnHit
+ knockDownBehavior: NoDrop
+ knockdownTime: 0.8
+ requireWield: true
diff --git a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
index 36be6451d2..cbefa86808 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
@@ -82,6 +82,7 @@
- type: FaxMachine
name: "Central Command"
notifyAdmins: true
+ receiveStationGoal: true # WD
- type: entity
parent: FaxMachineBase
@@ -109,5 +110,6 @@
- type: FaxMachine
name: "Captain's Office"
receiveNukeCodes: true
+ receiveStationGoal: true # WD
- type: StealTarget
stealGroup: FaxMachineCaptain
diff --git a/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml b/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml
index 43d4460ec5..da9dfef6ae 100644
--- a/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml
+++ b/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml
@@ -263,11 +263,11 @@
sprite: White/Objects/Weapons/Chaplain/scythe-inhands.rsi
- type: Sharp
-# Может пиздеть
+# Может пиздеть и может давать пизды
- type: entity
parent: HolyKatana
id: PossessedBlade
- name: одержимый клинок
+ name: Одержимый Клинок
description: Когда на станции царит хаос, приятно иметь рядом друга.
components:
- type: Sprite
@@ -281,9 +281,9 @@
- suitStorage
- type: GhostRole
allowSpeech: true
- name: Одержимый Клинок
- description: Вы - одержимый клинок. Подчиняйтесь своему владельцу.
- rules: ghost-role-component-default-rules
+ name: ghost-role-information-possessed-blade-name
+ description: ghost-role-information-possessed-blade-description
+ rules: ghost-role-information-possessed-blade-rules
- type: GhostTakeoverAvailable
- type: Examiner
- type: Item
@@ -292,6 +292,14 @@
shape:
- 0, 0, 1, 3
sprite: White/Objects/Weapons/Chaplain/possessed.rsi
+ - type: DamageOtherOnHit
+ damage:
+ types:
+ Slash: 13
+ - type: CombatMode
+ - type: UseDelay
+ delay: 2.0
+ - type: PacifiedOnChaplainAction
# Приклеен к руке, быстро и громко бьет
- type: entity
@@ -494,6 +502,9 @@
soundSwing:
collection: HammerMiss
- type: DisarmMalus
+ - type: KnockDownOnHit
+ knockDownBehavior: NoDrop
+ knockdownTime: 0.4
# Имеет все инструменты в себе, но работает медленно и почти не наносит урона
- type: entity
diff --git a/Resources/Prototypes/_White/_Engi/Entities/Clothing/Head/bucketHelmet.yml b/Resources/Prototypes/_White/_Engi/Entities/Clothing/Head/bucketHelmet.yml
new file mode 100644
index 0000000000..524c6e95af
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Entities/Clothing/Head/bucketHelmet.yml
@@ -0,0 +1,26 @@
+- type: entity
+ parent: ClothingHeadBase
+ id: ClothingHeadBucketHelmet
+ name: bucket helmet
+ description: A regular bucket with two eye holes. When worn on the head, something sticky inside latches on the earpiece.
+ components:
+ - type: Sprite
+ sprite: White/_Engi/Clothing/Head/bucketHelmet.rsi
+ - type: Clothing
+ sprite: White/_Engi/Clothing/Head/bucketHelmet.rsi
+ - type: IdentityBlocker
+ - type: Armor
+ modifiers:
+ coefficients:
+ Blunt: 0.95
+ - type: Tag
+ tags:
+ - HidesHair
+ - WhitelistChameleon
+ - type: Construction
+ deconstructionTarget: start
+ graph: ClothingHeadBucketHelmet
+ node: helmet
+ - type: Item
+ size: Normal
+ - type: BucketHelmet
diff --git a/Resources/Prototypes/_White/_Engi/Entities/Clothing/OuterClothing/ClothingOuterArmorReflectiveGhetto.yml b/Resources/Prototypes/_White/_Engi/Entities/Clothing/OuterClothing/ClothingOuterArmorReflectiveGhetto.yml
new file mode 100644
index 0000000000..92184cf628
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Entities/Clothing/OuterClothing/ClothingOuterArmorReflectiveGhetto.yml
@@ -0,0 +1,53 @@
+- type: entity
+ parent: ClothingOuterArmorBasic
+ id: ClothingOuterArmorReflectiveGhetto
+ name: makeshift reflective vest
+ description: Two mirrors connected by wires for dubious laser protection.
+ components:
+ - type: Sprite
+ sprite: White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi
+ state: icon
+ - type: Clothing
+ sprite: White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi
+ - type: Armor
+ modifiers:
+ coefficients:
+ Slash: 0.9
+ Heat: 0.7
+ - type: Reflect
+ reflectProb: 0.7
+ innate: true
+ placement:
+ - Body
+ reflects:
+ - Energy
+ - type: Construction
+ graph: ClothingOuterArmorReflectiveGhetto
+ node: vest
+ - type: DamageableClothing
+ damageModifier:
+ coefficients:
+ Blunt: 2
+ Slash: 0.9
+ Piercing: 1.5
+ Heat: .5
+ flatReductions:
+ Heat: 0.5
+ - type: Damageable
+ damageContainer: Shield
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 60
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: GlassBreak
+ - !type:SpawnEntitiesBehavior
+ spawn:
+ ShardGlass:
+ min: 3
+ max: 5
diff --git a/Resources/Prototypes/_White/_Engi/Entities/Objects/Shields/MirrorShieldGhetto.yml b/Resources/Prototypes/_White/_Engi/Entities/Objects/Shields/MirrorShieldGhetto.yml
new file mode 100644
index 0000000000..c0873496c1
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Entities/Objects/Shields/MirrorShieldGhetto.yml
@@ -0,0 +1,62 @@
+- type: entity
+ name: makeshift mirror shield
+ parent: BaseItem
+ id: MirrorShieldGhetto
+ description: A makeshift mirror with a handle, used as dubious laser protection.
+ components:
+ - type: Sprite
+ sprite: White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi
+ state: icon
+ - type: Item
+ sprite: White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi
+ size: Ginormous
+ - type: Tag
+ tags:
+ - MirrorShieldGhetto
+ - type: Reflect
+ reflectProb: 0.7
+ innate: true
+ reflects:
+ - Energy
+ - type: Blocking
+ passiveBlockModifier:
+ coefficients:
+ Blunt: 2
+ Slash: 0.9
+ Piercing: 1.5
+ Heat: .6
+ activeBlockModifier:
+ coefficients:
+ Blunt: 2
+ Slash: 0.9
+ Piercing: 1.5
+ Heat: .3
+ flatReductions:
+ Heat: 0.5
+ blockSound: !type:SoundPathSpecifier
+ path: /Audio/Effects/glass_step.ogg
+ - type: MeleeBlock
+ - type: Damageable
+ damageContainer: Shield
+ - type: Construction
+ graph: MirrorShieldGhetto
+ node: shield
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 40
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: GlassBreak
+ - !type:SpawnEntitiesBehavior
+ spawn:
+ ShardGlass:
+ min: 2
+ max: 3
+ - type: StaticPrice
+ price: 50
+ - type: DisarmMalus
diff --git a/Resources/Prototypes/_White/_Engi/Recipes/Graphs/bucketHelmet.yml b/Resources/Prototypes/_White/_Engi/Recipes/Graphs/bucketHelmet.yml
new file mode 100644
index 0000000000..cefb0023e3
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Recipes/Graphs/bucketHelmet.yml
@@ -0,0 +1,21 @@
+- type: constructionGraph
+ id: ClothingHeadBucketHelmet
+ start: start
+ graph:
+ - node: start
+ entity: Bucket
+ edges:
+ - to: helmet
+ conditions:
+ - !type:SolutionEmpty
+ solution: bucket
+ steps:
+ - tool: Cutting
+ doAfter: 5
+ - node: helmet
+ entity: ClothingHeadBucketHelmet
+ edges:
+ - to: start
+ steps:
+ - tool: Welding
+ doAfter: 5
diff --git a/Resources/Prototypes/_White/_Engi/Recipes/Graphs/ghettoMirrorShield.yml b/Resources/Prototypes/_White/_Engi/Recipes/Graphs/ghettoMirrorShield.yml
new file mode 100644
index 0000000000..d31994341c
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Recipes/Graphs/ghettoMirrorShield.yml
@@ -0,0 +1,42 @@
+- type: constructionGraph
+ id: MirrorShieldGhetto
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: shield
+ steps:
+ - material: Glass
+ amount: 5
+ doAfter: 3
+ - material: Steel
+ amount: 3
+ doAfter: 3
+ - node: shield
+ entity: MirrorShieldGhetto
+
+- type: constructionGraph
+ id: ClothingOuterArmorReflectiveGhetto
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: vest
+ steps:
+ - material: Cable
+ amount: 5
+ - tag: MirrorShieldGhetto
+ name: самодельный зеркальный щит
+ icon:
+ sprite: White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi
+ state: icon
+ amount: 1
+ - tag: MirrorShieldGhetto
+ name: самодельный зеркальный щит
+ icon:
+ sprite: White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi
+ state: icon
+ amount: 1
+ doAfter: 6
+ - node: vest
+ entity: ClothingOuterArmorReflectiveGhetto
diff --git a/Resources/Prototypes/_White/_Engi/Recipes/ghettoMirrorShield.yml b/Resources/Prototypes/_White/_Engi/Recipes/ghettoMirrorShield.yml
new file mode 100644
index 0000000000..8b42cc331a
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/Recipes/ghettoMirrorShield.yml
@@ -0,0 +1,25 @@
+- type: construction
+ name: самодельный зеркальный щит
+ id: MirrorShieldGhetto
+ graph: MirrorShieldGhetto
+ startNode: start
+ targetNode: shield
+ category: construction-category-weapons
+ objectType: Item
+ description: Сделанное на скорую руку зеркало с рукояткой для использования как сомнительная защита от лазеров.
+ icon:
+ sprite: White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi
+ state: icon
+
+- type: construction
+ name: самодельный отражающий жилет
+ id: ClothingOuterArmorReflectiveGhetto
+ graph: ClothingOuterArmorReflectiveGhetto
+ startNode: start
+ targetNode: vest
+ category: construction-category-clothing
+ objectType: Item
+ description: Два зеркала соединённые проводами для сомнительной защиты от лазеров.
+ icon:
+ sprite: White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi
+ state: icon
diff --git a/Resources/Prototypes/_White/_Engi/StationGoal/stationGoals.yml b/Resources/Prototypes/_White/_Engi/StationGoal/stationGoals.yml
new file mode 100644
index 0000000000..4877fb1cbf
--- /dev/null
+++ b/Resources/Prototypes/_White/_Engi/StationGoal/stationGoals.yml
@@ -0,0 +1,75 @@
+- type: stationGoal
+ id: Singularity
+ text: engi-station-goal-singularity
+
+- type: stationGoal
+ id: SolarPanels
+ text: engi-station-goal-solar-panels
+
+- type: stationGoal
+ id: Artifacts
+ text: engi-station-goal-artifacts
+
+- type: stationGoal
+ id: Bank
+ text: engi-station-goal-bank
+
+- type: stationGoal
+ id: Zoo
+ text: engi-station-goal-zoo
+
+- type: stationGoal
+ id: MiningOutpost
+ text: engi-station-goal-mining-outpost
+
+- type: stationGoal
+ id: Tesla
+ text: engi-station-goal-tesla
+
+- type: stationGoal
+ id: SecurityTraining
+ text: engi-station-goal-security
+
+- type: stationGoal
+ id: ShuttleMed
+ text: engi-station-goal-shuttle-med
+
+- type: stationGoal
+ id: ShuttleSec
+ text: engi-station-goal-shuttle-sec
+
+- type: stationGoal
+ id: ShuttleRnd
+ text: engi-station-goal-shuttle-rnd
+
+- type: stationGoal
+ id: ShuttleSrv
+ text: engi-station-goal-shuttle-srv
+
+- type: stationGoal
+ id: ShuttleEmergency
+ text: engi-station-goal-shuttle-emergency
+
+- type: stationGoal
+ id: Theatre
+ text: engi-station-goal-theatre
+
+- type: stationGoal
+ id: CellAI
+ text: engi-station-goal-ai
+
+- type: stationGoal
+ id: Botany
+ text: engi-station-goal-botany
+
+- type: stationGoal
+ id: Bunker
+ text: engi-station-goal-bunker
+
+- type: stationGoal
+ id: HamsterСircus
+ text: engi-station-goal-circus
+
+- type: stationGoal
+ id: Biodome
+ text: station-goal-biodome
diff --git a/Resources/Prototypes/_White/tags.yml b/Resources/Prototypes/_White/tags.yml
index 375c824a14..7e71fc6b52 100644
--- a/Resources/Prototypes/_White/tags.yml
+++ b/Resources/Prototypes/_White/tags.yml
@@ -120,3 +120,6 @@
- type: Tag
id: VoiceActivatedBombImplant
+
+- type: Tag
+ id: MirrorShieldGhetto
diff --git a/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/equipped-HELMET.png b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/equipped-HELMET.png
new file mode 100644
index 0000000000..2217a63c0f
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/equipped-HELMET.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/icon.png b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/icon.png
new file mode 100644
index 0000000000..1236927c54
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/icon.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/meta.json b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/meta.json
new file mode 100644
index 0000000000..b821cbeb0f
--- /dev/null
+++ b/Resources/Textures/White/_Engi/Clothing/Head/bucketHelmet.rsi/meta.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "stepppasha",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-HELMET",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/equipped-OUTERCLOTHING.png
new file mode 100644
index 0000000000..5572ecd007
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/equipped-OUTERCLOTHING.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/icon.png b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/icon.png
new file mode 100644
index 0000000000..a4205712d8
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/icon.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-left.png b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-left.png
new file mode 100644
index 0000000000..edc2a32edb
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-left.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-right.png b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-right.png
new file mode 100644
index 0000000000..5e35789113
Binary files /dev/null and b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/inhand-right.png differ
diff --git a/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/meta.json b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/meta.json
new file mode 100644
index 0000000000..61fc5a5260
--- /dev/null
+++ b/Resources/Textures/White/_Engi/Clothing/OuterClothing/armor_reflect_ghetto.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "stepppasha",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-OUTERCLOTHING",
+ "directions": 4
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/icon.png b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/icon.png
new file mode 100644
index 0000000000..f1bc32c7d6
Binary files /dev/null and b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/icon.png differ
diff --git a/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-left.png b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-left.png
new file mode 100644
index 0000000000..ccfebc408c
Binary files /dev/null and b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-left.png differ
diff --git a/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-right.png b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-right.png
new file mode 100644
index 0000000000..237cb837c3
Binary files /dev/null and b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/inhand-right.png differ
diff --git a/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/meta.json b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/meta.json
new file mode 100644
index 0000000000..cb084b7fa0
--- /dev/null
+++ b/Resources/Textures/White/_Engi/Objects/Weapons/ghetto_mirror_shield.rsi/meta.json
@@ -0,0 +1,22 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/Citadel-Station-13/Citadel-Station-13/commit/84223c65f5caf667a84f3c0f49bc2a41cdc6c4e3",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ }
+ ]
+}