Merge branch 'Transfer/Engi' into EngiTransfer
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared._White._Engi.BucketHelmet;
|
||||
|
||||
namespace Content.Server._White._Engi.BucketHelmet;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// This handles placemet of PreventStrippingFromEarsComponent when bucket helmet is in use.
|
||||
/// </summary>
|
||||
public sealed class BucketHelmetSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<BucketHelmetComponent, GotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<BucketHelmetComponent, GotUnequippedEvent>(OnGotUnequipped);
|
||||
}
|
||||
|
||||
|
||||
public void OnGotUnequipped(EntityUid uid, BucketHelmetComponent component, GotUnequippedEvent args)
|
||||
{
|
||||
RemComp<PreventStrippingFromEarsComponent>(args.Equipee);
|
||||
}
|
||||
|
||||
public void OnGotEquipped(EntityUid uid, BucketHelmetComponent component, GotEquippedEvent args)
|
||||
{
|
||||
if (args.Slot == "head")
|
||||
EnsureComp<PreventStrippingFromEarsComponent>(args.Equipee);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._White._Engi.PacifiedOnChaplainAction
|
||||
{
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// Adds verb for chaplain to pacify entity.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class PacifiedOnChaplainActionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SoundSpecifier ActionSound = new SoundPathSpecifier("/Audio/Effects/holy.ogg");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// WD
|
||||
/// </summary>
|
||||
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<PacifiedOnChaplainActionComponent, AfterInteractEvent>(OnAfterInteract);
|
||||
SubscribeLocalEvent<PacifiedOnChaplainActionComponent, GetVerbsEvent<AlternativeVerb>>(AddPacifiedOnChaplainVerb);
|
||||
}
|
||||
|
||||
private void Action(PacifiedOnChaplainActionComponent component, EntityUid target, EntityUid user)
|
||||
{
|
||||
var popup = "";
|
||||
|
||||
if (HasComp<PacifiedComponent>(target))
|
||||
{
|
||||
popup = "unpacified-by-chaplain";
|
||||
RemComp<PacifiedComponent>(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
popup = "pacified-by-chaplain";
|
||||
EnsureComp<PacifiedComponent>(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<BibleUserComponent>(args.User))
|
||||
return;
|
||||
|
||||
Action(component, (EntityUid) args.Target, args.User);
|
||||
|
||||
_delay.TryResetDelay((uid, useDelay));
|
||||
|
||||
return;
|
||||
}
|
||||
private void AddPacifiedOnChaplainVerb(EntityUid uid, PacifiedOnChaplainActionComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
if (!HasComp<BibleUserComponent>(args.User))
|
||||
return;
|
||||
|
||||
if (!_blocker.CanInteract(args.User, uid))
|
||||
return;
|
||||
|
||||
var verbName = "";
|
||||
|
||||
if (HasComp<PacifiedComponent>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IPrototypeManager>();
|
||||
if (!prototypeManager.TryIndex<StationGoalPrototype>(protoId, out var proto))
|
||||
{
|
||||
shell.WriteError($"No station goal found with ID {protoId}!");
|
||||
return;
|
||||
}
|
||||
|
||||
var stationGoalPaper = IoCManager.Resolve<IEntityManager>().System<StationGoalPaperSystem>();
|
||||
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<IPrototypeManager>()
|
||||
.EnumeratePrototypes<StationGoalPrototype>()
|
||||
.Select(p => new CompletionOption(p.ID));
|
||||
|
||||
return CompletionResult.FromHintOptions(options, Loc.GetString("send-station-goal-command-arg-id"));
|
||||
}
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._White._Engi.StationGoal
|
||||
{
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// If attached to a station prototype, will send the station a random goal from the list.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class StationGoalComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<ProtoId<StationGoalPrototype>> Goals = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Server._White._Engi.StationGoal
|
||||
{
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// Paper with a written station goal in it.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class StationGoalPaperComponent : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// System to spawn paper with station goal.
|
||||
/// </summary>
|
||||
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<RoundStartingEvent>(OnRoundStarting);
|
||||
}
|
||||
|
||||
private void OnRoundStarting(RoundStartingEvent ev)
|
||||
{
|
||||
var playerCount = _playerManager.PlayerCount;
|
||||
|
||||
var query = EntityQueryEnumerator<StationGoalComponent>();
|
||||
while (query.MoveNext(out var uid, out var station))
|
||||
{
|
||||
var tempGoals = new List<ProtoId<StationGoalPrototype>>(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<StationGoalPrototype> goal)
|
||||
{
|
||||
return SendStationGoal(ent, _proto.Index(goal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a station goal on selected station to all faxes which are authorized to receive it.
|
||||
/// </summary>
|
||||
/// <returns>True if at least one fax received paper</returns>
|
||||
public bool SendStationGoal(EntityUid? ent, StationGoalPrototype goal)
|
||||
{
|
||||
if (ent is null)
|
||||
return false;
|
||||
|
||||
if (!TryComp<StationDataComponent>(ent, out var stationData))
|
||||
return false;
|
||||
|
||||
var today = DateTime.Today.ToString("dd.MM");
|
||||
var namesList = new List<string>
|
||||
{
|
||||
"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<StampDisplayInfo>
|
||||
{
|
||||
new() { StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), StampedColor = Color.FromHex("#006600") },
|
||||
});
|
||||
|
||||
var wasSent = false;
|
||||
var query = EntityQueryEnumerator<FaxMachineComponent>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._White._Engi.StationGoal
|
||||
{
|
||||
/// <summary>
|
||||
/// WD
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Goal may require certain items to complete. These items will appear near the receving fax machine at the start of the round.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntProtoId> Spawns = new();
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,14 @@ public sealed partial class FaxMachineComponent : Component
|
||||
[DataField]
|
||||
public bool ReceiveNukeCodes { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// Should that fax receive station goal info
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("receiveStationGoal")]
|
||||
public bool ReceiveStationGoal { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Sound to play when fax has been emagged
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._White._Engi.BucketHelmet;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// This is used for bucket helmet.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class BucketHelmetComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._White._Engi.BucketHelmet;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// This is used to block stripping headsets when bucket helmet is on.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class PreventStrippingFromEarsComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._White._Engi.DamageableClothing;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// This component goes on an equippable item that should take damage while in use.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class DamageableClothingComponent : Component
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The entity that's wearing the item.
|
||||
/// </summary>
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityUid? User;
|
||||
|
||||
/// <summary>
|
||||
/// The damage modifier to use on item.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public DamageModifierSet DamageModifier = default!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Content.Shared._White._Engi.DamageableClothing;
|
||||
|
||||
/// <summary>
|
||||
/// WD.
|
||||
/// This component gets dynamically added to an Entity via the <see cref="DamageableClothing"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class DamageableClothingUserComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity that's also being damaged.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid? ItemId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared.Inventory.Events;
|
||||
|
||||
namespace Content.Shared._White._Engi.DamageableClothing;
|
||||
|
||||
/// <summary>
|
||||
/// WD
|
||||
/// </summary>
|
||||
public sealed partial class DamageableClothingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeUser();
|
||||
|
||||
SubscribeLocalEvent<DamageableClothingComponent, GotEquippedEvent>(OnEquipped);
|
||||
SubscribeLocalEvent<DamageableClothingComponent, GotUnequippedEvent>(OnUnequipped);
|
||||
SubscribeLocalEvent<DamageableClothingComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnEquipped(EntityUid uid, DamageableClothingComponent component, GotEquippedEvent args)
|
||||
{
|
||||
if (_gameTiming.ApplyingState)
|
||||
return;
|
||||
component.User = args.Equipee;
|
||||
var userComp = EnsureComp<DamageableClothingUserComponent>(args.Equipee);
|
||||
userComp.ItemId = args.Equipment;
|
||||
}
|
||||
|
||||
private void OnUnequipped(EntityUid uid, DamageableClothingComponent component, GotUnequippedEvent args)
|
||||
{
|
||||
RemCompDeferred<DamageableClothingUserComponent>(args.Equipee);
|
||||
component.User = null;
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, DamageableClothingComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (component.User != null)
|
||||
{
|
||||
RemCompDeferred<DamageableClothingUserComponent>(component.User.Value);
|
||||
component.User = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Content.Shared.Damage;
|
||||
|
||||
namespace Content.Shared._White._Engi.DamageableClothing;
|
||||
|
||||
/// <summary>
|
||||
/// WD
|
||||
/// </summary>
|
||||
public sealed partial class DamageableClothingSystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
|
||||
private void InitializeUser()
|
||||
{
|
||||
SubscribeLocalEvent<DamageableClothingUserComponent, DamageModifyEvent>(OnUserDamageModified);
|
||||
SubscribeLocalEvent<DamageableClothingComponent, DamageModifyEvent>(OnDamageModified);
|
||||
SubscribeLocalEvent<DamageableClothingUserComponent, EntityTerminatingEvent>(OnEntityTerminating);
|
||||
}
|
||||
|
||||
private void OnUserDamageModified(EntityUid uid, DamageableClothingUserComponent component, DamageModifyEvent args)
|
||||
{
|
||||
if (TryComp<DamageableClothingComponent>(component.ItemId, out var blocking))
|
||||
{
|
||||
if (args.Damage.GetTotal() <= 0)
|
||||
return;
|
||||
|
||||
if (!TryComp<DamageableComponent>(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<DamageableClothingComponent>(component.ItemId, out var blockingComponent))
|
||||
return;
|
||||
|
||||
RemCompDeferred<DamageableClothingUserComponent>(uid);
|
||||
}
|
||||
|
||||
}
|
||||
4
Resources/Locale/ru-RU/White/bucket-helmet.ftl
Normal file
@@ -0,0 +1,4 @@
|
||||
ent-ClothingHeadBucketHelmet = шлем из ведра
|
||||
.desc = Обычное ведро с двумя прорезями для глаз. При ношении на голове что-то липкое внутри цепляется за гарнитуру.
|
||||
|
||||
buckethelmet-cant-strip = Шлем из ведра не позволяет это сделать
|
||||
@@ -0,0 +1,2 @@
|
||||
ent-ClothingOuterArmorReflectiveGhetto = самодельный отражающий жилет
|
||||
.desc = Два зеркала соединённые проводами для сомнительной защиты от лазеров.
|
||||
2
Resources/Locale/ru-RU/White/ghetto-mirror-shield.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
ent-MirrorShieldGhetto = самодельный зеркальный щит
|
||||
.desc = Сделанное на скорую руку зеркало с рукояткой для использования как сомнительная защита от лазеров.
|
||||
@@ -0,0 +1,5 @@
|
||||
pacified-by-chaplain = {$target} пасифицирован.
|
||||
unpacified-by-chaplain = {$target} освобождён.
|
||||
|
||||
pacify-by-chaplain = Пасифицировать
|
||||
unpacify-by-chaplain = Освободить
|
||||
3
Resources/Locale/ru-RU/_Engi/possesed-blade.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
ghost-role-information-possessed-blade-name = Одержимый Клинок
|
||||
ghost-role-information-possessed-blade-description = Вы - Одержимый Клинок. Подчиняйтесь своему владельцу.
|
||||
ghost-role-information-possessed-blade-rules = Вы не имеете право атаковать своего владельца. Право собственности может быть передано только вашим владельцем.
|
||||
251
Resources/Locale/ru-RU/_Engi/station-goal.ftl
Normal file
@@ -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 (десять тысяч) кредитов.
|
||||
@@ -1,3 +1,3 @@
|
||||
send-station-goal-command-description = Отправляет выбранную цель станции на всех факсы способные её принять
|
||||
send-station-goal-command-description = WD. Отправляет выбранную цель станции на все факсы способные её принять
|
||||
send-station-goal-command-help-text = Использование: { $command } <id-цели>
|
||||
send-station-goal-command-arg-id = <ID цели>
|
||||
|
||||
@@ -66,3 +66,7 @@
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Plastic: 50
|
||||
- type: Construction # WD
|
||||
deconstructionTarget: null
|
||||
graph: ClothingHeadBucketHelmet
|
||||
node: start
|
||||
|
||||
@@ -28,3 +28,7 @@
|
||||
storedRotation: -44 # WD
|
||||
shape: # WD
|
||||
- 0,0,1,3
|
||||
- type: KnockDownOnHit
|
||||
knockDownBehavior: NoDrop
|
||||
knockdownTime: 0.8
|
||||
requireWield: true
|
||||
|
||||
@@ -39,3 +39,7 @@
|
||||
isBloodDagger: false
|
||||
- type: UseDelay
|
||||
delay: 1
|
||||
- type: KnockDownOnHit
|
||||
knockDownBehavior: NoDrop
|
||||
knockdownTime: 0.8
|
||||
requireWield: true
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -120,3 +120,6 @@
|
||||
|
||||
- type: Tag
|
||||
id: VoiceActivatedBombImplant
|
||||
|
||||
- type: Tag
|
||||
id: MirrorShieldGhetto
|
||||
|
||||
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 576 B |
|
After Width: | Height: | Size: 319 B |
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 607 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 330 B |
|
After Width: | Height: | Size: 758 B |
|
After Width: | Height: | Size: 697 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||