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 + } + ] +}