Merge branch 'master' into airalarm
This commit is contained in:
commit
94157358a8
|
|
@ -2,6 +2,7 @@ using Content.Client.Cargo.UI;
|
|||
using Content.Shared.Cargo.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
using Content.Shared._DV.Cargo.Components; // DeltaV: Bounty claim messages
|
||||
|
||||
namespace Content.Client.Cargo.BUI;
|
||||
|
||||
|
|
@ -30,6 +31,18 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
|
|||
{
|
||||
SendMessage(new BountySkipMessage(id));
|
||||
};
|
||||
|
||||
// DeltaV: bounty claim stuff begins
|
||||
_menu.OnClaimButtonPressed += id =>
|
||||
{
|
||||
SendMessage(new BountyClaimedMessage(id));
|
||||
};
|
||||
|
||||
_menu.OnStatusOptionSelected += (id, status) =>
|
||||
{
|
||||
SendMessage(new BountySetStatusMessage(id, status));
|
||||
};
|
||||
// DeltaV: bounty claim stuff ends
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState message)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<RichTextLabel Name="RewardLabel"/>
|
||||
<RichTextLabel Name="ManifestLabel"/>
|
||||
<RichTextLabel Name="ClaimedBylabel"/> <!-- DeltaV bounty claim -->
|
||||
<RichTextLabel Name="StatusLabel"/> <!-- DeltaV bounty claim -->
|
||||
</BoxContainer>
|
||||
<Control MinWidth="10"/>
|
||||
<BoxContainer Orientation="Vertical" MinWidth="120">
|
||||
|
|
@ -17,14 +19,22 @@
|
|||
<Button Name="PrintButton"
|
||||
Text="{Loc 'bounty-console-label-button-text'}"
|
||||
HorizontalExpand="False"
|
||||
HorizontalAlignment="Right"
|
||||
StyleClasses="OpenRight"/>
|
||||
StyleClasses="OpenBoth"/>
|
||||
<Button Name="SkipButton"
|
||||
Text="{Loc 'bounty-console-skip-button-text'}"
|
||||
HorizontalExpand="False"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalExpand="True"
|
||||
StyleClasses="OpenLeft"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" MinWidth="120"> <!-- Begin DeltaV bounty claim content -->
|
||||
<Button Name="ClaimButton"
|
||||
Text= "{Loc 'bounty-console-claim-button-text'}"
|
||||
HorizontalExpand="False"
|
||||
StyleClasses="OpenRight"/>
|
||||
<OptionButton Name="BountyStatusSelector"
|
||||
Access="Public"
|
||||
StyleClasses="OpenBoth"
|
||||
HorizontalExpand="True"/>
|
||||
</BoxContainer> <!-- End DeltaV content-->
|
||||
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ public sealed partial class BountyEntry : BoxContainer
|
|||
|
||||
public Action? OnLabelButtonPressed;
|
||||
public Action? OnSkipButtonPressed;
|
||||
public Action? OnClaimButtonPressed; // DeltaV
|
||||
public Action? OnStatusOptionSelected; // DeltaV
|
||||
|
||||
public TimeSpan EndTime;
|
||||
public TimeSpan UntilNextSkip;
|
||||
|
|
@ -45,6 +47,20 @@ public sealed partial class BountyEntry : BoxContainer
|
|||
|
||||
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
||||
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
||||
|
||||
// Begin DeltaV bounty claiming
|
||||
ClaimButton.OnPressed += _ => OnClaimButtonPressed?.Invoke();
|
||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Undelivered)}"), 0);
|
||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Waiting)}"), 1);
|
||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.OnShuttle)}"), 2);
|
||||
|
||||
BountyStatusSelector.Select((int) bounty.Status);
|
||||
BountyStatusSelector.ToolTip = Loc.GetString($"bounty-console-status-tooltip-{bounty.Status.ToString()}");
|
||||
|
||||
var claimedByText = string.IsNullOrEmpty(bounty.ClaimedBy) ? Loc.GetString("bounty-console-claimed-by-none") : bounty.ClaimedBy;
|
||||
ClaimedBylabel.SetMarkup(Loc.GetString("bounty-console-claimed-by", ("claimant", claimedByText)));
|
||||
StatusLabel.SetMarkup(Loc.GetString($"bounty-console-formatted-status-{bounty.Status.ToString()}"));
|
||||
// End DeltaV bounty claiming
|
||||
}
|
||||
|
||||
private void UpdateSkipButton(float deltaSeconds)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
<!--DeltaV - SetSize was 550, now 750 to accomodate bounty claim UI -->
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'bounty-console-menu-title'}"
|
||||
SetSize="550 420"
|
||||
SetSize="750 420"
|
||||
MinSize="400 350">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||
{
|
||||
public Action<string>? OnLabelButtonPressed;
|
||||
public Action<string>? OnSkipButtonPressed;
|
||||
public Action<string>? OnClaimButtonPressed; // DeltaV
|
||||
public Action<string, int>? OnStatusOptionSelected; // DeltaV
|
||||
|
||||
public CargoBountyMenu()
|
||||
{
|
||||
|
|
@ -31,6 +33,8 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||
var entry = new BountyEntry(b, untilNextSkip);
|
||||
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
||||
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
||||
entry.OnClaimButtonPressed += () => OnClaimButtonPressed?.Invoke(b.Id); // DeltaV
|
||||
entry.BountyStatusSelector.OnItemSelected += args => OnStatusOptionSelected?.Invoke(b.Id, args.Id); // DeltaV
|
||||
|
||||
BountyEntriesContainer.AddChild(entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ namespace Content.Client.Input
|
|||
common.AddFunction(ContentKeyFunctions.RotateStoredItem);
|
||||
common.AddFunction(ContentKeyFunctions.SaveItemLocation);
|
||||
common.AddFunction(ContentKeyFunctions.Point);
|
||||
// Floofstation section
|
||||
common.AddFunction(ContentKeyFunctions.OfferItem);
|
||||
// Floofstation section end
|
||||
common.AddFunction(ContentKeyFunctions.ZoomOut);
|
||||
common.AddFunction(ContentKeyFunctions.ZoomIn);
|
||||
common.AddFunction(ContentKeyFunctions.ResetZoom);
|
||||
|
|
|
|||
|
|
@ -75,9 +75,11 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
|
|||
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
||||
name = Loc.GetString("navmap-unknown-entity");
|
||||
|
||||
var pos = _xform.ToMapCoordinates(blip.Coordinates); // DeltaV - map-coordinates
|
||||
|
||||
var message = name + "\n" + Loc.GetString("navmap-location",
|
||||
("x", MathF.Round(blip.Coordinates.X)),
|
||||
("y", MathF.Round(blip.Coordinates.Y)));
|
||||
("x", MathF.Round(pos.X)), // DeltaV - map-coordinates
|
||||
("y", MathF.Round(pos.Y))); // DeltaV - map-coordinates
|
||||
|
||||
_trackedEntityLabel.Text = message;
|
||||
_trackedEntityPanel.Visible = true;
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ namespace Content.Client.Options.UI.Tabs
|
|||
AddButton(ContentKeyFunctions.MovePulledObject);
|
||||
AddButton(ContentKeyFunctions.ReleasePulledObject);
|
||||
AddButton(ContentKeyFunctions.Point);
|
||||
AddButton(ContentKeyFunctions.OfferItem); // Floofstation
|
||||
AddButton(ContentKeyFunctions.RotateObjectClockwise);
|
||||
AddButton(ContentKeyFunctions.RotateObjectCounterclockwise);
|
||||
AddButton(ContentKeyFunctions.FlipObject);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
using System.Linq;
|
||||
using Content.Shared._DV.Forensics;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._DV.Forensics;
|
||||
|
||||
public sealed class DVItemSlotVisualsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
|
||||
private static readonly ResPath TextureRoot = new("/Textures");
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVItemSlotVisualsComponent, EntInsertedIntoContainerMessage>(OnInsertedIntoContainer);
|
||||
SubscribeLocalEvent<DVItemSlotVisualsComponent, EntRemovedFromContainerMessage>(OnRemovedFromContainer);
|
||||
}
|
||||
|
||||
private void RefreshVisuals(Entity<DVItemSlotVisualsComponent> ent)
|
||||
{
|
||||
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||
if (slot.ContainedEntity is { } contained)
|
||||
{
|
||||
_sprite.CopySprite(contained, ent.Owner);
|
||||
_sprite.AddLayer(ent.Owner, ent.Comp.FilledSprite);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sprite = Comp<SpriteComponent>(ent);
|
||||
var count = sprite.AllLayers.Count();
|
||||
for (var i = count - 1; i >= 0; i--)
|
||||
{
|
||||
_sprite.RemoveLayer((ent, sprite), i);
|
||||
}
|
||||
|
||||
if (ent.Comp.UnfilledSprite is not SpriteSpecifier.Rsi rsi)
|
||||
{
|
||||
throw new InvalidOperationException($"{ToPrettyString(ent)} has an unfilled sprite that's not an RSI");
|
||||
}
|
||||
|
||||
if (!_resourceCache.TryGetResource<RSIResource>(TextureRoot / rsi.RsiPath, out var res))
|
||||
{
|
||||
throw new InvalidOperationException($"{ToPrettyString(ent)} has invalid RSI: {TextureRoot / rsi.RsiPath}");
|
||||
}
|
||||
|
||||
_sprite.SetBaseRsi(ent.Owner, res.RSI);
|
||||
_sprite.AddLayer(ent.Owner, ent.Comp.UnfilledSprite);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInsertedIntoContainer(Entity<DVItemSlotVisualsComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != ent.Comp.ItemSlot)
|
||||
return;
|
||||
|
||||
RefreshVisuals(ent);
|
||||
}
|
||||
|
||||
private void OnRemovedFromContainer(Entity<DVItemSlotVisualsComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != ent.Comp.ItemSlot)
|
||||
return;
|
||||
|
||||
RefreshVisuals(ent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
using System.Numerics;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._Floof.OfferItem;
|
||||
|
||||
public sealed class OfferItemIndicatorsOverlay : Overlay
|
||||
{
|
||||
private readonly IInputManager _inputManager;
|
||||
private readonly IEntityManager _entMan;
|
||||
private readonly IEyeManager _eye;
|
||||
private readonly OfferItemSystem _offer;
|
||||
|
||||
private readonly Texture _sight;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
private readonly Color _mainColor = Color.White.WithAlpha(0.3f);
|
||||
private readonly Color _strokeColor = Color.Black.WithAlpha(0.5f);
|
||||
private readonly float _scale = 0.6f; // 1 is a little big
|
||||
|
||||
public OfferItemIndicatorsOverlay(IInputManager input, IEntityManager entMan,
|
||||
IEyeManager eye, OfferItemSystem offerSys)
|
||||
{
|
||||
_inputManager = input;
|
||||
_entMan = entMan;
|
||||
_eye = eye;
|
||||
_offer = offerSys;
|
||||
|
||||
var spriteSys = _entMan.EntitySysManager.GetEntitySystem<SpriteSystem>();
|
||||
_sight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new("/Textures/_Floof/Interface/Misc/give_item.rsi"), "give_item"));
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (!_offer.IsInOfferMode())
|
||||
return false;
|
||||
|
||||
return base.BeforeDraw(in args);
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
var mouseScreenPosition = _inputManager.MouseScreenPosition;
|
||||
var mousePosMap = _eye.PixelToMap(mouseScreenPosition);
|
||||
if (mousePosMap.MapId != args.MapId)
|
||||
return;
|
||||
|
||||
|
||||
var mousePos = mouseScreenPosition.Position;
|
||||
var uiScale = (args.ViewportControl as Control)?.UIScale ?? 1f;
|
||||
var limitedScale = uiScale > 1.25f ? 1.25f : uiScale;
|
||||
|
||||
DrawSight(_sight, args.ScreenHandle, mousePos, limitedScale * _scale);
|
||||
}
|
||||
|
||||
private void DrawSight(Texture sight, DrawingHandleScreen screen, Vector2 centerPos, float scale)
|
||||
{
|
||||
var sightSize = sight.Size * scale;
|
||||
var expandedSize = sightSize + new Vector2(7f, 7f);
|
||||
|
||||
screen.DrawTextureRect(sight,
|
||||
UIBox2.FromDimensions(centerPos - sightSize * 0.5f, sightSize), _strokeColor);
|
||||
screen.DrawTextureRect(sight,
|
||||
UIBox2.FromDimensions(centerPos - expandedSize * 0.5f, expandedSize), _mainColor);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using Content.Shared._Floof.OfferItem;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
|
||||
namespace Content.Client._Floof.OfferItem;
|
||||
|
||||
public sealed class OfferItemSystem : SharedOfferItemSystem
|
||||
{
|
||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eye = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_overlayManager.AddOverlay(new OfferItemIndicatorsOverlay(
|
||||
_inputManager,
|
||||
EntityManager,
|
||||
_eye,
|
||||
this));
|
||||
}
|
||||
public override void Shutdown()
|
||||
{
|
||||
_overlayManager.RemoveOverlay<OfferItemIndicatorsOverlay>();
|
||||
base.Shutdown();
|
||||
}
|
||||
|
||||
public bool IsInOfferMode()
|
||||
{
|
||||
var entity = _playerManager.LocalEntity;
|
||||
|
||||
if (entity == null)
|
||||
return false;
|
||||
|
||||
return IsInOfferMode(entity.Value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Access.Systems; // DeltaV
|
||||
using Content.Server.Cargo.Components;
|
||||
using Content.Server.NameIdentifier;
|
||||
using Content.Shared.Access.Components;
|
||||
|
|
@ -20,6 +21,7 @@ using Robust.Shared.Prototypes;
|
|||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared._DV.Cargo.Components; // DeltaV: Bounty claim messages
|
||||
|
||||
namespace Content.Server.Cargo.Systems;
|
||||
|
||||
|
|
@ -28,6 +30,7 @@ public sealed partial class CargoSystem
|
|||
[Dependency] private readonly ContainerSystem _container = default!;
|
||||
[Dependency] private readonly NameIdentifierSystem _nameIdentifier = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSys = default!;
|
||||
[Dependency] private readonly IdCardSystem _idCard = default!; // DeltaV
|
||||
|
||||
private static readonly ProtoId<NameIdentifierGroupPrototype> BountyNameIdentifierGroup = "Bounty";
|
||||
|
||||
|
|
@ -40,6 +43,8 @@ public sealed partial class CargoSystem
|
|||
SubscribeLocalEvent<CargoBountyConsoleComponent, BoundUIOpenedEvent>(OnBountyConsoleOpened);
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyPrintLabelMessage>(OnPrintLabelMessage);
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySkipMessage>(OnSkipBountyMessage);
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountyClaimedMessage>(OnBountyClaimedMessage); // DeltaV
|
||||
SubscribeLocalEvent<CargoBountyConsoleComponent, BountySetStatusMessage>(OnSetBountyStatusMessage); // DeltaV
|
||||
SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice);
|
||||
SubscribeLocalEvent<EntitySoldEvent>(OnSold);
|
||||
SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit);
|
||||
|
|
@ -111,6 +116,72 @@ public sealed partial class CargoSystem
|
|||
_audio.PlayPvs(component.SkipSound, uid);
|
||||
}
|
||||
|
||||
// Begin DeltaV bounty claim system
|
||||
private void OnSetBountyStatusMessage(Entity<CargoBountyConsoleComponent> ent, ref BountySetStatusMessage args)
|
||||
{
|
||||
if (_station.GetOwningStation(ent.Owner) is not { } station || !TryComp<StationCargoBountyDatabaseComponent>(station, out var bountyDbComp))
|
||||
return;
|
||||
|
||||
for (var i = 0; i < bountyDbComp.Bounties.Count; i++)
|
||||
{
|
||||
var bounty = bountyDbComp.Bounties[i];
|
||||
|
||||
if (bounty.Id != args.BountyId)
|
||||
continue;
|
||||
|
||||
var newData = new CargoBountyData
|
||||
{
|
||||
Id = bounty.Id,
|
||||
Bounty = bounty.Bounty,
|
||||
ClaimedBy = bounty.ClaimedBy,
|
||||
Status = (CargoBountyStatus)args.Status,
|
||||
};
|
||||
|
||||
bountyDbComp.Bounties[i] = newData;
|
||||
}
|
||||
|
||||
var untilNextSkip = bountyDbComp.NextSkipTime - Timing.CurTime;
|
||||
_uiSystem.SetUiState(ent.Owner, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDbComp.Bounties, bountyDbComp.History, untilNextSkip));
|
||||
}
|
||||
|
||||
private void OnBountyClaimedMessage(Entity<CargoBountyConsoleComponent> ent, ref BountyClaimedMessage args)
|
||||
{
|
||||
if (_station.GetOwningStation(ent.Owner) is not { } station || !TryComp<StationCargoBountyDatabaseComponent>(station, out var bountyDbComp))
|
||||
return;
|
||||
|
||||
for (var i = 0; i < bountyDbComp.Bounties.Count; i++)
|
||||
{
|
||||
var bounty = bountyDbComp.Bounties[i];
|
||||
|
||||
if (bounty.Id != args.BountyId)
|
||||
continue;
|
||||
|
||||
string name;
|
||||
if (_idCard.TryFindIdCard(args.Actor, out var idCard) && idCard.Comp.FullName != null)
|
||||
{
|
||||
name = idCard.Comp.FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = Loc.GetString("bounty-console-claimed-by-unknown");
|
||||
}
|
||||
|
||||
var newData = new CargoBountyData
|
||||
{
|
||||
Id = bounty.Id,
|
||||
Bounty = bounty.Bounty,
|
||||
ClaimedBy = name.Equals(bounty.ClaimedBy) ? string.Empty : name,
|
||||
Status = bounty.Status,
|
||||
};
|
||||
|
||||
bountyDbComp.Bounties[i] = newData;
|
||||
}
|
||||
|
||||
var untilNextSkip = bountyDbComp.NextSkipTime - Timing.CurTime;
|
||||
_uiSystem.SetUiState(ent.Owner, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDbComp.Bounties, bountyDbComp.History, untilNextSkip));
|
||||
}
|
||||
// End DeltaV bounty claim system
|
||||
|
||||
public void SetupBountyLabel(EntityUid uid, EntityUid stationId, CargoBountyData bounty, PaperComponent? paper = null, CargoBountyLabelComponent? label = null)
|
||||
{
|
||||
if (!Resolve(uid, ref paper, ref label) || !_protoMan.Resolve<CargoBountyPrototype>(bounty.Bounty, out var prototype))
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ using Robust.Shared.Timing;
|
|||
using System.Linq;
|
||||
using Content.Shared.EntityEffects.Effects.Solution;
|
||||
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
||||
using Content.Server.Body.Components; // Delta V
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
|
||||
|
|
@ -267,7 +268,8 @@ public sealed class SmokeSystem : EntitySystem
|
|||
if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) || bloodSolution.AvailableVolume <= 0)
|
||||
return;
|
||||
|
||||
var blockIngestion = _internals.AreInternalsWorking(entity);
|
||||
var blockIngestion = _internals.AreInternalsWorking(entity)
|
||||
|| !HasComp<RespiratorComponent>(entity); // Starlight - Shadekin does not breathe and "AreInternalsWorking" does not check for that
|
||||
|
||||
var cloneSolution = solution.Clone();
|
||||
var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using Robust.Shared.Player;
|
|||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server.Mobs; // Starlight
|
||||
|
||||
namespace Content.Server.Ghost
|
||||
{
|
||||
|
|
@ -619,7 +620,15 @@ namespace Content.Server.Ghost
|
|||
_damageable.GetTotalDamage((playerEntity.Value, damageable));
|
||||
}
|
||||
|
||||
DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
|
||||
// Starlight - Start
|
||||
//DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
|
||||
|
||||
var damageType = _prototypeManager.Index(AsphyxiationDamageType);
|
||||
if (TryComp<DeathgaspComponent>(playerEntity, out var deathgasp))
|
||||
damageType = _prototypeManager.Index(deathgasp.DamageType);
|
||||
|
||||
DamageSpecifier damage = new(damageType, dealtDamage);
|
||||
// Starlight - End
|
||||
|
||||
_damageable.ChangeDamage(playerEntity.Value, damage, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Chat.Prototypes; // Starlight
|
||||
using Content.Shared.Damage.Prototypes; // Starlight
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Mobs;
|
||||
|
|
@ -21,4 +23,10 @@ public sealed partial class DeathgaspComponent : Component
|
|||
/// </summary>
|
||||
[DataField]
|
||||
public bool NeedsCritical = true;
|
||||
|
||||
/// <summary>
|
||||
/// Starlight - The damage that is taken when succumbing
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<DamageTypePrototype> DamageType = "Asphyxiation";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,9 +55,13 @@ public sealed class PseudoItemSystem : SharedPseudoItemSystem
|
|||
|
||||
protected override void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component, GettingPickedUpAttemptEvent args)
|
||||
{
|
||||
// Floof - changed this a bit to actually start a do-after
|
||||
// Try to pick the entity up instead first
|
||||
if (args.User != args.Item && _carrying.TryCarry(args.User, uid))
|
||||
if (args.User != args.Item
|
||||
&& TryComp<CarriableComponent>(uid, out var carriable)
|
||||
&& _carrying.CanCarry(args.User, (uid, carriable)))
|
||||
{
|
||||
_carrying.StartCarryDoAfter(args.User, (uid, carriable));
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,20 +209,24 @@ namespace Content.Server.Psionics.Glimmer
|
|||
|
||||
private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component, DestructionEventArgs args)
|
||||
{
|
||||
Spawn("MaterialBluespace1", Transform(uid).Coordinates);
|
||||
|
||||
var proberCoords = Transform(uid).Coordinates;
|
||||
var tier = _glimmerSystem.GetGlimmerTier();
|
||||
if (tier < GlimmerTier.High)
|
||||
return;
|
||||
|
||||
var totalIntensity = (float) (_glimmerSystem.Glimmer * 2);
|
||||
var slope = (float) (11 - _glimmerSystem.Glimmer / 100);
|
||||
var maxIntensity = 20;
|
||||
var explosionMultiplier = 2;
|
||||
if (_glimmerSystem.GetGlimmerTier() == GlimmerTier.Critical) // YOU DONE FUCKED UP
|
||||
explosionMultiplier = 3;
|
||||
|
||||
var removed = (float) _glimmerSystem.Glimmer * _random.NextFloat(0.06f, 0.08f);
|
||||
_glimmerSystem.Glimmer -= (int) removed;
|
||||
var totalIntensity = (float)(_glimmerSystem.Glimmer * explosionMultiplier);
|
||||
var slope = (float)(11 - _glimmerSystem.Glimmer / 100);
|
||||
var maxIntensity = 75; // Same as syndicate bomb
|
||||
|
||||
var removed = _glimmerSystem.Glimmer * _random.NextFloat(0.06f, 0.08f);
|
||||
_glimmerSystem.Glimmer -= (int)removed;
|
||||
BeamRandomNearProber(uid, _glimmerSystem.Glimmer / 350, _glimmerSystem.Glimmer / 50);
|
||||
_explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity);
|
||||
_explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity, addLog: true);
|
||||
Spawn("MaterialBluespace1", proberCoords); // Congrats on your bluespace!
|
||||
}
|
||||
|
||||
private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent component, UnanchorAttemptEvent args)
|
||||
|
|
@ -230,7 +234,7 @@ namespace Content.Server.Psionics.Glimmer
|
|||
if (component.Locked)
|
||||
{
|
||||
_sharedAudioSystem.PlayPvs(component.ShockNoises, args.User);
|
||||
_electrocutionSystem.TryDoElectrocution(args.User, null, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false);
|
||||
_electrocutionSystem.TryDoElectrocution(args.User, uid, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false);
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,8 @@ public sealed class OracleSystem : EntitySystem
|
|||
|
||||
while (i != 0)
|
||||
{
|
||||
Spawn("MaterialBluespace1", Transform(user).Coordinates);
|
||||
var entityToSpawn = _random.Next(0, 2) == 0 ? "MaterialBluespace1" : "CrystalNormality";
|
||||
Spawn(entityToSpawn, Transform(user).Coordinates);
|
||||
i--;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,12 +125,12 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
|||
RaiseLocalEvent(projectile, ref pierceEv);
|
||||
|
||||
// If the object won't be destroyed, it "tanks" the penetration hit.
|
||||
if (damage.GetTotal() < damageRequired)
|
||||
if (damage.GetTotal() < damageRequired && !pierceEv.Pierced) // DeltaV - Addition of the NT-3
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!projectile.Comp.ProjectileSpent)
|
||||
if (!projectile.Comp.ProjectileSpent && !pierceEv.Pierced) // DeltaV - Addition of the NT-3
|
||||
{
|
||||
projectile.Comp.PenetrationAmount += damageRequired;
|
||||
// The projectile has dealt enough damage to be spent.
|
||||
|
|
@ -139,7 +139,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
|||
return false;
|
||||
}
|
||||
|
||||
if (projectile.Comp.ProjectileSpent && pierceEv.Pierced) // DeltaV - Addition of the NT-3
|
||||
if (projectile.Comp.ProjectileSpent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared.Tag;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._DV.Projectiles.Components;
|
||||
|
|
@ -21,10 +22,14 @@ public sealed partial class PiercingProjectileComponent : Component
|
|||
public float PierceCounter;
|
||||
|
||||
/// <summary>
|
||||
/// The tag that will cause the piercing bullet to increment it's <see cref="PierceCounter"/>.
|
||||
/// The whitelist for checking what increments the <see cref="PierceCounter"/>.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// If this has the tag "Wall" in it, any entity with the tag "Wall" will increment <see cref="PierceCounter"/>
|
||||
/// upon being hit.
|
||||
/// </example>
|
||||
[DataField]
|
||||
public List<ProtoId<TagPrototype>> PierceBlockTag = ["Wall", "Window"];
|
||||
public EntityWhitelist PierceCounterWhitelist;
|
||||
|
||||
/// <summary>
|
||||
/// The number of entities it is allowed to pierce before being deleted.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Content.Shared.FixedPoint;
|
|||
namespace Content.Server._DV.Projectiles.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a piercing projectile hits an entity that doesn't follow upstream piercing rules.
|
||||
/// Raised when a piercing projectile that doesn't follow upstream piercing rules hits an entity.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct ProjectilePierceEvent(EntityUid Target, FixedPoint2 RequiredDamage, bool Pierced = false);
|
||||
|
|
|
|||
|
|
@ -1,29 +1,33 @@
|
|||
using Content.Server._DV.Projectiles.Components;
|
||||
using Content.Server._DV.Projectiles.Events;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Whitelist;
|
||||
|
||||
namespace Content.Server._DV.Projectiles.Systems;
|
||||
|
||||
public sealed class PiercingProjectileSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||
|
||||
// Mobs return a required Damage amount of Float.MaxValue. Therefore, we need to check for absurdly high values.
|
||||
private readonly int _indestructibleNumber = 20000000;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PiercingProjectileComponent, ProjectilePierceEvent>(OnPierce);
|
||||
}
|
||||
|
||||
private void OnPierce(Entity<PiercingProjectileComponent> bullet, ref ProjectilePierceEvent args)
|
||||
{
|
||||
// If the target doesn't have any tags to stop the bullet from piercing, it's automatically true.
|
||||
if (!_tagSystem.HasAnyTag(args.Target, bullet.Comp.PierceBlockTag))
|
||||
if (_whitelist.IsWhitelistFail(bullet.Comp.PierceCounterWhitelist, args.Target))
|
||||
{
|
||||
args.Pierced = true;
|
||||
return;
|
||||
}
|
||||
// If it does have the tag to stop it and enough health to count as "strongly armored", it'll block the bullet.
|
||||
if (bullet.Comp.HealthThreshold < args.RequiredDamage)
|
||||
if (bullet.Comp.HealthThreshold < args.RequiredDamage && args.RequiredDamage < _indestructibleNumber)
|
||||
return;
|
||||
|
||||
if (bullet.Comp.Direction == null) // Get the direction of the bullet to determine which walls count.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Toolshed;
|
||||
using Robust.Shared.Toolshed.Errors;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._DV.Toolshed;
|
||||
|
||||
/// <summary>
|
||||
/// An extended version of the engine's <c>do</c> command. Runs a console command once per piped value,
|
||||
/// substituting <c>$NAME</c> tokens in the command string first.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// On top of the built-in tokens that <c>do</c> supports (<c>$ID</c>, <c>$PID</c>, <c>$WX</c>, <c>$WY</c>,
|
||||
/// <c>$LX</c>, <c>$LY</c>, <c>$SELF</c>), any other <c>$name</c> is resolved as a toolshed variable and
|
||||
/// converted to a string. Tokens that don't resolve to anything are left untouched.
|
||||
///
|
||||
/// Where the command actually runs is explicit:
|
||||
/// <list type="bullet">
|
||||
/// <item><c>doext:client</c> sends it back down to the calling user's own client to run locally. This is what
|
||||
/// you want for client-side commands like <c>exec</c>, which resolve paths against the client's user data.</item>
|
||||
/// <item><c>doext:server</c> runs it server-side as the calling session, like <c>do</c> does.</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <example><code>
|
||||
/// self doext:client "exec /Script_$var.txt"
|
||||
/// i 5 => $count; self doext:server "somecommand $count"
|
||||
/// </code></example>
|
||||
[ToolshedCommand(Name = "doext"), AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class DoExtCommand : ToolshedCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Matches a <c>$name</c> token. Names use the same character set as toolshed variable names, so this
|
||||
/// matches whole identifiers - <c>$IDLE</c> resolves as "IDLE" rather than being mangled into <c>$ID</c>.
|
||||
/// </summary>
|
||||
private static readonly Regex TokenRegex = new(@"\$(\w+)", RegexOptions.Compiled);
|
||||
|
||||
[Dependency] private readonly IConsoleHost _console = default!;
|
||||
|
||||
private SharedTransformSystem? _xform;
|
||||
|
||||
/// <summary>
|
||||
/// Sends the command back down to the calling user's client, which runs it locally.
|
||||
/// </summary>
|
||||
[CommandImplementation("client"), TakesPipedTypeAsGeneric]
|
||||
public IEnumerable<T> Client<T>(IInvocationContext ctx, [PipedArgument] IEnumerable<T> input, string command)
|
||||
{
|
||||
// No session means there's no client to hand this back to - e.g. the server console.
|
||||
if (ctx.Session is not { } session)
|
||||
{
|
||||
ctx.ReportError(new NoClientSessionError());
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var value in input)
|
||||
{
|
||||
_console.RemoteExecuteCommand(session, Substitute(command, value, ctx));
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command on the server as the calling session.
|
||||
/// </summary>
|
||||
[CommandImplementation("server"), TakesPipedTypeAsGeneric]
|
||||
public IEnumerable<T> Server<T>(IInvocationContext ctx, [PipedArgument] IEnumerable<T> input, string command)
|
||||
{
|
||||
foreach (var value in input)
|
||||
{
|
||||
_console.ExecuteCommand(ctx.Session, Substitute(command, value, ctx));
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
|
||||
private string Substitute<T>(string command, T value, IInvocationContext ctx)
|
||||
{
|
||||
return TokenRegex.Replace(command, match =>
|
||||
{
|
||||
var name = match.Groups[1].Value;
|
||||
|
||||
if (TryGetBuiltin(name, value, ctx, out var builtin))
|
||||
return builtin;
|
||||
|
||||
// Anything else is looked up as a toolshed variable and implicitly stringified.
|
||||
if (ctx.ReadVar(name) is { } variable)
|
||||
return Stringify(variable);
|
||||
|
||||
// Unresolved, so leave the token alone rather than silently blanking it.
|
||||
return match.Value;
|
||||
});
|
||||
}
|
||||
|
||||
private bool TryGetBuiltin<T>(string name, T value, IInvocationContext ctx, [NotNullWhen(true)] out string? result)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "SELF":
|
||||
result = Stringify(value);
|
||||
return true;
|
||||
case "PID":
|
||||
result = (ctx.Session?.AttachedEntity ?? EntityUid.Invalid).ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The remaining tokens are all positional, so they only apply when piping entities.
|
||||
if (value is not EntityUid uid)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "ID":
|
||||
result = uid.ToString();
|
||||
return true;
|
||||
case "WX":
|
||||
result = Number(WorldPosition(uid).X);
|
||||
return true;
|
||||
case "WY":
|
||||
result = Number(WorldPosition(uid).Y);
|
||||
return true;
|
||||
case "LX":
|
||||
result = Number(Transform(uid).Coordinates.X);
|
||||
return true;
|
||||
case "LY":
|
||||
result = Number(Transform(uid).Coordinates.Y);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Vector2 WorldPosition(EntityUid uid)
|
||||
{
|
||||
_xform ??= GetSys<SharedTransformSystem>();
|
||||
return _xform.GetWorldPosition(uid);
|
||||
}
|
||||
|
||||
private static string Number(float value) => value.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
private static string Stringify(object? value) => value?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public sealed class NoClientSessionError : IConError
|
||||
{
|
||||
public FormattedMessage DescribeInner()
|
||||
{
|
||||
return FormattedMessage.FromUnformatted("There is no client to run this on. doext:client must be run by a player, not the server console.");
|
||||
}
|
||||
|
||||
public string? Expression { get; set; }
|
||||
public Vector2i? IssueSpan { get; set; }
|
||||
public StackTrace? Trace { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Toolshed;
|
||||
using Robust.Shared.Toolshed.Errors;
|
||||
using Robust.Shared.Toolshed.Syntax;
|
||||
using Robust.Shared.Toolshed.TypeParsers;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server._DV.Toolshed;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the value of a single field or property off of the piped input, by name.
|
||||
/// Member names are resolved the same way <c>vvread</c> does: the member must be exposed
|
||||
/// via <c>[ViewVariables]</c>, <c>[DataField]</c>, or <c>[IncludeDataField]</c>.
|
||||
/// </summary>
|
||||
/// <example><code>ent 12345 . Name</code></example>
|
||||
[ToolshedCommand(Name = "."), AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class FieldCommand : ToolshedCommand
|
||||
{
|
||||
[CommandImplementation]
|
||||
public object? Field([PipedArgument] object? value, [CommandArgument(typeof(FieldNameParser))] string field, IInvocationContext ctx)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
ctx.ReportError(new NullInputFieldError());
|
||||
return null;
|
||||
}
|
||||
|
||||
var type = value.GetType();
|
||||
var member = GetSingleMember(type, field);
|
||||
|
||||
// Restrict to members that vvread would let you read, so this can't be used to peek at arbitrary internals.
|
||||
if (member == null || !ViewVariablesUtility.TryGetViewVariablesAccess(member, out _))
|
||||
{
|
||||
ctx.ReportError(new NoSuchFieldError(type, field));
|
||||
return null;
|
||||
}
|
||||
|
||||
return member switch
|
||||
{
|
||||
FieldInfo f => f.GetValue(value),
|
||||
PropertyInfo p => p.GetValue(value),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the field or property with the given name, mirroring the resolution used by <c>vvread</c>.
|
||||
/// </summary>
|
||||
private static MemberInfo? GetSingleMember(Type type, string member)
|
||||
{
|
||||
var members = type
|
||||
.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => m.Name == member && m is FieldInfo or PropertyInfo)
|
||||
.ToArray();
|
||||
|
||||
if (members.Length == 0)
|
||||
return null;
|
||||
|
||||
// In case there's member hiding going on, grab the one declared by the type of the object by default.
|
||||
return members.Length > 1
|
||||
? members.FirstOrDefault(m => m.DeclaringType == type) ?? members[0]
|
||||
: members[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a field name as a bare identifier (letters, digits, underscore) so that the <c>.</c> command doesn't
|
||||
/// require the name to be wrapped in quotes like the default <see cref="string"/> parser does.
|
||||
/// </summary>
|
||||
public sealed class FieldNameParser : CustomTypeParser<string>
|
||||
{
|
||||
public override bool TryParse(ParserContext ctx, [NotNullWhen(true)] out string? result)
|
||||
{
|
||||
ctx.ConsumeWhitespace();
|
||||
result = ctx.GetWord(ParserContext.IsToken);
|
||||
if (result != null)
|
||||
return true;
|
||||
|
||||
if (ctx.PeekRune() is null)
|
||||
ctx.Error = new OutOfInputError();
|
||||
else
|
||||
ctx.Error = new InvalidFieldNameError();
|
||||
|
||||
ctx.Error.Contextualize(ctx.Input, (ctx.Index, ctx.Index + 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg)
|
||||
{
|
||||
return CompletionResult.FromHint(GetArgHint(arg));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InvalidFieldNameError : IConError
|
||||
{
|
||||
public FormattedMessage DescribeInner()
|
||||
{
|
||||
return FormattedMessage.FromUnformatted("Expected a field name (letters, digits, or underscores).");
|
||||
}
|
||||
|
||||
public string? Expression { get; set; }
|
||||
public Vector2i? IssueSpan { get; set; }
|
||||
public StackTrace? Trace { get; set; }
|
||||
}
|
||||
|
||||
public sealed class NullInputFieldError : IConError
|
||||
{
|
||||
public FormattedMessage DescribeInner()
|
||||
{
|
||||
return FormattedMessage.FromUnformatted("Cannot read a field off of a null input.");
|
||||
}
|
||||
|
||||
public string? Expression { get; set; }
|
||||
public Vector2i? IssueSpan { get; set; }
|
||||
public StackTrace? Trace { get; set; }
|
||||
}
|
||||
|
||||
public sealed class NoSuchFieldError(Type type, string field) : IConError
|
||||
{
|
||||
public FormattedMessage DescribeInner()
|
||||
{
|
||||
return FormattedMessage.FromUnformatted($"Type {type.Name} has no readable field or property named '{field}'. It must be exposed via [ViewVariables], [DataField], or [IncludeDataField].");
|
||||
}
|
||||
|
||||
public string? Expression { get; set; }
|
||||
public Vector2i? IssueSpan { get; set; }
|
||||
public StackTrace? Trace { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
using Content.Shared._Floof.OfferItem;
|
||||
|
||||
namespace Content.Server._Floof.OfferItem;
|
||||
|
||||
public sealed partial class OfferItemSystem : SharedOfferItemSystem;
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Server.GameObjects;
|
||||
using Content.Shared.Examine;
|
||||
using Robust.Server.Containers;
|
||||
using Content.Shared._Starlight;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared._Goobstation.Overlays;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server.Body.Components;
|
||||
using System.Linq;
|
||||
using Content.Shared._Goobstation.Flashbang;
|
||||
using Content.Shared._Starlight.Flash.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Flash; // Delta V - Flash Work
|
||||
|
||||
|
||||
namespace Content.Server._Starlight;
|
||||
|
||||
public sealed class ShadekinSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||
[Dependency] private readonly ContainerSystem _container = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
|
||||
[Dependency] private readonly SharedFlashSystem _flashSystem = default!;
|
||||
|
||||
private sealed class LightCone
|
||||
{
|
||||
public float Direction { get; set; }
|
||||
public float InnerWidth { get; set; }
|
||||
public float OuterWidth { get; set; }
|
||||
}
|
||||
private readonly Dictionary<string, List<LightCone>> lightMasks = new()
|
||||
{
|
||||
["/Textures/Effects/LightMasks/cone.png"] = new List<LightCone>
|
||||
{
|
||||
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 }
|
||||
},
|
||||
["/Textures/Effects/LightMasks/double_cone.png"] = new List<LightCone>
|
||||
{
|
||||
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 },
|
||||
new LightCone { Direction = 180, InnerWidth = 30, OuterWidth = 60 }
|
||||
}
|
||||
};
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ShadekinComponent, ComponentStartup>(OnInit);
|
||||
SubscribeLocalEvent<ShadekinComponent, EyeColorInitEvent>(OnEyeColorChange);
|
||||
SubscribeLocalEvent<ShadekinComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
||||
SubscribeLocalEvent<ShadekinComponent, AfterFlashedEvent>(OnShadekinFlashed); // Delta V - Prevent Chain Flashing
|
||||
SubscribeLocalEvent<ShadekinComponent, FlashDurationMultiplierEvent>(GetFlashModifier); // Delta V - Flash Modifier to Shadekin
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, ShadekinComponent component, ComponentStartup args)
|
||||
{
|
||||
UpdateAlert(uid, component, (short)component.CurrentState);
|
||||
RemComp<InternalsComponent>(uid);
|
||||
}
|
||||
|
||||
private void OnEyeColorChange(EntityUid uid, ShadekinComponent component, EyeColorInitEvent args)
|
||||
{
|
||||
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
||||
return;
|
||||
|
||||
// humanoid.EyeColor = Color.Black;
|
||||
Dirty(uid, humanoid);
|
||||
}
|
||||
|
||||
public void UpdateAlert(EntityUid uid, ShadekinComponent component, short state)
|
||||
{
|
||||
_alerts.ShowAlert(uid, component.ShadekinAlert, state);
|
||||
}
|
||||
|
||||
private Angle GetAngle(EntityUid lightUid, SharedPointLightComponent lightComp, EntityUid targetUid)
|
||||
{
|
||||
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(lightUid);
|
||||
lightPos += lightRot.RotateVec(lightComp.Offset);
|
||||
|
||||
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetUid);
|
||||
|
||||
var mapDiff = targetPos - lightPos;
|
||||
|
||||
var oppositeMapDiff = (-lightRot).RotateVec(mapDiff);
|
||||
var angle = oppositeMapDiff.ToWorldAngle();
|
||||
|
||||
if (angle == double.NaN && _transform.ContainsEntity(targetUid, lightUid) || _transform.ContainsEntity(lightUid, targetUid))
|
||||
{
|
||||
angle = 0f;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an illumination float value with is how many "energy" of light is hitting our ent.
|
||||
/// WARNING: This function might be expensive, Avoid calling it too much and CACHE THE RESULT!
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <returns></returns>
|
||||
public float GetLightExposure(EntityUid uid)
|
||||
{
|
||||
var illumination = 0f;
|
||||
|
||||
var lightQuery = _lookup.GetEntitiesInRange<PointLightComponent>(Transform(uid).Coordinates, 20, LookupFlags.Uncontained);
|
||||
|
||||
foreach (var light in lightQuery)
|
||||
{
|
||||
if (!light.Comp.Enabled
|
||||
|| light.Comp.Radius < 1
|
||||
|| light.Comp.Energy <= 0)
|
||||
continue;
|
||||
|
||||
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(light);
|
||||
lightPos += lightRot.RotateVec(light.Comp.Offset);
|
||||
|
||||
if (!_examine.InRangeUnOccluded(light, uid, light.Comp.Radius, null))
|
||||
continue;
|
||||
|
||||
Transform(uid).Coordinates.TryDistance(EntityManager, Transform(light).Coordinates, out var dist);
|
||||
|
||||
var denom = dist / light.Comp.Radius;
|
||||
var attenuation = 1 - (denom * denom);
|
||||
var calculatedLight = 0f;
|
||||
|
||||
if (light.Comp.MaskPath is not null)
|
||||
{
|
||||
var angleToTarget = GetAngle(light, light.Comp, uid);
|
||||
foreach (var cone in lightMasks[light.Comp.MaskPath])
|
||||
{
|
||||
var coneLight = 0f;
|
||||
var angleAttenuation = (float)Math.Min((float)Math.Max(cone.OuterWidth - angleToTarget, 0f), cone.InnerWidth) / cone.OuterWidth;
|
||||
|
||||
if (angleToTarget.Degrees - cone.Direction > cone.OuterWidth)
|
||||
continue;
|
||||
else if (angleToTarget.Degrees - cone.Direction > cone.InnerWidth
|
||||
&& angleToTarget.Degrees - cone.Direction < cone.OuterWidth)
|
||||
coneLight = light.Comp.Energy * attenuation * attenuation * angleAttenuation;
|
||||
else
|
||||
coneLight = light.Comp.Energy * attenuation * attenuation;
|
||||
|
||||
calculatedLight = Math.Max(calculatedLight, coneLight);
|
||||
}
|
||||
}
|
||||
else
|
||||
calculatedLight = light.Comp.Energy * attenuation * attenuation;
|
||||
|
||||
illumination += calculatedLight; //Math.Max(illumination, calculatedLight);
|
||||
}
|
||||
|
||||
return illumination;
|
||||
}
|
||||
|
||||
private void SetPassiveBuff(EntityUid uid, ShadekinState state)
|
||||
{
|
||||
if (!TryComp<PassiveDamageComponent>(uid, out var passive))
|
||||
return;
|
||||
|
||||
if (state == ShadekinState.Extreme || state == ShadekinState.Annoying || state == ShadekinState.High)
|
||||
{
|
||||
// passive.DamageCap = 1;
|
||||
}
|
||||
else if (state == ShadekinState.Low)
|
||||
{
|
||||
// passive.DamageCap = 20;
|
||||
passive.AllowedStates.Clear();
|
||||
passive.AllowedStates.Add(MobState.Alive);
|
||||
passive.Interval = 1f;
|
||||
}
|
||||
else if (state != ShadekinState.Dark)
|
||||
{
|
||||
// passive.DamageCap = 0;
|
||||
passive.AllowedStates.Clear();
|
||||
passive.AllowedStates.Add(MobState.Alive);
|
||||
passive.AllowedStates.Add(MobState.Critical);
|
||||
passive.AllowedStates.Add(MobState.Dead);
|
||||
passive.Interval = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleNightVision(EntityUid uid, ShadekinState state)
|
||||
{
|
||||
if (state == ShadekinState.Dark)
|
||||
{
|
||||
var nightVisionComponent = EnsureComp<NightVisionComponent>(uid);
|
||||
nightVisionComponent.Color = Color.FromHex("#808080"); // Delta V - Change Night Vision Color
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryComp<NightVisionComponent>(uid, out var nightVision) && nightVision.IsActive)
|
||||
_flashSystem.Flash(uid, uid, uid, TimeSpan.FromSeconds(0.5 * (int)state), 0.5f);
|
||||
RemComp<NightVisionComponent>(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyLightDamage(EntityUid uid, float dmg)
|
||||
{
|
||||
var damage = new DamageSpecifier();
|
||||
damage.DamageDict.Add("Heat", dmg);
|
||||
_damageable.TryChangeDamage(uid, damage, true, false);
|
||||
|
||||
}
|
||||
|
||||
private void OnRefreshMovementSpeedModifiers(EntityUid uid, ShadekinComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
if (component.CurrentState == ShadekinState.Low || component.CurrentState == ShadekinState.Annoying ||
|
||||
component.CurrentState == ShadekinState.Dark || component.CurrentState == ShadekinState.Invalid)
|
||||
return;
|
||||
|
||||
if (!TryComp<MovementSpeedModifierComponent>(uid, out var movement))
|
||||
return;
|
||||
|
||||
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
|
||||
args.ModifySpeed(1f, sprintDif);
|
||||
}
|
||||
|
||||
private ShadekinState GetStateByThreshold(ShadekinComponent component, float lightExposure)
|
||||
{
|
||||
var returnState = ShadekinState.Dark;
|
||||
|
||||
foreach (var (threshold, shadekinState) in component.Thresholds.Reverse())
|
||||
{
|
||||
if (threshold <= lightExposure)
|
||||
{
|
||||
returnState = shadekinState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnState;
|
||||
}
|
||||
|
||||
// Delta V - Begin Shadekin Flash Changes
|
||||
private void GetFlashModifier(EntityUid uid, ShadekinComponent comp, FlashDurationMultiplierEvent args)
|
||||
{
|
||||
if (!TryComp<FlashModifierComponent>(uid, out var flashModifier))
|
||||
return;
|
||||
|
||||
args.Multiplier = flashModifier.Modifier;
|
||||
}
|
||||
|
||||
private void OnShadekinFlashed(EntityUid uid, ShadekinComponent comp, AfterFlashedEvent ev)
|
||||
{
|
||||
RemComp<NightVisionComponent>(uid);
|
||||
}
|
||||
// Delta V - End
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ShadekinComponent>();
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
{
|
||||
if (_timing.CurTime < component.NextUpdate)
|
||||
continue;
|
||||
|
||||
component.NextUpdate = _timing.CurTime + component.UpdateCooldown;
|
||||
|
||||
var lightExposure = 0f;
|
||||
|
||||
if (!_container.IsEntityInContainer(uid))
|
||||
lightExposure = GetLightExposure(uid);
|
||||
|
||||
component.CurrentState = GetStateByThreshold(component, lightExposure);
|
||||
|
||||
UpdateAlert(uid, component, (short)component.CurrentState);
|
||||
|
||||
SetPassiveBuff(uid, component.CurrentState);
|
||||
ToggleNightVision(uid, component.CurrentState);
|
||||
|
||||
_speed.RefreshMovementSpeedModifiers(uid);
|
||||
|
||||
if (component.CurrentState == ShadekinState.Extreme)
|
||||
ApplyLightDamage(uid, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -392,7 +392,6 @@ public abstract partial class SharedBuckleSystem
|
|||
if (TryComp<PhysicsComponent>(buckle, out var physics))
|
||||
_physics.ResetDynamics(buckle, physics);
|
||||
|
||||
// TOOD: DV - This fails when you try to buckle the entity you're carrying to something. Figure out why later.
|
||||
DebugTools.AssertEqual(xform.ParentUid, strap.Owner);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,18 @@ public readonly partial record struct CargoBountyData
|
|||
Bounty = bounty.ID;
|
||||
Id = $"{bounty.IdPrefix}{uniqueIdentifier:D3}";
|
||||
}
|
||||
}
|
||||
// Begin DeltaV bounty claiming
|
||||
[DataField]
|
||||
public string ClaimedBy { get; init; } = string.Empty;
|
||||
|
||||
[DataField]
|
||||
public CargoBountyStatus Status { get; init; } = CargoBountyStatus.Undelivered;
|
||||
}
|
||||
|
||||
public enum CargoBountyStatus
|
||||
{
|
||||
Undelivered,
|
||||
Waiting,
|
||||
OnShuttle,
|
||||
} // End DeltaV bounty claiming
|
||||
|
||||
|
|
|
|||
|
|
@ -94,3 +94,4 @@ public sealed class BountySkipMessage : BoundUserInterfaceMessage
|
|||
BountyId = bountyId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ using System.Linq;
|
|||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared._Starlight.Flash.Components; // Delta V - For Flash Duration
|
||||
|
||||
namespace Content.Shared.Flash;
|
||||
|
||||
|
|
@ -173,7 +174,7 @@ public abstract class SharedFlashSystem : EntitySystem
|
|||
// Goobstation end
|
||||
|
||||
// don't paralyze, slowdown or convert to rev if the target is immune to flashes
|
||||
if (!_statusEffectsSystem.TryAddStatusEffect<FlashedComponent>(target, FlashedKey, flashDuration, true) && !ignoreProtection) //DeltaV: allow flashing to ignore flash protection
|
||||
if (!_statusEffectsSystem.TryAddStatusEffect<FlashedComponent>(target, FlashedKey, flashDuration * multiplier, true) && !ignoreProtection) //DeltaV: allow flashing to ignore flash protection. Added Flashduration Multiplier
|
||||
return;
|
||||
|
||||
if (stunDuration != null)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ using Content.Shared.Armor; // DeltaV - Addition of HandHeldArmor
|
|||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.Cuffs;
|
||||
using Content.Shared.Damage; // DeltaV End - Addition of HandHeldArmor
|
||||
using Content.Shared.Damage.Systems; // DeltaV End - Addition of HandHeldArmor
|
||||
using Content.Shared.Damage.Systems; // DeltaV - Addition of HandHeldArmor
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Projectiles;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ namespace Content.Shared.Input
|
|||
public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI";
|
||||
public static readonly BoundKeyFunction ToggleFullscreen = "ToggleFullscreen";
|
||||
public static readonly BoundKeyFunction Point = "Point";
|
||||
public static readonly BoundKeyFunction OfferItem = "OfferItem"; // Floofstation
|
||||
public static readonly BoundKeyFunction ZoomOut = "ZoomOut";
|
||||
public static readonly BoundKeyFunction ZoomIn = "ZoomIn";
|
||||
public static readonly BoundKeyFunction ResetZoom = "ResetZoom";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Content.Shared._DV.Overlays;
|
||||
using Content.Shared._DV.Overlays; // DeltaV
|
||||
using Content.Shared._DV.Psionics.Events; // DeltaV
|
||||
using Content.Shared.Armor;
|
||||
using Content.Shared.Atmos;
|
||||
|
|
@ -85,13 +85,15 @@ public partial class InventorySystem
|
|||
SubscribeLocalEvent<InventoryComponent, WieldAttemptEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, UnwieldAttemptEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, IngestionAttemptEvent>(RefRelayInventoryEvent);
|
||||
// DeltaV Start - Psionic Events
|
||||
// DeltaV Start
|
||||
// Psionic Events
|
||||
SubscribeLocalEvent<InventoryComponent, DispelledEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, PsionicPowerUseAttemptEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, TargetedByPsionicPowerEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, NoosphericFryEvent>(RefRelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, WeightlessnessChangedEvent>(RefRelayInventoryEvent); // Heavy Clothing
|
||||
// DeltaV End - Psionic Events
|
||||
// Heavy Clothing
|
||||
SubscribeLocalEvent<InventoryComponent, WeightlessnessChangedEvent>(RefRelayInventoryEvent);
|
||||
// DeltaV End
|
||||
|
||||
// Eye/vision events
|
||||
SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,22 @@ public abstract class SharedItemSystem : EntitySystem
|
|||
VisualsChanged(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - clear item visuals
|
||||
/// </summary>
|
||||
public void ClearVisuals(Entity<ItemComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
ent.Comp.RsiPath = null;
|
||||
ent.Comp.InhandVisuals = new();
|
||||
ent.Comp.HeldPrefix = null;
|
||||
|
||||
Dirty(ent, ent.Comp);
|
||||
VisualsChanged(ent.Owner);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHandEvent args)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared._ST.Interaction; // Stellar - interaction particles
|
||||
using Content.Shared._Floof.OfferItem; // Floof
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Alert;
|
||||
|
|
@ -117,10 +118,11 @@ public sealed class PullingSystem : EntitySystem
|
|||
if (TryComp(args.PullerUid, out PullerComponent? pullerComp) && !pullerComp.NeedsHands)
|
||||
return;
|
||||
|
||||
if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid))
|
||||
if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid, out var virt)) // Floofstation - store item
|
||||
{
|
||||
DebugTools.Assert("Unable to find available hand when starting pulling??");
|
||||
}
|
||||
EnsureComp<OfferableVirtualItemComponent>(virt.Value); // Floofstation - add a special component to allow offering it
|
||||
}
|
||||
|
||||
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
using Content.Shared.Actions;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Item.PseudoItem;
|
||||
|
|
@ -24,7 +23,8 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!; // Floofstation
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!; // Floofstation
|
||||
|
||||
private readonly ProtoId<TagPrototype> PreventTag = "PreventLabel";
|
||||
private readonly EntProtoId SleepActionId = "ActionSleep"; // The action used for sleeping inside bags. Currently uses the default sleep action (same as beds)
|
||||
|
|
@ -116,17 +116,35 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||
protected virtual void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component,
|
||||
GettingPickedUpAttemptEvent args)
|
||||
{
|
||||
if (args.User == args.Item)
|
||||
return;
|
||||
args.Cancel(); // Floof - this is a terrible idea. This triggers every time ANY system checks if a pseudo-item can be picked up.
|
||||
// WHY DID YOU DO THAT, NYANOTRASEN???
|
||||
|
||||
_transform.AttachToGridOrMap(uid);
|
||||
args.Cancel();
|
||||
// if (args.User == args.Item)
|
||||
// return;
|
||||
//
|
||||
// _transform.AttachToGridOrMap(uid);
|
||||
// args.Cancel();
|
||||
}
|
||||
|
||||
private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAttemptEvent args)
|
||||
{
|
||||
if (component.Active)
|
||||
args.Cancel();
|
||||
if (!component.Active)
|
||||
return;
|
||||
|
||||
// Floof - we try to get the containing container and try to drop it into it
|
||||
// If possible, we do it, since a bagged cat probably can put things back into the bag just like they can pick them up.
|
||||
string? failReason = null;
|
||||
if (_hands.GetActiveItem(uid) is { Valid: true, } droppedItem
|
||||
&& _container.TryGetContainingContainer(Transform(uid).ParentUid, uid, out var pseudoItemContainer)
|
||||
&& TryComp<StorageComponent>(pseudoItemContainer.Owner, out var targetStorage)
|
||||
&& _storage.CanInsert(pseudoItemContainer.Owner, droppedItem, out failReason, targetStorage, ignoreStacks: true)
|
||||
)
|
||||
_storage.Insert(pseudoItemContainer.Owner, droppedItem, out _, uid, targetStorage, stackAutomatically: false);
|
||||
|
||||
if (failReason != null)
|
||||
_popupSystem.PopupEntity(Loc.GetString(failReason), uid, uid);
|
||||
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
|
||||
|
|
@ -141,8 +159,9 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
|
|||
// Prevents moving within the bag :)
|
||||
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
|
||||
{
|
||||
if (args.Uid == args.Target && component.Active)
|
||||
args.Cancelled = true;
|
||||
// Floof - why the fuck.
|
||||
// if (args.Uid == args.Target && component.Active)
|
||||
// args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems; // DeltaV
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Doors.Components;
|
||||
|
|
@ -19,6 +20,7 @@ namespace Content.Shared.Remotes.EntitySystems;
|
|||
public abstract class SharedDoorRemoteSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAirlockSystem _airlock = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!; // DeltaV
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedDoorSystem _doorSystem = default!;
|
||||
[Dependency] private readonly SharedElectrocutionSystem _electrify = default!;
|
||||
|
|
@ -96,6 +98,19 @@ public abstract class SharedDoorRemoteSystem : EntitySystem
|
|||
else if (entity.Comp.RequireTagWhitelist)
|
||||
return;
|
||||
|
||||
// Begin DeltaV - Emergency access only bypasses open/close; bolting and toggling emergency access still require actual access.
|
||||
if (entity.Comp.Mode != OperatingMode.OpenClose
|
||||
&& accessComponent != null
|
||||
&& !_accessReader.IsAllowed(accessTarget, args.Target.Value, accessComponent))
|
||||
{
|
||||
if (isAirlock)
|
||||
_doorSystem.Deny(args.Target.Value, doorComp, user: args.User, predicted: true);
|
||||
|
||||
_popup.PopupClient(Loc.GetString("door-remote-denied"), args.User, args.User);
|
||||
return;
|
||||
}
|
||||
// End DeltaV
|
||||
|
||||
switch (entity.Comp.Mode)
|
||||
{
|
||||
case OperatingMode.OpenClose:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Content.Shared.Examine;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Stealth.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Timing;
|
||||
|
|
|
|||
|
|
@ -188,12 +188,20 @@ public abstract class SharedStorageSystem : EntitySystem
|
|||
return;
|
||||
}
|
||||
|
||||
// Begin DeltaV - the grid check excludes the item being resized because it's already in the storage which defeats the purpose so yoink it out to remove that
|
||||
storage.StoredItems.Remove(itemEnt.Owner);
|
||||
UpdateOccupied((container.Owner, storage));
|
||||
|
||||
if (!ItemFitsInGridLocation((itemEnt.Owner, itemEnt.Comp), (container.Owner, storage), loc))
|
||||
if (ItemFitsInGridLocation((itemEnt.Owner, itemEnt.Comp), (container.Owner, storage), loc))
|
||||
{
|
||||
storage.StoredItems.Add(itemEnt.Owner, loc);
|
||||
UpdateOccupied((container.Owner, storage));
|
||||
}
|
||||
else
|
||||
{
|
||||
ContainerSystem.Remove(itemEnt.Owner, container, force: true);
|
||||
}
|
||||
// End DeltaV - the grid check excludes the item being resized because it's already in the storage which defeats the purpose so yoink it out to remove that
|
||||
}
|
||||
|
||||
private void OnNestedStorageCvar(bool obj)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Content.Shared._DV.Body.Components;
|
||||
using Content.Shared._DV.Body.Events;
|
||||
using Content.Shared.Buckle;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
|
|
@ -13,6 +14,7 @@ public sealed class CPRSystem : EntitySystem
|
|||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -85,7 +87,7 @@ public sealed class CPRSystem : EntitySystem
|
|||
{
|
||||
Act = () => StartCPR(user, target, cprComp.TimeLength),
|
||||
Text = Loc.GetString("cpr-verb-start"),
|
||||
Priority = 2,
|
||||
Priority = _buckle.IsBuckled(target) ? 3 : 1, // Higher priority if they are buckled. Otherwise, this conflicts with trying to carry.
|
||||
Disabled = alreadyAffected,
|
||||
Message = alreadyAffected ? Loc.GetString("cpr-verb-disabled-description") : Loc.GetString("cpr-verb-description"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared._DV.Cargo.Components;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BountyClaimedMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string BountyId;
|
||||
|
||||
public BountyClaimedMessage(string bountyId)
|
||||
{
|
||||
BountyId = bountyId;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BountySetStatusMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string BountyId;
|
||||
public readonly int Status;
|
||||
|
||||
public BountySetStatusMessage(string bountyId, int status)
|
||||
{
|
||||
BountyId = bountyId;
|
||||
Status = status;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,9 @@ using Robust.Shared.Network;
|
|||
using Robust.Shared.Physics.Components;
|
||||
using System.Numerics;
|
||||
using Content.Shared._DV.Polymorph;
|
||||
using Content.Shared._Floof.OfferItem;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Buckle;
|
||||
|
||||
namespace Content.Shared._DV.Carrying;
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ public sealed class CarryingSystem : EntitySystem
|
|||
SubscribeLocalEvent<BeingCarriedComponent, GettingInteractedWithAttemptEvent>(OnInteractedWith);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, PullAttemptEvent>(OnPullAttempt);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, StartClimbEvent>(OnDrop);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, BuckledEvent>(OnDrop);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, BuckledEvent>(OnBuckle);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, UnbuckledEvent>(OnDrop);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, StrappedEvent>(OnDrop);
|
||||
SubscribeLocalEvent<BeingCarriedComponent, UnstrappedEvent>(OnDrop);
|
||||
|
|
@ -181,14 +183,15 @@ public sealed class CarryingSystem : EntitySystem
|
|||
/// </summary>
|
||||
private void OnInteractionAttempt(Entity<BeingCarriedComponent> ent, ref InteractionAttemptEvent args)
|
||||
{
|
||||
if (args.Target is not {} target)
|
||||
return;
|
||||
|
||||
var targetParent = Transform(target).ParentUid;
|
||||
|
||||
var carrier = ent.Comp.Carrier;
|
||||
if (target != carrier && targetParent != carrier && targetParent != ent.Owner)
|
||||
args.Cancelled = true;
|
||||
// Floofstation - no - this prevents the person from escaping and more.
|
||||
// if (args.Target is not {} target)
|
||||
// return;
|
||||
//
|
||||
// var targetParent = Transform(target).ParentUid;
|
||||
//
|
||||
// var carrier = ent.Comp.Carrier;
|
||||
// if (target != carrier && targetParent != carrier && targetParent != ent.Owner)
|
||||
// args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnMoveAttempt(Entity<BeingCarriedComponent> ent, ref UpdateCanMoveEvent args)
|
||||
|
|
@ -203,8 +206,9 @@ public sealed class CarryingSystem : EntitySystem
|
|||
|
||||
private void OnInteractedWith(Entity<BeingCarriedComponent> ent, ref GettingInteractedWithAttemptEvent args)
|
||||
{
|
||||
if (args.Uid != ent.Comp.Carrier)
|
||||
args.Cancelled = true;
|
||||
// Floofstation - why?
|
||||
// if (args.Uid != ent.Comp.Carrier)
|
||||
// args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnPullAttempt(Entity<BeingCarriedComponent> ent, ref PullAttemptEvent args)
|
||||
|
|
@ -217,6 +221,13 @@ public sealed class CarryingSystem : EntitySystem
|
|||
DropCarried(ent.Comp.Carrier, ent);
|
||||
}
|
||||
|
||||
private void OnBuckle(Entity<BeingCarriedComponent> ent, ref BuckledEvent args)
|
||||
{
|
||||
// Buckling to a bed already handles the reparenting to the entity that the carried
|
||||
// entity is buckled to, and then relays the BuckledEvent, so don't reparent to the grid.
|
||||
DropCarried(ent.Comp.Carrier, ent, attachToGrid: false);
|
||||
}
|
||||
|
||||
private void OnRemoved(Entity<BeingCarriedComponent> ent, ref ComponentRemove args)
|
||||
{
|
||||
/*
|
||||
|
|
@ -242,7 +253,8 @@ public sealed class CarryingSystem : EntitySystem
|
|||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void StartCarryDoAfter(EntityUid carrier, Entity<CarriableComponent> carried)
|
||||
// Floofstation - made public
|
||||
public void StartCarryDoAfter(EntityUid carrier, Entity<CarriableComponent> carried)
|
||||
{
|
||||
TimeSpan length = GetPickupDuration(carrier, carried);
|
||||
|
||||
|
|
@ -299,7 +311,8 @@ public sealed class CarryingSystem : EntitySystem
|
|||
|
||||
for (var x = 0; x < Comp<CarriableComponent>(carried).FreeHandsRequired; x++)
|
||||
{
|
||||
_virtualItem.TrySpawnVirtualItemInHand(carried, carrier);
|
||||
if (_virtualItem.TrySpawnVirtualItemInHand(carried, carrier, out var virtualItem))
|
||||
EnsureComp<OfferableVirtualItemComponent>(virtualItem.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,9 +335,9 @@ public sealed class CarryingSystem : EntitySystem
|
|||
return true;
|
||||
}
|
||||
|
||||
public void DropCarried(EntityUid carrier, EntityUid carried)
|
||||
public void DropCarried(EntityUid carrier, EntityUid carried, bool attachToGrid = true)
|
||||
{
|
||||
Drop(carried);
|
||||
Drop(carried, attachToGrid);
|
||||
CleanupCarrier(carrier, carried);
|
||||
}
|
||||
|
||||
|
|
@ -336,12 +349,15 @@ public sealed class CarryingSystem : EntitySystem
|
|||
_movementSpeed.RefreshMovementSpeedModifiers(carrier);
|
||||
}
|
||||
|
||||
private void Drop(EntityUid carried)
|
||||
private void Drop(EntityUid carried, bool attachToGrid = true)
|
||||
{
|
||||
RemComp<BeingCarriedComponent>(carried);
|
||||
RemComp<KnockedDownComponent>(carried); // TODO SHITMED: make sure this doesnt let you make someone with no legs walk
|
||||
_actionBlocker.UpdateCanMove(carried);
|
||||
_transform.AttachToGridOrMap(carried);
|
||||
|
||||
// Some systems will handle re-parenting and then throw an event, and this changes the parent when it should not
|
||||
if (attachToGrid)
|
||||
_transform.AttachToGridOrMap(carried);
|
||||
_standingState.Stand(carried);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
using Content.Shared.Item;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._DV.Forensics;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVExpandToInsertedItemSizeComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string ItemSlot;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<ItemSizePrototype> EmptySize;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using Content.Shared.Item;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Shared._DV.Forensics;
|
||||
|
||||
public sealed class DVExpandToInsertedItemSizeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVExpandToInsertedItemSizeComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
|
||||
SubscribeLocalEvent<DVExpandToInsertedItemSizeComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
|
||||
}
|
||||
|
||||
private void Refresh(Entity<DVExpandToInsertedItemSizeComponent> ent)
|
||||
{
|
||||
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||
if (slot.ContainedEntity is { } contained)
|
||||
{
|
||||
var item = Comp<ItemComponent>(contained);
|
||||
_item.SetSize(ent, item.Size);
|
||||
_item.SetShape(ent, item.Shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
_item.SetSize(ent, ent.Comp.EmptySize);
|
||||
_item.SetShape(ent, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemInserted(Entity<DVExpandToInsertedItemSizeComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (ent.Comp.ItemSlot != args.Container.ID)
|
||||
return;
|
||||
|
||||
Refresh(ent);
|
||||
}
|
||||
|
||||
private void OnItemRemoved(Entity<DVExpandToInsertedItemSizeComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (ent.Comp.ItemSlot != args.Container.ID)
|
||||
return;
|
||||
|
||||
Refresh(ent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._DV.Forensics;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVItemSlotVisualsComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string ItemSlot;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier FilledSprite;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier UnfilledSprite;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Forensics;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVSeenInsertedItemComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string ItemSlot;
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared._DV.Forensics;
|
||||
|
||||
public sealed class DVSeenInsertedItemSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly NameModifierSystem _nameModifier = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVSeenInsertedItemComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<DVSeenInsertedItemComponent, RefreshNameModifiersEvent>(OnRefreshModifiers);
|
||||
SubscribeLocalEvent<DVSeenInsertedItemComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
|
||||
SubscribeLocalEvent<DVSeenInsertedItemComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<DVSeenInsertedItemComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||
if (slot.ContainedEntity is { } contained)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("dv-seen-inserted-item-examined.full", ("container", Identity.Entity(ent, EntityManager, args.Examiner)), ("contained", contained)));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("dv-seen-inserted-item-examined.empty", ("container", Identity.Entity(ent, EntityManager, args.Examiner))));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRefreshModifiers(Entity<DVSeenInsertedItemComponent> ent, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||
if (slot.ContainedEntity is not { } contained)
|
||||
return;
|
||||
|
||||
args.AddModifier("dv-seen-inserted-item-name-modifier", extraArgs: ("contained", contained));
|
||||
}
|
||||
|
||||
private void Refresh(Entity<DVSeenInsertedItemComponent> ent)
|
||||
{
|
||||
_nameModifier.RefreshNameModifiers(ent.Owner);
|
||||
|
||||
var slot = _container.EnsureContainer<ContainerSlot>(ent, ent.Comp.ItemSlot);
|
||||
if (slot.ContainedEntity is { } contained)
|
||||
{
|
||||
var item = Comp<ItemComponent>(contained);
|
||||
_item.CopyVisuals(ent.Owner, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
_item.ClearVisuals(ent.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemInserted(Entity<DVSeenInsertedItemComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != ent.Comp.ItemSlot || _timing.ApplyingState)
|
||||
return;
|
||||
|
||||
Refresh(ent);
|
||||
}
|
||||
|
||||
private void OnItemRemoved(Entity<DVSeenInsertedItemComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != ent.Comp.ItemSlot || _timing.ApplyingState)
|
||||
return;
|
||||
|
||||
Refresh(ent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
using Content.Shared.Alert;
|
||||
|
||||
namespace Content.Shared._Floof.OfferItem;
|
||||
|
||||
public sealed partial class AcceptOfferAlertEvent : BaseAlertEvent;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
using Content.Shared.Alert;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._Floof.OfferItem;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[Access(typeof(SharedOfferItemSystem))]
|
||||
public sealed partial class OfferItemComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Apparently this indicates whether the entity is currently choosing an entity to offer (right after pressing F).
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
|
||||
public bool IsInOfferMode;
|
||||
|
||||
/// <summary>
|
||||
/// If this is true, then someone is currently offering an item to this entity, and <see cref="ReceivingFrom"/>
|
||||
/// stores the ID of that entity.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool IsInReceiveMode;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public string? Hand;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Item;
|
||||
|
||||
/// <summary>
|
||||
/// Floofstation note. So, this is EE shitcode, so prepare for an emotional rollercoaster.
|
||||
/// This field can mean TWO things. It's either the target entity this entity is offering an item to,
|
||||
/// or an entity that is offering an item to this entity.
|
||||
/// Whether it's one or the other is distinguished by <see cref="IsInReceiveMode"/>.<br/><br/>
|
||||
///
|
||||
/// In rare cases it can be both. According to my research, if entity A offers an item to entity B, and entity B offers to entity A,
|
||||
/// then both entities will end up in receive mode, and they will have each other as targets. There's a check preventing offer loops
|
||||
/// of length more than 2.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? ReceivingFrom;
|
||||
|
||||
[DataField]
|
||||
public float MaxOfferDistance = 2f;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> OfferAlert = "Offer";
|
||||
|
||||
public EntityUid GetRealEntity(EntityManager entityManager) =>
|
||||
entityManager.GetComponentOrNull<VirtualItemComponent>(Item)?.BlockingEntity ?? Item ?? EntityUid.Invalid;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._Floof.OfferItem;
|
||||
|
||||
/// <summary>
|
||||
/// A marker component that, when applied to a virtual item, allows it to be offered using item offering.
|
||||
/// Implementors have to listen on ItemTransferredEvent.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
public sealed partial class OfferableVirtualItemComponent : Component;
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared._Floof.OfferItem;
|
||||
|
||||
public abstract partial class SharedOfferItemSystem
|
||||
{
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
|
||||
private void InitializeInteractions()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.OfferItem, InputCmdHandler.FromDelegate(SetInOfferMode, handle: false, outsidePrediction: false))
|
||||
.Register<SharedOfferItemSystem>();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
CommandBinds.Unregister<SharedOfferItemSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This sets IsInOfferMode to true, allowing the player to select whom to offer an item to with interaction.
|
||||
/// </summary>
|
||||
private void SetInOfferMode(ICommonSession? offerer)
|
||||
{
|
||||
if (offerer is not { } playerSession)
|
||||
return;
|
||||
|
||||
if (playerSession.AttachedEntity is not { Valid: true } uid)
|
||||
return;
|
||||
|
||||
if (!Exists(uid))
|
||||
return;
|
||||
|
||||
if (!_actionBlocker.CanInteract(uid, null))
|
||||
return;
|
||||
|
||||
if (!TryComp<OfferItemComponent>(uid, out var offerItem))
|
||||
return;
|
||||
|
||||
if (!TryComp<HandsComponent>(uid, out var hands))
|
||||
return;
|
||||
|
||||
if (_hands.GetActiveHand((uid, hands)) is not { } activeHandName)
|
||||
return;
|
||||
|
||||
if (!_hands.TryGetHeldItem((uid, hands), activeHandName, out var heldItem))
|
||||
return;
|
||||
|
||||
offerItem.Item = heldItem;
|
||||
if (!offerItem.IsInOfferMode)
|
||||
{
|
||||
if (offerItem.Item == null)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("offer-item-empty-hand"), uid, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offerItem.Hand == null || offerItem.ReceivingFrom == null)
|
||||
{
|
||||
offerItem.IsInOfferMode = true;
|
||||
offerItem.Hand = activeHandName;
|
||||
|
||||
Dirty(uid, offerItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're already offering an item to someone, cancel that offer
|
||||
if (offerItem.ReceivingFrom != null)
|
||||
{
|
||||
UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
|
||||
offerItem.IsInOfferMode = false;
|
||||
Dirty(uid, offerItem);
|
||||
return;
|
||||
}
|
||||
|
||||
UnOffer(uid, offerItem);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
using Content.Shared._DV.Carrying;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
// Dear contributor.
|
||||
// This system is fucking unmaintainable.
|
||||
// If you ever happen to touch this again, please do your best to document your changes and try to resolve mysteries surrounding this code.
|
||||
// I did what I could to document the parts I managed to understand, but there is still more truth to be unveiled.
|
||||
//
|
||||
// HOURS_WASTED_HERE_FLOOFSTATION = 10
|
||||
// HOURS_WASTED_HERE_DELTAV = 1
|
||||
|
||||
namespace Content.Shared._Floof.OfferItem;
|
||||
|
||||
public abstract partial class SharedOfferItemSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly CarryingSystem _carrying = default!;
|
||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<OfferItemComponent, AcceptOfferAlertEvent>(OnAcceptOffer);
|
||||
SubscribeLocalEvent<OfferItemComponent, InteractUsingEvent>(OnInteractWithReceiver, before: [typeof(IngestionSystem)]);
|
||||
SubscribeLocalEvent<OfferableVirtualItemComponent, BeforeRangedInteractEvent>(OnRangedInteractWithReceiver);
|
||||
SubscribeLocalEvent<OfferItemComponent, MoveEvent>(OnMove);
|
||||
|
||||
SubscribeLocalEvent<BeingCarriedComponent, ItemTransferredEvent>(OnCarryTransfer);
|
||||
SubscribeLocalEvent<PullableComponent, ItemTransferredEvent>(OnPulledTransfer);
|
||||
|
||||
InitializeInteractions();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<OfferItemComponent, HandsComponent>();
|
||||
while (query.MoveNext(out var uid, out var offerItem, out var hands))
|
||||
{
|
||||
// If the mob no longer holds an item in the original offering hand, clear offering mode
|
||||
if (offerItem.Hand != null && !_hands.TryGetHeldItem((uid, hands), offerItem.Hand, out _))
|
||||
{
|
||||
if (offerItem.ReceivingFrom != null)
|
||||
{
|
||||
UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
|
||||
offerItem.IsInOfferMode = false;
|
||||
Dirty(uid, offerItem);
|
||||
}
|
||||
else
|
||||
UnOffer(uid, offerItem);
|
||||
}
|
||||
|
||||
if (!offerItem.IsInReceiveMode)
|
||||
{
|
||||
_alertsSystem.ClearAlert(uid, offerItem.OfferAlert);
|
||||
continue;
|
||||
}
|
||||
|
||||
_alertsSystem.ShowAlert(uid, offerItem.OfferAlert);
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
private void OnAcceptOffer(Entity<OfferItemComponent> ent, ref AcceptOfferAlertEvent args)
|
||||
{
|
||||
Receive((ent, ent.Comp));
|
||||
}
|
||||
|
||||
private void OnInteractWithReceiver(Entity<OfferItemComponent> receiver, ref InteractUsingEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted || _timing.ApplyingState || args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<OfferItemComponent>(args.User, out var offererComponent))
|
||||
return;
|
||||
|
||||
args.Handled = CreateOffer(receiver, (args.User, offererComponent));
|
||||
}
|
||||
|
||||
private void OnRangedInteractWithReceiver(Entity<OfferableVirtualItemComponent> virtItem, ref BeforeRangedInteractEvent args)
|
||||
{
|
||||
// If the entity being offered is a virtual item, InteractUsing will not be raised
|
||||
// because virtual items exclude themselves from being marked as used
|
||||
// If this is the case, InteractHand will be raised instead, which we can use anyway because OfferItem.Item stores the offered item
|
||||
//
|
||||
// We also can't check Handled here because VirtualItemSystem handles it, ffs
|
||||
// This won't lead you to accidentally offering someone your gun
|
||||
//
|
||||
// This is shitcode, this time my shitcode. My changes to the offering system allow you to transfer carrying and pulling,
|
||||
// but in order to handle these, we need to be able to intercept interactions with virtual items.
|
||||
//
|
||||
// Ideally this code should be rewritten to:
|
||||
// a) Have each different virtual item have a distinct component (e.g. CarryingVirtualItem) which would allow to distinguish them from the rest
|
||||
// b) Not rely on the InteractionSystem.
|
||||
// However, I'm not in the mood to do either. And I'm too deep into the rabbit hole of getting this shit to work.
|
||||
if (!_timing.IsFirstTimePredicted || _timing.ApplyingState)
|
||||
return;
|
||||
|
||||
var receiver = args.Target;
|
||||
if (!TryComp<OfferItemComponent>(receiver, out var receiverComponent))
|
||||
return;
|
||||
|
||||
var offerer = args.User;
|
||||
if (!TryComp<OfferItemComponent>(offerer, out var offererComponent) || offererComponent.Item == null)
|
||||
return;
|
||||
|
||||
// Since this is ranged, we must also check distance, because the interaction system wont check it for us in this case
|
||||
if (!Transform(offerer).Coordinates.TryDistance(EntityManager, _transform, Transform(receiver.Value).Coordinates, out var dst)
|
||||
|| dst > offererComponent.MaxOfferDistance)
|
||||
return;
|
||||
|
||||
args.Handled = CreateOffer((receiver.Value, receiverComponent), (offerer, offererComponent));
|
||||
}
|
||||
|
||||
private void OnMove(EntityUid uid, OfferItemComponent component, MoveEvent args)
|
||||
{
|
||||
if (_net.IsClient) // Client often mispredicts movement, we cant trust it here
|
||||
return;
|
||||
|
||||
if (component.ReceivingFrom == null)
|
||||
return;
|
||||
|
||||
if (_transform.InRange(args.NewPosition, Transform(component.ReceivingFrom.Value).Coordinates, component.MaxOfferDistance))
|
||||
return;
|
||||
|
||||
UnOffer(uid, component);
|
||||
}
|
||||
|
||||
private void OnCarryTransfer(Entity<BeingCarriedComponent> ent, ref ItemTransferredEvent args)
|
||||
{
|
||||
if (args.Handled
|
||||
|| args.PassedItem == args.RealItem // Means the entity is transferred NOT via carrying
|
||||
|| args.RealItem is not { Valid: true } carried
|
||||
|| ent.Comp.Carrier is not { Valid: true } oldCarrier)
|
||||
return;
|
||||
|
||||
_carrying.DropCarried(oldCarrier, ent);
|
||||
args.Handled = _carrying.TryCarry(args.Target, carried);
|
||||
}
|
||||
|
||||
private void OnPulledTransfer(Entity<PullableComponent> ent, ref ItemTransferredEvent args)
|
||||
{
|
||||
if (args.Handled
|
||||
|| args.PassedItem == args.RealItem // Means the entity is transferred NOT via pulling
|
||||
|| args.RealItem is not { Valid: true } pulled)
|
||||
return;
|
||||
|
||||
_pulling.TryStopPull(pulled, ent);
|
||||
args.Handled = _pulling.TryStartPull(args.Target, ent, null, ent.Comp);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Offering / Recieving
|
||||
/// <summary>
|
||||
/// Attempts to create an offer. Expects offerer.Item to already be set to the offered item, offererComponent.InReceiveMode == true.
|
||||
/// Will fail if offerer == receiver or if receiver already has a set TargetOrOfferer, and that person is not the current offerer
|
||||
/// </summary>
|
||||
private bool CreateOffer(Entity<OfferItemComponent> receiver, Entity<OfferItemComponent> offerer)
|
||||
{
|
||||
var offererComponent = offerer.Comp;
|
||||
var receiverComponent = receiver.Comp;
|
||||
if (offerer == receiver || receiverComponent.IsInReceiveMode || !offererComponent.IsInOfferMode)
|
||||
return false;
|
||||
|
||||
if (offererComponent.IsInReceiveMode && offererComponent.ReceivingFrom != receiver)
|
||||
return false;
|
||||
|
||||
receiverComponent.IsInReceiveMode = true;
|
||||
receiverComponent.ReceivingFrom = offerer;
|
||||
|
||||
Dirty(receiver, receiverComponent);
|
||||
|
||||
offererComponent.ReceivingFrom = receiver; // TODO this is ee shitcode, may not be necessary?
|
||||
offererComponent.IsInOfferMode = false;
|
||||
|
||||
Dirty(offerer, offererComponent);
|
||||
|
||||
if (offererComponent.Item == null)
|
||||
return false;
|
||||
|
||||
// Sender popup (client-side only)
|
||||
_popup.PopupClient(
|
||||
Loc.GetString("offer-item-try-give",
|
||||
("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager)),
|
||||
("target", Identity.Entity(receiver, EntityManager))),
|
||||
offerer,
|
||||
offerer);
|
||||
// Receiver popup (server side only, not predicted because recipient != local player)
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-try-give-target",
|
||||
("user", Identity.Entity(receiverComponent.ReceivingFrom.Value, EntityManager)),
|
||||
("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager))),
|
||||
offerer,
|
||||
receiver,
|
||||
Popups.PopupType.Medium);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets the <see cref="OfferItemComponent"/> of the user and the target
|
||||
/// </summary>
|
||||
protected void UnOffer(EntityUid thisEntity, OfferItemComponent offererComp)
|
||||
{
|
||||
if (!TryComp<HandsComponent>(thisEntity, out var hands) || _hands.GetActiveHand((thisEntity, hands)) is null)
|
||||
return;
|
||||
|
||||
if (offererComp.ReceivingFrom is { } otherEntity && TryComp<OfferItemComponent>(otherEntity, out var otherOfferer))
|
||||
{
|
||||
// So this tries to figure out which of these entities do what...
|
||||
// if A.OfferItemComponent.Item != null, then A is currently offering an item to A.OfferItemComponent.TargetOrOfferer
|
||||
// If it is null, then it is ONLY being offered an item TO.
|
||||
if (offererComp.Item != null && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-no-give",
|
||||
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||
("target", Identity.Entity(otherEntity, EntityManager))),
|
||||
thisEntity,
|
||||
thisEntity);
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-no-give-target",
|
||||
("user", Identity.Entity(thisEntity, EntityManager)),
|
||||
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
|
||||
thisEntity,
|
||||
otherEntity);
|
||||
}
|
||||
|
||||
else if (otherOfferer.Item != null && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-no-give",
|
||||
("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||
("target", Identity.Entity(thisEntity, EntityManager))),
|
||||
otherEntity,
|
||||
otherEntity);
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-no-give-target",
|
||||
("user", Identity.Entity(otherEntity, EntityManager)),
|
||||
("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager))),
|
||||
otherEntity,
|
||||
thisEntity);
|
||||
}
|
||||
|
||||
otherOfferer.IsInOfferMode = false;
|
||||
otherOfferer.IsInReceiveMode = false;
|
||||
otherOfferer.Hand = null;
|
||||
otherOfferer.ReceivingFrom = null;
|
||||
otherOfferer.Item = null;
|
||||
|
||||
Dirty(otherEntity, otherOfferer);
|
||||
}
|
||||
|
||||
offererComp.IsInOfferMode = false;
|
||||
offererComp.IsInReceiveMode = false;
|
||||
offererComp.Hand = null;
|
||||
offererComp.ReceivingFrom = null;
|
||||
offererComp.Item = null;
|
||||
|
||||
Dirty(thisEntity, offererComp);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the transfer of the item
|
||||
/// </summary>
|
||||
protected void UnReceive(EntityUid receiver, OfferItemComponent? receiverComp = null, OfferItemComponent? offererComp = null)
|
||||
{
|
||||
if (!Resolve(receiver, ref receiverComp)
|
||||
|| receiverComp.ReceivingFrom is not {} offerer
|
||||
|| !Resolve(offerer, ref offererComp))
|
||||
return;
|
||||
|
||||
// Idk why this check is here
|
||||
if (!TryComp<HandsComponent>(receiver, out var hands) || _hands.GetActiveHand((receiver, hands)) == null || receiverComp.ReceivingFrom == null)
|
||||
return;
|
||||
|
||||
// If offererComp.Item != null, then they are actively offering to TargetOrOfferer
|
||||
// Normally this method is called right after a transfer is done, but this part can be called from SetInOfferMode when the player presses F again to cancel an ongoing offer
|
||||
if (offererComp.Item != null)
|
||||
{
|
||||
_popup.PopupClient(
|
||||
Loc.GetString("offer-item-no-give",
|
||||
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
|
||||
("target", Identity.Entity(receiver, EntityManager))),
|
||||
offerer,
|
||||
offerer);
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-no-give-target",
|
||||
("user", Identity.Entity(receiverComp.ReceivingFrom.Value, EntityManager)), // Floof - resolve virtual items
|
||||
("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
|
||||
offerer,
|
||||
receiver);
|
||||
}
|
||||
|
||||
if (!offererComp.IsInReceiveMode)
|
||||
{
|
||||
offererComp.ReceivingFrom = null;
|
||||
receiverComp.ReceivingFrom = null;
|
||||
}
|
||||
|
||||
offererComp.Item = null;
|
||||
offererComp.Hand = null;
|
||||
receiverComp.IsInReceiveMode = false;
|
||||
|
||||
Dirty(receiver, receiverComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accepting the offer and receive item
|
||||
/// </summary>
|
||||
public void Receive(Entity<OfferItemComponent?> receiver)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (!Resolve(receiver, ref receiver.Comp))
|
||||
return;
|
||||
|
||||
if (!TryComp<OfferItemComponent>(receiver.Comp.ReceivingFrom, out var offererComponent) ||
|
||||
offererComponent.Hand == null ||
|
||||
receiver.Comp.ReceivingFrom is not {} sender ||
|
||||
!TryComp<HandsComponent>(receiver, out var hands))
|
||||
return;
|
||||
|
||||
if (offererComponent.Item != null)
|
||||
{
|
||||
// Floof - check if there's something else handling it first
|
||||
var realItem = offererComponent.GetRealEntity(EntityManager);
|
||||
if (!TryHandleExtendedTransfer(sender, receiver, offererComponent.Item.Value, realItem)
|
||||
&& !_hands.TryPickup(receiver, offererComponent.Item.Value, handsComp: hands))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("offer-item-full-hand"), receiver, receiver);
|
||||
return;
|
||||
}
|
||||
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-give",
|
||||
("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
|
||||
("target", Identity.Entity(receiver, EntityManager))),
|
||||
sender,
|
||||
sender);
|
||||
_popup.PopupEntity(
|
||||
Loc.GetString("offer-item-give-other",
|
||||
("user", Identity.Entity(receiver.Comp.ReceivingFrom.Value, EntityManager)),
|
||||
("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
|
||||
("target", Identity.Entity(receiver, EntityManager))),
|
||||
sender,
|
||||
Filter.PvsExcept(sender, entityManager: EntityManager),
|
||||
true);
|
||||
}
|
||||
|
||||
offererComponent.Item = null;
|
||||
UnReceive(receiver, receiver.Comp, offererComponent);
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Returns true if <see cref="OfferItemComponent.IsInOfferMode"/> = true
|
||||
/// </summary>
|
||||
protected bool IsInOfferMode(Entity<OfferItemComponent?> ent)
|
||||
{
|
||||
return Resolve(ent, ref ent.Comp, false) && ent.Comp.IsInOfferMode;
|
||||
}
|
||||
|
||||
private bool TryHandleExtendedTransfer(EntityUid user, EntityUid target, EntityUid offeredItem, EntityUid realItem)
|
||||
{
|
||||
var ev = new ItemTransferredEvent
|
||||
{
|
||||
User = user,
|
||||
Target = target,
|
||||
PassedItem = offeredItem,
|
||||
RealItem = realItem,
|
||||
};
|
||||
RaiseLocalEvent(realItem, ref ev);
|
||||
return ev.Handled;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the entity that was transferred via item offering.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class ItemTransferredEvent : HandledEntityEventArgs
|
||||
{
|
||||
public EntityUid User;
|
||||
public EntityUid Target;
|
||||
|
||||
/// <summary>
|
||||
/// The actual item being passed around. Can be a virtual item.
|
||||
/// </summary>
|
||||
public EntityUid PassedItem;
|
||||
/// <summary>
|
||||
/// If <see cref="PassedItem"/> is a virtual item, this field contains the real item that was transferred.
|
||||
/// </summary>
|
||||
public EntityUid? RealItem;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._Impstation.Clothing;
|
||||
|
||||
/// <summary>
|
||||
/// Adds examine text to the entity that wears item, for making things obvious.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(WearerGetsExamineTextSystem))]
|
||||
public sealed partial class WearerGetsExamineTextComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The LocId that specifies what category of object this is.
|
||||
/// i.e. "pin" or "scarf"
|
||||
/// Should be redefined on a per-category basis, naturally.
|
||||
/// </summary>
|
||||
[DataField("thing")]
|
||||
public LocId Category = "obvious-thing-default";
|
||||
|
||||
/// <summary>
|
||||
/// The LocId that specifies what member of the category this is.
|
||||
/// i.e. "lesbian pride"
|
||||
/// Can be used to define text colors that are copied to all things
|
||||
/// which share this specifier (i.e. the other items of the same pride).
|
||||
/// (And summarily, makes accessibility-based changes for these colors a cinch.)
|
||||
/// Should be defined by each thing that has this component.
|
||||
/// </summary>
|
||||
[DataField("thingType")]
|
||||
public LocId Specifier = "obvious-type-default";
|
||||
|
||||
/// <summary>
|
||||
/// The LocId that will be added to any wearing entity's examination.
|
||||
/// Typically only needs redefining on a per-category basis,
|
||||
/// but items that should have totally-unique obvious text can simply specify them here.
|
||||
/// </summary>
|
||||
[DataField("examineText", required: true)]
|
||||
public LocId ExamineOnWearer = "obvious-desc-default";
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the entity wearing this clothing.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Wearer;
|
||||
/// <summary>
|
||||
/// The string that is attached to this item's ExamineOnWearer.
|
||||
/// Typically doesn't need to be redefined.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId PrefixExamineOnWearer = "obvious-prefix-wearing";
|
||||
|
||||
/// <summary>
|
||||
/// If true, an entity with this item in any slot (i.e. in pockets) will gain the examine text,
|
||||
/// instead of when just equipped as clothing.
|
||||
/// Should be used sparingly only when truly appropriate; this is effectively a half-measure for lack of a special pin slot.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool PocketEvident;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the entity's description will inform examiners what others will see on the wearer (before they equip it).
|
||||
/// If the item is contraband, the item will also warn that displaying it may cause undue attention.
|
||||
/// Keep this false for good-natured jokes (i.e. the pride cloaks having funny, non-pride names)
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool WarnExamine = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Contraband;
|
||||
using Content.Shared._Impstation.Examine;
|
||||
using System.Text;
|
||||
|
||||
namespace Content.Shared._Impstation.Clothing;
|
||||
|
||||
/// <summary>
|
||||
/// Adds examine text to the entity that wears item, for making things obvious.
|
||||
/// </summary>
|
||||
public sealed class WearerGetsExamineTextSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<WearerGetsExamineTextComponent, GotEquippedEvent>(OnEquipped);
|
||||
SubscribeLocalEvent<WearerGetsExamineTextComponent, GotUnequippedEvent>(OnUnequipped);
|
||||
SubscribeLocalEvent<WearerGetsExamineTextComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnEquipped(Entity<WearerGetsExamineTextComponent> entity, ref GotEquippedEvent args)
|
||||
{
|
||||
if (!TryComp(entity, out ClothingComponent? clothing))
|
||||
return;
|
||||
var isCorrectSlot = (clothing.Slots & args.SlotFlags) != Inventory.SlotFlags.NONE;
|
||||
if (!entity.Comp.PocketEvident) //if it can't be evident in our pockets
|
||||
{
|
||||
// Make sure the clothing item was equipped to the right slot, and not just held in a hand.
|
||||
if (!isCorrectSlot)
|
||||
return;
|
||||
}
|
||||
|
||||
entity.Comp.Wearer = args.Equipee;
|
||||
Dirty(entity);
|
||||
|
||||
//GIVE THEM INSPECT TEXT
|
||||
var obviousExamine = EnsureComp<ExtraExamineTextComponent>(args.Equipee);
|
||||
obviousExamine.Lines.TryAdd(entity.Owner, //using try so that we don't cause an error if we move something from slot to slot
|
||||
ConstructExamineText(entity, !isCorrectSlot, args.Equipee));
|
||||
}
|
||||
|
||||
|
||||
private string ConstructExamineText(Entity<WearerGetsExamineTextComponent> entity, bool prefixFallback, EntityUid affecting)
|
||||
{
|
||||
//parameters (these are the same between both constructions)
|
||||
var user = Identity.Entity(affecting, EntityManager);
|
||||
var nomen = Identity.Name(affecting, EntityManager);
|
||||
var thing = Loc.GetString(entity.Comp.Category);
|
||||
var type = Loc.GetString(entity.Comp.Specifier);
|
||||
var stringSpec = entity.Comp.Specifier.ToString();
|
||||
var shortType = stringSpec.Substring(stringSpec.LastIndexOf('-')); // necessary for working with colored text...
|
||||
|
||||
var prefix = Loc.GetString(prefixFallback ? "obvious-prefix-default" : entity.Comp.PrefixExamineOnWearer, // uses a different prefix if worn / displayed
|
||||
("user", user),
|
||||
("name", nomen),
|
||||
("thing", thing),
|
||||
("type", type));
|
||||
var suffix = Loc.GetString(entity.Comp.ExamineOnWearer,
|
||||
("user", user),
|
||||
("name", nomen),
|
||||
("thing", thing),
|
||||
("type", type),
|
||||
("short-type", shortType));
|
||||
return prefix + " " + suffix;
|
||||
}
|
||||
|
||||
private void OnUnequipped(Entity<WearerGetsExamineTextComponent> entity, ref GotUnequippedEvent args)
|
||||
{
|
||||
if (entity.Comp.Wearer is not { } wearer)
|
||||
return;
|
||||
|
||||
if (TryComp(wearer, out ExtraExamineTextComponent? obviousExamine))
|
||||
{
|
||||
obviousExamine.Lines.Remove(entity.Owner);
|
||||
}
|
||||
|
||||
entity.Comp.Wearer = null;
|
||||
Dirty(entity);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<WearerGetsExamineTextComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
var currentlyWorn = entity.Comp.Wearer != null;
|
||||
var outString = new StringBuilder(Loc.GetString(currentlyWorn ? "obvious-on-item-currently" : "obvious-on-item",
|
||||
("used", Loc.GetString(entity.Comp.PocketEvident ? "obvious-reveal-pockets" : "obvious-reveal-default")),
|
||||
("thing", entity.Comp.Category),
|
||||
("me", Identity.Entity(entity, EntityManager))));
|
||||
|
||||
if (entity.Comp.WarnExamine)
|
||||
{
|
||||
if (!currentlyWorn && TryComp(entity, out ContrabandComponent? contra)) // if the item's contra and we're not wearing it yet
|
||||
{
|
||||
var contraLocId = "obvious-on-item-contra-" + contra.Severity; // apply additional text if the item is contraband to note that displaying it might be really bad
|
||||
if (Loc.HasString(contraLocId)) // saves us the trouble of making a switch block for this
|
||||
outString.Append(" " + Loc.GetString(contraLocId));
|
||||
}
|
||||
var affecting = currentlyWorn ? entity.Comp.Wearer.GetValueOrDefault() : args.Examiner;
|
||||
var testOut = ConstructExamineText(entity, false, affecting);
|
||||
|
||||
outString.Append("\n" + Loc.GetString("obvious-on-item-for-others",
|
||||
("will", currentlyWorn ? "can" : "will"), // i love hardcoding strings it's my favorite thing ever
|
||||
("output", testOut)));
|
||||
}
|
||||
|
||||
args.PushMarkup(outString.ToString());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._Impstation.Examine;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DetailedInspectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public LocId VerbText = "verbs-detailed-inspect";
|
||||
|
||||
[DataField]
|
||||
public LocId VerbMessage = "verbs-detailed-inspect-message";
|
||||
|
||||
[DataField(required: true)]
|
||||
public List<LocId> ExamineText;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the entries in ExamineText are separated by linebreaks.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool LineBreak = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the entries in ExamineText are preceded by ticks.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool TickEntries = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not entries in the list are numbered.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool NumberedEntries = false;
|
||||
|
||||
/// <summary>
|
||||
/// Rooted directory of the icon for the verb.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Icon = "/Textures/Interface/VerbIcons/dot.svg.192dpi.png";
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using Content.Shared.Examine;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._Impstation.Examine;
|
||||
|
||||
public sealed partial class DetailedInspectSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DetailedInspectComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerb);
|
||||
}
|
||||
|
||||
public void OnGetVerb(Entity<DetailedInspectComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess || !_net.IsServer)
|
||||
return;
|
||||
|
||||
var msg = new FormattedMessage();
|
||||
var numberedIndex = 1;
|
||||
|
||||
foreach (var locId in ent.Comp.ExamineText)
|
||||
{
|
||||
if (ent.Comp.TickEntries)
|
||||
msg.AddMarkupOrThrow("- ");
|
||||
|
||||
if (ent.Comp.NumberedEntries)
|
||||
{
|
||||
msg.AddMarkupOrThrow($"{numberedIndex}. ");
|
||||
numberedIndex++;
|
||||
}
|
||||
|
||||
msg.AddMarkupOrThrow(Loc.GetString(locId));
|
||||
|
||||
if (ent.Comp.LineBreak)
|
||||
msg.PushNewline();
|
||||
else
|
||||
msg.AddMarkupOrThrow(" ");
|
||||
}
|
||||
|
||||
|
||||
_examine.AddDetailedExamineVerb(args, ent.Comp, msg, Loc.GetString(ent.Comp.VerbText), ent.Comp.Icon, Loc.GetString(ent.Comp.VerbMessage));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using Robust.Shared.GameStates;
|
||||
using Content.Shared._Impstation.Clothing;
|
||||
|
||||
namespace Content.Shared._Impstation.Examine;
|
||||
|
||||
/// <summary>
|
||||
/// Adds examine text to the entity, intentionally "obvious details".
|
||||
/// Like, that's it. It's basic -- all it does is add the lines to the attached entity.
|
||||
/// This is particularly used for assigning players unique examine text.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(ExtraExamineTextSystem), typeof(WearerGetsExamineTextSystem))]
|
||||
public sealed partial class ExtraExamineTextComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The LocIds that will be added to the attached entity's examination.
|
||||
///
|
||||
/// The key is the source of the line, and the value is the text
|
||||
/// (built by the component that creates this one).
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<EntityUid, LocId> Lines { get; set; } = new();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
|
||||
namespace Content.Shared._Impstation.Examine;
|
||||
|
||||
/// <summary>
|
||||
/// Adds examine text to the entity, intentionally "obvious details".
|
||||
/// Like, that's it. It's basic -- all it does is add the line to the attached entity.
|
||||
/// This is particularly used for assigning players unique examine text.
|
||||
/// </summary>
|
||||
public sealed class ExtraExamineTextSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ExtraExamineTextComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<ExtraExamineTextComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if (entity.Comp.Lines.Count == 0)
|
||||
{
|
||||
RemCompDeferred<ExtraExamineTextComponent>(entity); // no more need for me!
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var l in entity.Comp.Lines)
|
||||
{
|
||||
args.PushMarkup(l.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Content.Shared._Starlight.Flash.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class FlashModifierComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float Modifier = 1f;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
namespace Content.Shared.Humanoid;
|
||||
|
||||
public static class EyeColor
|
||||
{
|
||||
public const float ShadekinBrightness = 0.251f;
|
||||
|
||||
public static bool VerifyShadekin(Color color)
|
||||
{
|
||||
var colorHsv = Color.ToHsv(color);
|
||||
|
||||
if (colorHsv.Z > ShadekinBrightness)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Color MakeShadekinValid(Color color)
|
||||
{
|
||||
var hsv = Color.ToHsv(color);
|
||||
|
||||
hsv.Z = Math.Clamp(hsv.Z, 0, ShadekinBrightness);
|
||||
|
||||
return Color.FromHsv(hsv);
|
||||
}
|
||||
|
||||
public static bool VerifyEyeColor(HumanoidEyeColor type, Color color)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
HumanoidEyeColor.Shadekin => VerifyShadekin(color),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public static Color ValidEyeColor(HumanoidEyeColor type, Color color)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
HumanoidEyeColor.Shadekin => MakeShadekinValid(color),
|
||||
_ => color
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum HumanoidEyeColor : byte
|
||||
{
|
||||
Shadekin,
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct EyeColorInitEvent();
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._Starlight;
|
||||
|
||||
#region Shadekin
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause, AutoGenerateComponentState]
|
||||
public sealed partial class ShadekinComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> ShadekinAlert = "Shadekin";
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly), AutoPausedField]
|
||||
public TimeSpan NextUpdate = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan UpdateCooldown = TimeSpan.FromSeconds(1f);
|
||||
|
||||
[AutoNetworkedField, ViewVariables]
|
||||
public ShadekinState CurrentState { get; set; } = ShadekinState.Dark;
|
||||
|
||||
[DataField("thresholds", required: true)]
|
||||
public SortedDictionary<FixedPoint2, ShadekinState> Thresholds = new();
|
||||
|
||||
/// <summary>
|
||||
/// whether to flicker lights or not. default on
|
||||
/// </summary>
|
||||
[DataField] public bool DoLightFlicker = true;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ShadekinState : byte
|
||||
{
|
||||
Invalid = 0,
|
||||
Dark = 1,
|
||||
Low = 2,
|
||||
Annoying = 3,
|
||||
High = 4,
|
||||
Extreme = 5
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
- files: ["wurble.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/wurble.ogg"
|
||||
|
||||
- files: ["mar.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/mar.ogg"
|
||||
|
||||
- files: ["scream_f1.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken and remixed from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f1.ogg"
|
||||
|
||||
- files: ["scream_f2.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken and remixed from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f2.ogg"
|
||||
|
||||
- files: ["scream_m1.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken and remixed from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_m1.ogg"
|
||||
|
||||
- files: ["scream_m2.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken and remixed from CHOMPStation"
|
||||
source: "https://github.com/CHOMPStation2/CHOMPStation2/blob/e846f4f73d14875a390ede039a11e4b9b699f420/sound/voice/scream_f2.ogg"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -348,5 +348,13 @@ Entries:
|
|||
id: 38
|
||||
time: '2026-07-19T16:18:47.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6317
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: '`entities` and a lot of other basic QUERY commare are now a DEBUG-level
|
||||
commands.'
|
||||
type: Tweak
|
||||
id: 39
|
||||
time: '2026-07-24T17:27:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6351
|
||||
Name: DeltaVAdmin
|
||||
Order: 5
|
||||
|
|
|
|||
|
|
@ -1,215 +1,4 @@
|
|||
Entries:
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Removed footprint prediction (for now)
|
||||
type: Remove
|
||||
id: 2074
|
||||
time: '2026-01-16T19:07:45.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5224
|
||||
- author: Velcroboy
|
||||
changes:
|
||||
- message: Prisoners can find dull bread knives in the ChefVend.
|
||||
type: Tweak
|
||||
id: 2075
|
||||
time: '2026-01-17T21:13:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5234
|
||||
- author: Halo3moth
|
||||
changes:
|
||||
- message: The T1 armored vest (slim) can now once again be picked in security loadouts.
|
||||
type: Add
|
||||
id: 2076
|
||||
time: '2026-01-17T21:36:45.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5220
|
||||
- author: biddygelson
|
||||
changes:
|
||||
- message: 'Academy: added anti-meteor zones and anti-anomaly zone, AI restoration
|
||||
console in Mystagogue, Robotics Console in robo, fishing hole added to park,
|
||||
materials is cargo at roundstart.'
|
||||
type: Add
|
||||
- message: 'Academy: station starts with distro and waste enabled, spare atmos chambers
|
||||
start as vacuums, split artifacts'' APCs for power management, botany has more
|
||||
trays and is slightly larger, department-front holopads in the department.'
|
||||
type: Tweak
|
||||
id: 2077
|
||||
time: '2026-01-18T01:54:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5130
|
||||
- author: DisposableCrewmember42
|
||||
changes:
|
||||
- message: You can no longer drink the deep fryer.
|
||||
type: Fix
|
||||
id: 2078
|
||||
time: '2026-01-18T04:40:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5238
|
||||
- author: snowywinters
|
||||
changes:
|
||||
- message: Reinforced cameras can now be built! They have additional HP and are
|
||||
more resistant to explosions and meteors.
|
||||
type: Add
|
||||
- message: The AI has its own section in the security cameras console.
|
||||
type: Add
|
||||
id: 2079
|
||||
time: '2026-01-18T17:18:45.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5027
|
||||
- author: Dorragon
|
||||
changes:
|
||||
- message: Ready Manifest added to the lobby
|
||||
type: Add
|
||||
id: 2080
|
||||
time: '2026-01-18T18:47:07.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5187
|
||||
- author: MilonPL
|
||||
changes:
|
||||
- message: Added a new traits system, supporting conditions and new effects. Make
|
||||
sure to check out the Traits tab in the character editor!
|
||||
type: Add
|
||||
- message: All character traits have been reset.
|
||||
type: Remove
|
||||
id: 2081
|
||||
time: '2026-01-20T11:49:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5208
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: You can now examine character descriptions from much further away.
|
||||
type: Tweak
|
||||
id: 2082
|
||||
time: '2026-01-20T11:49:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5219
|
||||
- author: Eternally-Confused
|
||||
changes:
|
||||
- message: (TEST MERGE) Space pens now contain a chemical called Stabilizine instead
|
||||
of Leporazine, which is better at stabilizing body temperature.
|
||||
type: Tweak
|
||||
- message: Avali no longer die from space pens.
|
||||
type: Tweak
|
||||
id: 2083
|
||||
time: '2026-01-20T21:15:21.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5181
|
||||
- author: turtlemutt
|
||||
changes:
|
||||
- message: Added more names for ghost role spawns.
|
||||
type: Add
|
||||
id: 2084
|
||||
time: '2026-01-21T05:17:05.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5254
|
||||
- author: Cepelinas1
|
||||
changes:
|
||||
- message: Logistics Officers can now use the shipyard to buy shuttles. No need
|
||||
to beg Captain to buy it anymore!
|
||||
type: Add
|
||||
id: 2085
|
||||
time: '2026-01-21T05:52:10.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5251
|
||||
- author: Colin-Tel
|
||||
changes:
|
||||
- message: Eked the Anglish tung tie. In other words, added a trait that lets you
|
||||
talk like an Anglo Saxon with over 1,100 word replacements.
|
||||
type: Add
|
||||
id: 2086
|
||||
time: '2026-01-21T09:37:07.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4092
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: The ninja is now revealed with hit with attacks, projectiles, explosions,
|
||||
and grenades that do damage.
|
||||
type: Tweak
|
||||
- message: The ninja is now revealed with hit with attacks, projectiles, explosions,
|
||||
and grenades that do damage.
|
||||
type: Fix
|
||||
id: 2087
|
||||
time: '2026-01-21T14:18:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5217
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: FTL times have been adjusted. Startup is shorter, travel is longer.
|
||||
type: Tweak
|
||||
- message: The FTL startup sound now lines up with the duration of startup again!!!
|
||||
type: Fix
|
||||
id: 2088
|
||||
time: '2026-01-21T14:50:49.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5257
|
||||
- author: ShepardToTheStars, foxcumberland
|
||||
changes:
|
||||
- message: Added fashionable longcoats for command, security, and crew. Find them
|
||||
in the loadouts for command, security, and passengers, or in the ClothesMate
|
||||
on station!
|
||||
type: Add
|
||||
id: 2089
|
||||
time: '2026-01-21T16:23:14.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5235
|
||||
- author: Apachito
|
||||
changes:
|
||||
- message: Made tide breaker actually craftable
|
||||
type: Fix
|
||||
id: 2090
|
||||
time: '2026-01-21T16:28:54.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5239
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Certain painkillers are more long-lasting than others, based on how strong
|
||||
they are.
|
||||
type: Tweak
|
||||
- message: Players with the chronic pain trait start with ~5 minutes of suppressed
|
||||
pain before they start feeling the effects.
|
||||
type: Tweak
|
||||
- message: Fixed chronic pain's effects from pulsing continuously.
|
||||
type: Fix
|
||||
id: 2091
|
||||
time: '2026-01-23T10:24:32.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5180
|
||||
- author: snowywinters
|
||||
changes:
|
||||
- message: Captain's armored winter coat a alternative to the carapace
|
||||
type: Add
|
||||
- message: Changed the defense of captain's EVA suit and carapace
|
||||
type: Tweak
|
||||
id: 2092
|
||||
time: '2026-01-23T19:31:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5227
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: Listening Post Operatives only have the ability to hear binary comms
|
||||
now. They can no longer talk on binary.
|
||||
type: Tweak
|
||||
id: 2093
|
||||
time: '2026-01-23T19:35:58.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5243
|
||||
- author: MilonPL
|
||||
changes:
|
||||
- message: The traits points bar will now show up correctly.
|
||||
type: Fix
|
||||
id: 2094
|
||||
time: '2026-01-24T20:55:31.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5275
|
||||
- author: MilonPL
|
||||
changes:
|
||||
- message: The uncloneable trait no longer prevents your character from getting
|
||||
revived by defibrillators.
|
||||
type: Fix
|
||||
id: 2095
|
||||
time: '2026-01-24T21:29:58.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5273
|
||||
- author: Halo3moth
|
||||
changes:
|
||||
- message: The energy magnums "magnum" rounds no longer pierce windows
|
||||
type: Fix
|
||||
id: 2096
|
||||
time: '2026-01-25T13:48:54.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5270
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Added buttons for build info and credits to the escape menu
|
||||
type: Tweak
|
||||
id: 2097
|
||||
time: '2026-01-25T14:42:09.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5260
|
||||
- author: MilonPL
|
||||
changes:
|
||||
- message: Added the "Marked as Protected" trait which makes you immune to becoming
|
||||
a target objective.
|
||||
type: Add
|
||||
id: 2098
|
||||
time: '2026-01-25T16:30:18.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5274
|
||||
- author: AeraAuling
|
||||
changes:
|
||||
- message: Shadow damage no longer removes all your blood immediately
|
||||
|
|
@ -4369,4 +4158,209 @@
|
|||
id: 2574
|
||||
time: '2026-07-20T00:24:43.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6310
|
||||
- author: kotobdev
|
||||
changes:
|
||||
- message: The Ardent Censer no longer requires fuel for deconversions.
|
||||
type: Tweak
|
||||
id: 2575
|
||||
time: '2026-07-20T17:38:51.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5016
|
||||
- author: Halo3rat, kotobdev
|
||||
changes:
|
||||
- message: The Freighter Crew's Jumpsuit is now available in the AutoDrobe, for
|
||||
those who value their dental hygiene.
|
||||
type: Add
|
||||
id: 2576
|
||||
time: '2026-07-20T20:06:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6331
|
||||
- author: Mnemotechnician, kotobdev, ShepardToTheStars
|
||||
changes:
|
||||
- message: You can now offer items to other players by pressing F, and then clicking
|
||||
on them! They can accept by clicking on the alert on the side of their screen.
|
||||
type: Add
|
||||
id: 2577
|
||||
time: '2026-07-20T20:13:58.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5597
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Glimmer probers can once again turn on and lock into place when glimmer
|
||||
is over 750.
|
||||
type: Add
|
||||
- message: Glimmer prober explosions are 1.5x bigger if glimmer is over 900. You
|
||||
better build drainers! :)
|
||||
type: Tweak
|
||||
- message: The oracle can now give normality crystals when completing her requests.
|
||||
type: Tweak
|
||||
id: 2578
|
||||
time: '2026-07-20T20:29:02.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6292
|
||||
- author: keekee38
|
||||
changes:
|
||||
- message: Added the novice mark, to help show that you're new! It is on intern
|
||||
roles by default, and optional for everyone
|
||||
type: Add
|
||||
- message: Some clothes now have examine text, in particular pride clothes.
|
||||
type: Tweak
|
||||
id: 2579
|
||||
time: '2026-07-20T22:08:57.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6118
|
||||
- author: Coryler
|
||||
changes:
|
||||
- message: Shadekin has arrived in the DeltaV sector.
|
||||
type: Add
|
||||
id: 2580
|
||||
time: '2026-07-20T22:10:50.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5481
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: The crew monitor now reports global coordinate positions.
|
||||
type: Tweak
|
||||
id: 2581
|
||||
time: '2026-07-20T22:20:12.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6326
|
||||
- author: keekee38
|
||||
changes:
|
||||
- message: Vulpkanins can yip now.
|
||||
type: Tweak
|
||||
id: 2582
|
||||
time: '2026-07-20T22:21:24.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6301
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: Improvised shotgun shells use the old upstream crafting recipe.
|
||||
type: Tweak
|
||||
- message: The improvised shotgun is craftable once again.
|
||||
type: Fix
|
||||
id: 2583
|
||||
time: '2026-07-20T22:22:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6327
|
||||
- author: kotobdev
|
||||
changes:
|
||||
- message: Security cold weather ponchos are gone from loadouts and the SecDrobe.
|
||||
type: Remove
|
||||
id: 2584
|
||||
time: '2026-07-20T22:44:01.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6332
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: Security now has access to evidence bags, for storing all the illegal
|
||||
things that can be stored.
|
||||
type: Add
|
||||
id: 2585
|
||||
time: '2026-07-20T23:17:53.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6280
|
||||
- author: jessiscah23
|
||||
changes:
|
||||
- message: Added organizational capabilities to the cargo bounty computer.
|
||||
type: Add
|
||||
id: 2586
|
||||
time: '2026-07-20T23:23:28.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6306
|
||||
- author: Proxysseia
|
||||
changes:
|
||||
- message: (TEST MERGE) Increased traitor starting telecrystal balance from 20 to
|
||||
30.
|
||||
type: Tweak
|
||||
id: 2587
|
||||
time: '2026-07-20T23:37:07.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6275
|
||||
- author: ArionGekkota
|
||||
changes:
|
||||
- message: reintroduced researchable PKA modkits
|
||||
type: Add
|
||||
- message: Changed the PKA to its current upstream state
|
||||
type: Tweak
|
||||
- message: Reduced the health of some salvage mobs
|
||||
type: Tweak
|
||||
id: 2588
|
||||
time: '2026-07-20T23:46:11.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6258
|
||||
- author: nlaky
|
||||
changes:
|
||||
- message: Fixed incorrect Vulpkanin mask sprites.
|
||||
type: Fix
|
||||
id: 2589
|
||||
time: '2026-07-21T00:05:09.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6201
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Vulps can yip properly now.
|
||||
type: Fix
|
||||
id: 2590
|
||||
time: '2026-07-21T02:20:30.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6354
|
||||
- author: Coryler
|
||||
changes:
|
||||
- message: Shadekin meds working on them
|
||||
type: Fix
|
||||
- message: Shadekin emotes being available to other species
|
||||
type: Fix
|
||||
id: 2591
|
||||
time: '2026-07-21T07:58:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6357
|
||||
- author: Coryler
|
||||
changes:
|
||||
- message: Add back Felinid root ability
|
||||
type: Add
|
||||
id: 2592
|
||||
time: '2026-07-21T18:44:49.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6358
|
||||
- author: EmberAstra
|
||||
changes:
|
||||
- message: Cosmic Cult's Entropic Blades are now smaller (2x4 spaces)
|
||||
type: Tweak
|
||||
id: 2593
|
||||
time: '2026-07-23T03:17:02.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6371
|
||||
- author: turtlemutt
|
||||
changes:
|
||||
- message: Gave Lighthouse new doorbells and pagers. Have fun harassing departments!
|
||||
type: Tweak
|
||||
id: 2594
|
||||
time: '2026-07-23T16:29:30.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6088
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: Buckling someone while they are being carried should work as intended
|
||||
now.
|
||||
type: Fix
|
||||
- message: Picking someone up that is criticla will have priority over CPR unless
|
||||
they are buckled to something.
|
||||
type: Tweak
|
||||
id: 2595
|
||||
time: '2026-07-23T20:07:04.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6375
|
||||
- author: ManuDemoen
|
||||
changes:
|
||||
- message: Emergency access no longer allows anyone with a remote to bolt the door
|
||||
and checks if the remote has access to bolt.
|
||||
type: Fix
|
||||
id: 2596
|
||||
time: '2026-07-24T17:28:01.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6141
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: Monkeys now make sounds when using emotes!
|
||||
type: Add
|
||||
id: 2597
|
||||
time: '2026-07-24T17:28:47.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5928
|
||||
- author: keekee38
|
||||
changes:
|
||||
- message: The WT550 once again fires at 5.5 rounds a second and has 30-round magazines.
|
||||
type: Tweak
|
||||
id: 2598
|
||||
time: '2026-07-24T17:34:48.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/6364
|
||||
- author: SirWarock
|
||||
changes:
|
||||
- message: The NT-3 cannot be parcel-wrapped anymore!
|
||||
type: Tweak
|
||||
- message: Adjusted the wielding sprites of the NT-3 to look less wrong.
|
||||
type: Fix
|
||||
- message: The NT-3 can pierce things again.
|
||||
type: Fix
|
||||
id: 2599
|
||||
time: '2026-07-24T17:39:18.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5653
|
||||
Order: 1
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -16,3 +16,6 @@ delta-chat-emote-name-harpysquish = Squish
|
|||
delta-chat-emote-name-quack = Quack
|
||||
delta-chat-emote-name-squawk = Squawk
|
||||
delta-chat-emote-name-horn = Horn
|
||||
delta-chat-emote-name-yip = Yip
|
||||
|
||||
delta-chat-emote-msg-yip = yips.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
dv-seen-inserted-item-name-modifier = {$baseName} with { INDEFINITE($contained) } { $contained }
|
||||
dv-seen-inserted-item-examined =
|
||||
.full = { CAPITALIZE(SUBJECT($container)) } has [color=paleturquoise]{ INDEFINITE($contained) } { $contained }[/color] in { SUBJECT($container) }.
|
||||
.empty = { CAPITALIZE(SUBJECT($container)) } has nothing in { SUBJECT($container) }.
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
# Ears
|
||||
marking-EarsShadekinMotley = Motley Ears
|
||||
marking-EarsShadekinMotley-shadowkin = Ears
|
||||
marking-EarsShadekinMotley-motley_secondary = Pattern
|
||||
marking-EarsShadekinShady = Dark Ears
|
||||
marking-EarsShadekinShady-shady = Ears
|
||||
marking-EarsShadekinStriped = Striped Ears
|
||||
marking-EarsShadowkinStriped-shadowkin = Ears
|
||||
marking-EarsShadowkinStriped-shadowkin_stripes = Stripes
|
||||
marking-EarsShadekinPiercingAll = Ears with Piercings
|
||||
marking-EarsShadekinPiercingAll-shadowkin = Ears
|
||||
marking-EarsShadekinPiercingAll-piercing_all = Piercings
|
||||
marking-EarsShadekinPiercingLeft = Ears with Piercing (L)
|
||||
marking-EarsShadekinPiercingLeft-shadowkin = Ears
|
||||
marking-EarsShadekinPiercingLeft-piercing_left = Piercing
|
||||
marking-EarsShadekinPiercingRight = Ears with Piercing (R)
|
||||
marking-EarsShadekinPiercingRight-shadowkin = Ears
|
||||
marking-EarsShadekinPiercingRight-piercing_right = Piercing
|
||||
marking-EarsShadekinRingedAll = Ears with Rings
|
||||
marking-EarsShadekinRingedAll-shadowkin = Ears
|
||||
marking-EarsShadekinRingedAll-ringed_all_secondary = Rings
|
||||
marking-EarsShadekinRingedLeft = Ears with Ring (L)
|
||||
marking-EarsShadekinRingedLeft-shadowkin = Ears
|
||||
marking-EarsShadekinRingedLeft-ringed_left_secondary = Ring
|
||||
marking-EarsShadekinRingedRight = Ears with Ring (R)
|
||||
marking-EarsShadekinRingedRight-shadowkin = Ears
|
||||
marking-EarsShadekinRingedRight-ringed_right_secondary = Ring
|
||||
marking-EarsShadekinGauzedAll = Gauzed Ears
|
||||
marking-EarsShadekinGauzedAll-shadowkin = Ears
|
||||
marking-EarsShadekinGauzedAll-gauze_ear_all_default = Gauze
|
||||
marking-EarsShadekinGauzedLeft = Ear Bandage (L)
|
||||
marking-EarsShadekinGauzedLeft-shadowkin = Ears
|
||||
marking-EarsShadekinGauzedLeft-gauze_ear_l_default = Bandage
|
||||
marking-EarsShadekinGauzedRight = Ear Bandage (R)
|
||||
marking-EarsShadekinGauzedRight-shadowkin = Ears
|
||||
marking-EarsShadekinGauzedRight-gauze_ear_r_default = Bandage
|
||||
marking-EarsShadekinFluffy = Fluffy Ears
|
||||
marking-EarsShadekinFluffy-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyButterfly = Fluffy Ears, Butterfly
|
||||
marking-EarsShadekinFluffyButterfly-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyButterfly-fluffy_butterfly = Pattern
|
||||
marking-EarsShadekinFluffyCowling = Fluffy Ears, Spotted
|
||||
marking-EarsShadekinFluffyCowling-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyCowling-fluffy_cowling = Pattern
|
||||
marking-EarsShadekinFluffyCrow = Fluffy Ears, Crow
|
||||
marking-EarsShadekinFluffyCrow-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyCrow-fluffy_crow = Pattern
|
||||
marking-EarsShadekinFluffyMotley = Fluffy Ears, Bright
|
||||
marking-EarsShadekinFluffyMotley-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyMotley-fluffy_motley = Pattern
|
||||
marking-EarsShadekinFluffySpidy = Fluffy Ears, Spidy
|
||||
marking-EarsShadekinFluffySpidy-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffySpidy-fluffy_spidy = Pattern
|
||||
marking-EarsShadekinFluffyRingedAll = Fluffy Ears, with Rings
|
||||
marking-EarsShadekinFluffyRingedAll-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyRingedAll-fluffy_ringed_all = Rings
|
||||
marking-EarsShadekinFluffyRingedLeft = Fluffy Ears, with Ring (L)
|
||||
marking-EarsShadekinFluffyRingedLeft-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyRingedLeft-fluffy_ringed_left = Ring
|
||||
marking-EarsShadekinFluffyRingedRight = Fluffy Ears, with Ring (R)
|
||||
marking-EarsShadekinFluffyRingedRight-fluffy_default = Ears
|
||||
marking-EarsShadekinFluffyRingedRight-fluffy_ringed_right = Ring
|
||||
marking-EarsShadekinSaggy = Drooping Ears
|
||||
marking-EarsShadekinSaggy-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyBrawly = Drooping Ears, Patterned
|
||||
marking-EarsShadekinSaggyBrawly-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyBrawly-saggy_brawly = Pattern
|
||||
marking-EarsShadekinSaggyZebra = Drooping Ears, Striped
|
||||
marking-EarsShadekinSaggyZebra-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyZebra-saggy_zebra = Stripes
|
||||
marking-EarsShadekinSaggyGradient = Drooping Ears, Gradient
|
||||
marking-EarsShadekinSaggyGradient-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyGradient-saggy_gradient = Gradient
|
||||
marking-EarsShadekinSaggyGauzedAll = Drooping Ears, Gauzed
|
||||
marking-EarsShadekinSaggyGauzedAll-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyGauzedAll-saggy_gauze_all = Gauze
|
||||
marking-EarsShadekinSaggyGauzedLeft = Drooping Ears, Ear Bandage (L)
|
||||
marking-EarsShadekinSaggyGauzedLeft-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyGauzedLeft-saggy_gauze_l = Bandage
|
||||
marking-EarsShadekinSaggyGauzedRight = Drooping Ears, Ear Bandage (R)
|
||||
marking-EarsShadekinSaggyGauzedRight-saggy_default = Ears
|
||||
marking-EarsShadekinSaggyGauzedRight-saggy_gauze_r = Bandage
|
||||
marking-EarsShadekinShort = Short Ears
|
||||
marking-EarsShadekinShort-short_default = Ears
|
||||
marking-EarsShadekinShortButterfly = Short Ears, Decorated
|
||||
marking-EarsShadekinShortButterfly-short_default = Ears
|
||||
marking-EarsShadekinShortButterfly-short_butterfly = Pattern
|
||||
marking-EarsShadekinShortRingedAll = Short Ears, with Rings
|
||||
marking-EarsShadekinShortRingedAll-short_default = Ears
|
||||
marking-EarsShadekinShortRingedAll-short_ringed_all = Rings
|
||||
marking-EarsShadekinShortRingedLeft = Short Ears, with Ring (L)
|
||||
marking-EarsShadekinShortRingedLeft-short_default = Ears
|
||||
marking-EarsShadekinShortRingedLeft-short_ringed_left = Ring
|
||||
marking-EarsShadekinShortRingedRight = Short Ears, with Ring (R)
|
||||
marking-EarsShadekinShortRingedRight-short_default = Ears
|
||||
marking-EarsShadekinShortRingedRight-short_ringed_right = Ring
|
||||
marking-EarsShadekinBull = Straight Ears
|
||||
marking-EarsShadekinBull-bull_default = Ears
|
||||
marking-EarsShadekinBullSmooth = Straight Ears, Outlined
|
||||
marking-EarsShadekinBullSmooth-bull_default = Ears
|
||||
marking-EarsShadekinBullSmooth-bull_smooth = Inner ears
|
||||
marking-EarsShadekinAqua = Aqua Ears
|
||||
marking-EarsShadekinAqua-aqua_default = Ears
|
||||
marking-EarsShadekinAquaIncolor = Aqua Ears, Colored
|
||||
marking-EarsShadekinAquaIncolor-aqua_default = Ears
|
||||
marking-EarsShadekinAquaIncolor-aqua_incolor = Inner ears
|
||||
|
||||
# Tails
|
||||
marking-TailShadekin = Long Tail
|
||||
marking-TailShadekinBig = Big Tail
|
||||
marking-TailShadekinShorter = Short Tail
|
||||
marking-TailShadekinShorter-shadekin_shorter_over = Tail
|
||||
marking-TailShadekinShorterBrush = Short Tail, Furry
|
||||
marking-TailShadekinShorterBrush-shadekin_shorter_over = Tail
|
||||
marking-TailShadekinShorterBrush-shorter_brush_over = Tail tip
|
||||
marking-TailShadekinMedium = Medium Tail
|
||||
marking-TailShadekinMedium-shadekin_medium_front = Tail
|
||||
marking-TailShadekinMediumTwoColored = Medium Tail, Two-Toned
|
||||
marking-TailShadekinMediumTwoColored-shadekin_medium_front = Tail
|
||||
marking-TailShadekinMediumTwoColored-medium_twocolored_over = Tail underside
|
||||
|
||||
# Overlays
|
||||
marking-BodyShadekinArrow = Arrow Marking
|
||||
marking-BodyShadekinArrow-body_arrow = Marking
|
||||
marking-BodyShadekinBlackHole = Black Hole Marking
|
||||
marking-BodyShadekinBlackHole-body_blackhole = Marking
|
||||
marking-BodyShadekinBrace = Bracelet Marking
|
||||
marking-BodyShadekinBrace-body_brace = Marking
|
||||
marking-BodyShadekinBrawly = Combat Marking
|
||||
marking-BodyShadekinBrawly-body_brawly = Marking
|
||||
marking-BodyShadekinHeart = Heart Marking
|
||||
marking-BodyShadekinHeart-body_heart = Marking
|
||||
marking-BodyShadekinInk = Ink Marking
|
||||
marking-BodyShadekinInk-body_ink = Marking
|
||||
marking-BodyShadekinInk2 = Ink Marking 2
|
||||
marking-BodyShadekinInk2-body_ink2 = Marking
|
||||
marking-BodyShadekinInk3 = Ink Marking 3
|
||||
marking-BodyShadekinInk3-body_ink3 = Marking
|
||||
marking-BodyShadekinInk4 = Ink Marking 4
|
||||
marking-BodyShadekinInk4-body_ink4 = Marking
|
||||
marking-BodyShadekinInk5 = Ink Marking 5
|
||||
marking-BodyShadekinInk5-body_ink5 = Marking
|
||||
marking-BodyShadekinInk6 = Spiritual Ink Marking
|
||||
marking-BodyShadekinInk6-body_ink6 = Marking
|
||||
marking-BodyShadekinInkAnim = Spiral Ink Marking
|
||||
marking-BodyShadekinInkAnim-body_ink_anim = Marking
|
||||
marking-BodyShadekinLines = Lines Marking
|
||||
marking-BodyShadekinLines-body_lines = Marking
|
||||
marking-BodyShadekinNeck = Neck Marking
|
||||
marking-BodyShadekinNeck-body_neck = Marking
|
||||
marking-BodyShadekinShield = Protective Marking
|
||||
marking-BodyShadekinShield-body_shield = Marking
|
||||
marking-BodyShadekinVacuum = Open Marking
|
||||
marking-BodyShadekinVacuum-body_vacuum = Marking
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
command-description-doext-client = Sends a console command back to the calling user's own client to run locally, once per piped value, substituting $ID/$PID/$WX/$WY/$LX/$LY/$SELF as well as any toolshed variable by name.
|
||||
command-description-doext-server = Runs a console command on the server as the calling session, once per piped value, substituting $ID/$PID/$WX/$WY/$LX/$LY/$SELF as well as any toolshed variable by name.
|
||||
|
|
@ -0,0 +1 @@
|
|||
command-description-FieldCommand = Reads the value of a field or property (by name) off of the piped input, resolved the same way vvread does.
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
ent-MagazinePistolSubMachineGunTopMounted =
|
||||
.desc = Unconventional 20-round top feeding magazine for the WT550 SMG. Intended to hold general-purpose kinetic ammunition.
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
offer-item-empty-hand = You don't have anything in your hand to give!
|
||||
|
||||
offer-item-full-hand = Your hand isn't free to receive the item.
|
||||
|
||||
offer-item-try-give = You offer {THE($item)} to {$target}.
|
||||
offer-item-try-give-target = {CAPITALIZE(THE($user))} offers you {THE($item)}.
|
||||
|
||||
offer-item-give = You handed {THE($item)} to {$target}.
|
||||
offer-item-give-other = {CAPITALIZE(THE($user))} handed {THE($item)} to {$target}.
|
||||
offer-item-give-target = {CAPITALIZE(THE($user))} handed you {THE($item)}.
|
||||
|
||||
offer-item-no-give = You stop offering {THE($item)} to {$target}.
|
||||
offer-item-no-give-target = {CAPITALIZE(THE($user))} is no longer offering {THE($item)} to you.
|
||||
|
||||
|
||||
alerts-offer-name = Accept Offer
|
||||
alerts-offer-desc = Click this alert to accept the item offered to you.
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
obvious-on-item = When {$used}, { SUBJECT($me) } will be [color=white]obvious[/color] to casual examination.
|
||||
obvious-on-item-currently = { CAPITALIZE(SUBJECT($me)) } { CONJUGATE-BE($me) } [color=white]obvious[/color] to casual examination.
|
||||
obvious-on-item-for-others = [italic][color=#777777]Others {$will} see:[/color] "{$output}"[/italic]
|
||||
|
||||
obvious-reveal-default = worn
|
||||
obvious-reveal-pockets = worn or pocketed
|
||||
|
||||
obvious-on-item-contra-Syndicate = Might make you seem [color=#ff0000]evil[/color].
|
||||
obvious-on-item-contra-Magical = Might make you seem [color=blue]mystical[/color].
|
||||
obvious-on-item-contra-Major = Don't be surprised if [color=#cb0000]some people[/color] aren't a fan.
|
||||
|
||||
obvious-prefix-default = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-HAVE($user) }
|
||||
obvious-prefix-wearing = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } wearing
|
||||
|
||||
## general descriptions
|
||||
obvious-desc-default = { INDEFINITE($short-type) } { $type } { $thing }.
|
||||
obvious-desc-colors = { INDEFINITE($thing) } { $thing } in { $type } colors.
|
||||
obvious-desc-proves = { INDEFINITE($thing) } [color=white]{ $thing }[/color] that proves { SUBJECT($user) } { CONJUGATE-BE($user) } { INDEFINITE($short-type) } { $type }.
|
||||
|
||||
## item categories
|
||||
obvious-thing-default = [italic]something-or-another[/italic]
|
||||
obvious-thing-cloak = cloak
|
||||
obvious-thing-pin = pin
|
||||
obvious-thing-scarf = scarf
|
||||
obvious-thing-badge = badge
|
||||
obvious-thing-armband = armband
|
||||
obvious-thing-medal = medal
|
||||
|
||||
## item types
|
||||
obvious-type-default = [italic]nothing[/italic]
|
||||
|
||||
# prides
|
||||
obvious-type-pride = [color=#d479d4]LGBTQ[/color] [color=white]pride[/color]
|
||||
obvious-type-pride-aro = [color=#3DA542]aromantic[/color] [color=white]pride[/color]
|
||||
obvious-type-pride-ace = [color=#efefef]asexual[/color] [color=#800080]pride[/color]
|
||||
obvious-type-pride-aroace = [color=#efc337]aroace[/color] [color=#45bcee]pride[/color]
|
||||
obvious-type-pride-lesbian = [color=#EF7627]lesbian[/color] [color=#B55690]pride[/color]
|
||||
obvious-type-pride-bi = [color=#D60270]bisexual[/color] [color=#0038A8]pride[/color]
|
||||
obvious-type-pride-pan = [color=#FF218C]pansexual[/color] [color=#21B1FF]pride[/color]
|
||||
obvious-type-pride-gay = [color=#078D70]gay[/color] [color=#5049CC]pride[/color]
|
||||
obvious-type-pride-omni = [color=#FE9ACE]omnisexual[/color] [color=8EA6FF]pride[/color]
|
||||
obvious-type-pride-bear = [color=#FDDC62]bear[/color] [color=#613704]pride[/color]
|
||||
obvious-type-pride-intersex = [color=#FFD800]intersex[/color] [color=#7902AA]pride[/color]
|
||||
obvious-type-pride-nonbinary = [color=#FCF434]nonbinary[/color] [color=#9C59D1]pride[/color]
|
||||
obvious-type-pride-trans = [color=#5BCEFA]transgender[/color] [color=#F5A9B8]pride[/color]
|
||||
obvious-type-pride-gf = [color=#FF76A4]genderfluid[/color] [color=#2F3CBE]pride[/color]
|
||||
obvious-type-pride-aut = [color=#FFD700]autism[/color] [color=white]pride[/color]
|
||||
obvious-type-pride-straightally = [color=#7c7c7c]straight[/color] [color=#d479d4]LGBTQ ally[/color]
|
||||
obvious-type-pride-gq = [color=#B57EDC]genderqueer[/color] [color=#4A8123]pride[/color]
|
||||
|
||||
# lawyers
|
||||
obvious-type-law = [color=white]certified[/color] [color=#FFD700]lawyer[/color]
|
||||
obvious-type-law-defense = [color=white]certified[/color] [color=#00C0C0]defense attorney[/color]
|
||||
obvious-type-law-prosecution = [color=white]certified[/color] [color=#FF2222]prosecuting attorney[/color]
|
||||
|
||||
## SPECIFIC DESCRIPTIONS (skips the above description-builders)
|
||||
obvious-x-scarf-lesbian-long = some [color=#EF7627]long[/color] [color=white]ba[/color][color=#B55690]con[/color].
|
||||
obvious-x-medal-nothing = a [color=#FFD700]gleaming medal[/color]!
|
||||
# medals should be in the description building functions but there's too many of them and this feature is already over-scope
|
||||
|
||||
# imp only items
|
||||
obvious-x-pin-straight = a [color=#7c7c7c]straight[/color] [color=white]pride[/color] pin... [italic]Ew.[/italic]
|
||||
obvious-x-cloak-straight = a cloak in the [color=#7c7c7c]straight[/color] [color=white]pride[/color] colors... [italic]Ew.[/italic]
|
||||
obvious-x-pin-novice = a [color=#F4EE12]novice[/color] [color=#1CAC99]mark[/color], identifying as [color=#efefef]unskilled[/color]. [color=#1CAC99][italic]Be patient and considerate with { OBJECT($user) }.[/italic][/color]
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Sad
|
||||
names-shadekin-dataset-1 = Fragile
|
||||
names-shadekin-dataset-2 = Heartbreak
|
||||
names-shadekin-dataset-3 = Inferior
|
||||
names-shadekin-dataset-4 = Lone
|
||||
names-shadekin-dataset-5 = Lonesome
|
||||
names-shadekin-dataset-6 = Loss
|
||||
names-shadekin-dataset-7 = Solitary
|
||||
names-shadekin-dataset-8 = Solitude
|
||||
names-shadekin-dataset-9 = Sorrow
|
||||
names-shadekin-dataset-10 = Shade
|
||||
|
||||
# Angry
|
||||
names-shadekin-dataset-11 = Fear
|
||||
names-shadekin-dataset-12 = Fearful
|
||||
names-shadekin-dataset-13 = Fury
|
||||
names-shadekin-dataset-14 = Pain
|
||||
names-shadekin-dataset-15 = Rage
|
||||
names-shadekin-dataset-16 = Rush
|
||||
names-shadekin-dataset-17 = Wrath
|
||||
|
||||
# Happy
|
||||
names-shadekin-dataset-18 = Calm
|
||||
names-shadekin-dataset-19 = Content
|
||||
names-shadekin-dataset-20 = Contented
|
||||
names-shadekin-dataset-21 = Happy
|
||||
names-shadekin-dataset-22 = Hope
|
||||
names-shadekin-dataset-23 = Joyous
|
||||
names-shadekin-dataset-24 = Lovely
|
||||
names-shadekin-dataset-25 = Peace
|
||||
names-shadekin-dataset-26 = Peaceful
|
||||
names-shadekin-dataset-27 = Quiet
|
||||
names-shadekin-dataset-28 = Serene
|
||||
names-shadekin-dataset-29 = Serenity
|
||||
names-shadekin-dataset-30 = Tranquil
|
||||
names-shadekin-dataset-31 = Tranquility
|
||||
|
||||
# Memory
|
||||
names-shadekin-dataset-32 = Dillusioned
|
||||
names-shadekin-dataset-33 = Forgotten
|
||||
names-shadekin-dataset-34 = Focusless
|
||||
names-shadekin-dataset-35 = Lost
|
||||
names-shadekin-dataset-36 = Memory
|
||||
names-shadekin-dataset-37 = Recollection
|
||||
names-shadekin-dataset-38 = Remembrance
|
||||
names-shadekin-dataset-39 = Reminisce
|
||||
names-shadekin-dataset-40 = Reminiscence
|
||||
|
||||
# Other
|
||||
names-shadekin-dataset-41 = Apathy
|
||||
names-shadekin-dataset-42 = Collected
|
||||
names-shadekin-dataset-43 = Curiosity
|
||||
names-shadekin-dataset-44 = Free
|
||||
names-shadekin-dataset-45 = Interest
|
||||
names-shadekin-dataset-46 = Jax
|
||||
names-shadekin-dataset-47 = Still
|
||||
names-shadekin-dataset-48 = Unbound
|
||||
names-shadekin-dataset-49 = Shadows
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
chat-emote-name-marr = Marr
|
||||
chat-emote-name-wurble = Wurble
|
||||
|
||||
chat-emote-msg-marr = marrs!
|
||||
chat-emote-msg-wurble = wurbles!
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
alerts-shadekin-name = Light Exposure
|
||||
alerts-shadekin-desc = How much light is around you.
|
||||
|
||||
shadekin-alert-0 = [color=green]Light Exposure: Darkness...[/color]
|
||||
The darkness is nice... It's like home... I feel my wounds healing...
|
||||
shadekin-alert-1 = [color=green]Light Exposure: Low[/color]
|
||||
shadekin-alert-2 = [color=green]Light Exposure: Annoying[/color]
|
||||
The light is annoying in this place... I feel my wounds will not heal properly...
|
||||
shadekin-alert-3 = [color=green]Light Exposure: High[/color]
|
||||
Too many lights... too many! I feel exausted...
|
||||
shadekin-alert-4 = [color=green]Light Exposure:[/color] [color=red]EXTREME[/color]
|
||||
LIGHTS... I NEED DARKNESS! It burns!
|
||||
|
||||
phase-fail-generic = I can't phase!
|
||||
|
|
@ -0,0 +1 @@
|
|||
species-name-shadekin = Shadekin
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
trait-clumsy-name = Clumsy
|
||||
trait-clumsy-desc = You are a bit accident-prone
|
||||
|
||||
trait-highlightsensitivity-name = High Light Sensitivity
|
||||
trait-highlightsensitivity-desc = You are much more sensitive to light than most shadekins
|
||||
|
||||
trait-extremelightsensitivity-name = Extreme Light Sensitivity
|
||||
trait-extremelightsensitivity-desc = You are extremely more sensitive to light than most shadekins.
|
||||
|
|
@ -13,6 +13,25 @@ bounty-console-manifest-reward = Reward: ${$reward}
|
|||
bounty-console-description-label = [color=gray]{$description}[/color]
|
||||
bounty-console-id-label = ID#{$id}
|
||||
|
||||
## Begin DeltaV
|
||||
bounty-console-claim-button-text = Claim
|
||||
bounty-console-claimed-by-none = None
|
||||
bounty-console-claimed-by-unknown = Unknown
|
||||
bounty-console-claimed-by = Claimed by: {$claimant}
|
||||
|
||||
bounty-console-status-Undelivered = Undelivered
|
||||
bounty-console-status-Waiting = Processing
|
||||
bounty-console-status-OnShuttle = On Shuttle
|
||||
|
||||
bounty-console-status-formatted-Undelivered = [color=orange]Undelivered[/color]
|
||||
bounty-console-status-formatted-Waiting = Processing
|
||||
bounty-console-status-formatted-OnShuttle = [color=limegreen]On Shuttle[/color]
|
||||
|
||||
bounty-console-status-tooltip-Undelivered = This bounty has not yet been sent out for fulfilment
|
||||
bounty-console-status-tooltip-Waiting = This bounty has been sent out, and is waiting to be fulfilled
|
||||
bounty-console-status-tooltip-OnShuttle = This bounty is completed, ready to be delivered to the trade station
|
||||
## End DeltaV
|
||||
|
||||
bounty-console-flavor-left = Bounties sourced from local unscrupulous dealers.
|
||||
bounty-console-flavor-right = v1.4
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,6 +6,7 @@
|
|||
order:
|
||||
- category: Health
|
||||
- category: Stamina
|
||||
- alertType: Shadeskin # Starlight
|
||||
- alertType: SuitPower
|
||||
- category: Internals
|
||||
- alertType: Fire
|
||||
|
|
@ -28,6 +29,7 @@
|
|||
- alertType: Rooted
|
||||
- alertType: Pacified
|
||||
- alertType: Stealthy
|
||||
- alertType: Offer # Floofstation - port from EE
|
||||
|
||||
- type: entity
|
||||
id: AlertSpriteView
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@
|
|||
Kidneys: OrganVulpkaninKidneys
|
||||
- type: HumanoidProfile
|
||||
species: Vulpkanin
|
||||
- type: Inventory
|
||||
speciesId: vulpkanin
|
||||
# Delta V - We got no displacement for Vulpkaning
|
||||
# - type: Inventory
|
||||
# speciesId: vulpkanin
|
||||
# displacements:
|
||||
# jumpsuit:
|
||||
# sizeMaps:
|
||||
|
|
@ -149,7 +149,7 @@
|
|||
- type: Speech
|
||||
speechSounds: Vulpkanin
|
||||
speechVerb: Vulpkanin
|
||||
allowedEmotes: [ 'Bark', 'Snarl', 'Whine', 'Howl', 'Growl' ]
|
||||
allowedEmotes: [ 'Bark', 'Snarl', 'Whine', 'Howl', 'Growl', 'Yip' ] # DeltaV - Added Yip Emote
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleVulpkanin
|
||||
|
|
|
|||
|
|
@ -97,3 +97,4 @@
|
|||
type: HumanoidMarkingModifierBoundUserInterface
|
||||
enum.StrippingUiKey.Key:
|
||||
type: StrippableBoundUserInterface
|
||||
- type: OfferItem # Floofstation
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
PassengerIDCard: 5
|
||||
ClothingHeadsetGrey: 5
|
||||
ClothingHeadsetService: 5 # Delta-V
|
||||
ClothingNeckNoviceMark: 5 # imp
|
||||
RubberStampApproved: 1
|
||||
RubberStampDenied: 1
|
||||
BoxFolderPlasticClipboardEmpty: 2
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
ClothingHeadHelmetBasic: 2 # DeltaV - added helmets to the SecTech. Another line of defense between the tide and your grey matter.
|
||||
BreachingCharge: 8 # DeltaV - added breaching charges
|
||||
TicketPad: 5 # imp
|
||||
DVEvidenceBag: 10 # DeltaV - evidence bags
|
||||
DVBoxEvidenceBags: 2 # DeltaV - evidence bags
|
||||
# security officers need to follow a diet regimen!
|
||||
contrabandInventory:
|
||||
WeaponMeleeNeedle: 2
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
ClothingOuterCoatStasec: 2 # DeltaV - replace ClothingOuterWinterSec
|
||||
ClothingOuterCoatStasecCorpsman: 2 # DeltaV - added corpsman uniform to secdrobe
|
||||
# ClothingOuterWinterSec: 2 # DeltaV - removed this
|
||||
ClothingNeckCWPSec: 3 # DeltaV - add cold weather ponchos
|
||||
## ClothingOuterArmorBasic: 2 # DeltaV - moved body armour from SecDrobe to SecTech
|
||||
## ClothingOuterArmorBasicSlim: 2
|
||||
ClothingNeckScarfStripedBlue: 3 # DeltaV - blue instead of red scarf. Was ClothingNeckScarfStripedRed
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
ClothingUniformJumpskirtWaitstaffFormal: 2
|
||||
ClothingUniformJumpsuitWaitstaffFormal: 2
|
||||
ClothingUniformJumpsuitWorkvest: 2
|
||||
ClothingUniformJumpsuitFreighterCrew: 2
|
||||
ClothingOuterDusterCoat: 2
|
||||
ClothingOuterCoatNavalCoat: 2
|
||||
ClothingNeckCloakWitchCloak: 2
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
sprite: Clothing/Neck/Cloaks/miner.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakTrans
|
||||
name: vampire cloak
|
||||
description: Worn by high ranking vampires of the transylvanian society of vampires.
|
||||
|
|
@ -145,6 +145,8 @@
|
|||
sprite: Clothing/Neck/Cloaks/trans.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakTrans # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-trans
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -214,7 +216,7 @@
|
|||
proto: alien
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakAce
|
||||
name: pilot's cloak
|
||||
description: Cloak awarded to Nanotrasen's finest space aces.
|
||||
|
|
@ -223,9 +225,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/ace.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakAce # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-ace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakAro
|
||||
name: werewolf cloak
|
||||
description: This cloak lets others know you're a lone wolf.
|
||||
|
|
@ -234,9 +238,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/aro.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakAro # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aro
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakAroace
|
||||
name: aeropilot's cloak # thank you happyman442 this was the best name idea ever
|
||||
description: Cloak awarded to Nanotrasen's finest pilots on planets with inhabitable atmospheres.
|
||||
|
|
@ -245,9 +251,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/aroace.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakAroace # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aroace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakBi
|
||||
name: poison cloak
|
||||
description: The purple color is a clear indicator you are poisonous.
|
||||
|
|
@ -256,9 +264,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/bi.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakBi # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-bi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakIntersex
|
||||
name: cyclops cloak
|
||||
description: The circle on this cloak represents a cyclops' eye.
|
||||
|
|
@ -267,9 +277,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/intersex.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakIntersex # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-intersex
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakLesbian
|
||||
name: poet cloak
|
||||
description: This cloak belonged to an ancient poet, you forgot which one.
|
||||
|
|
@ -278,9 +290,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/les.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakLesbian # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-lesbian
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakGay
|
||||
name: multi-level marketing cloak
|
||||
description: This cloak is highly sought after in the Nanotrasen Marketing Offices.
|
||||
|
|
@ -289,9 +303,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/gay.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakGay # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-gay
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakEnby
|
||||
name: treasure hunter cloak
|
||||
description: This cloak belonged to a greedy treasure hunter.
|
||||
|
|
@ -300,9 +316,11 @@
|
|||
sprite: Clothing/Neck/Cloaks/enby.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakEnby # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-nonbinary
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderCloakBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderCloakBase, BaseObviousCloak ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckCloakPan
|
||||
name: chef's cloak
|
||||
description: Meant to be worn alongside a frying pan.
|
||||
|
|
@ -311,4 +329,7 @@
|
|||
sprite: Clothing/Neck/Cloaks/pan.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckCloakPan # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-pan
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -30,6 +35,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -45,6 +54,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -60,6 +73,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -75,6 +92,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -90,6 +111,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -105,6 +130,10 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
@ -122,3 +151,8 @@
|
|||
tags:
|
||||
- Medal
|
||||
- WhitelistChameleon
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-medal
|
||||
examineText: obvious-x-medal-nothing
|
||||
pocketEvident: true
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
sprite: Clothing/Neck/Misc/bling.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
parent: [ ClothingNeckBase, BaseObviousBadge ] # imp
|
||||
id: ClothingNeckLawyerbadge
|
||||
name: lawyer badge
|
||||
description: A badge to show that the owner is a 'legitimate' lawyer who passed the NT bar exam required to practice law.
|
||||
|
|
@ -57,6 +57,8 @@
|
|||
sprite: Clothing/Neck/Misc/lawyerbadge.rsi
|
||||
- type: TypingIndicatorClothing
|
||||
proto: lawyer
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-law
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckBase
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
sprite: Clothing/Neck/Misc/pins.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Neck/Misc/pins.rsi
|
||||
- type: WearerGetsExamineText # imp
|
||||
thing: obvious-thing-pin
|
||||
examineText: obvious-desc-default
|
||||
pocketEvident: true
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckPinBase
|
||||
|
|
@ -46,6 +50,8 @@
|
|||
equippedPrefix: lgbt
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckLGBTPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -59,6 +65,8 @@
|
|||
equippedPrefix: ally
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckAllyPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-straightally
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -72,6 +80,8 @@
|
|||
equippedPrefix: aro
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckAromanticPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aro
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -85,6 +95,8 @@
|
|||
equippedPrefix: aroace
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckAroacePin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aroace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -98,6 +110,8 @@
|
|||
equippedPrefix: asex
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckAsexualPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-ace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -111,6 +125,8 @@
|
|||
equippedPrefix: bi
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckBisexualPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-bi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -124,6 +140,8 @@
|
|||
equippedPrefix: gay
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckGayPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-gay
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -137,6 +155,8 @@
|
|||
equippedPrefix: inter
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckIntersexPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-intersex
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -150,6 +170,8 @@
|
|||
equippedPrefix: les
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckLesbianPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-lesbian
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -163,6 +185,8 @@
|
|||
equippedPrefix: non
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckNonBinaryPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-nonbinary
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -176,6 +200,8 @@
|
|||
equippedPrefix: pan
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckPansexualPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-pan
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -202,6 +228,8 @@
|
|||
equippedPrefix: omni
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckOmnisexualPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-omni
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -215,6 +243,8 @@
|
|||
equippedPrefix: gender
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckGenderqueerPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-gq
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderPinBase
|
||||
|
|
@ -241,6 +271,8 @@
|
|||
equippedPrefix: trans
|
||||
- type: ChameleonClothing
|
||||
default: ClothingNeckTransPin
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-trans
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckPinBase
|
||||
|
|
@ -252,6 +284,8 @@
|
|||
state: autism
|
||||
- type: Clothing
|
||||
equippedPrefix: autism
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aut
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckPinBase
|
||||
|
|
@ -263,6 +297,8 @@
|
|||
state: goldautism
|
||||
- type: Clothing
|
||||
equippedPrefix: goldautism
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aut
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
|
||||
# Pride Scarves
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedAce
|
||||
name: striped asexual scarf
|
||||
description: A stylish striped asexual scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -147,9 +147,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/ace.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedAce # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-ace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedAro
|
||||
name: striped aromantic scarf
|
||||
description: A stylish striped aromantic scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -160,9 +162,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/aro.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedAro # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aro
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedAroace
|
||||
name: striped aroace scarf
|
||||
description: A stylish striped aroace scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -173,9 +177,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/aroace.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedAroace # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-aroace
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedBiSexual
|
||||
name: striped bisexual scarf
|
||||
description: A stylish striped bisexual scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -186,9 +192,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/bi.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedBiSexual # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-bi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedGay
|
||||
name: striped gay scarf
|
||||
description: A stylish striped gay scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -199,9 +207,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/gay.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedGay # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-gay
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedInter
|
||||
name: striped intersex scarf
|
||||
description: A stylish striped intersex scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -212,9 +222,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/inter.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedInter # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-intersex
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedLesbian
|
||||
name: striped lesbian scarf
|
||||
description: A stylish striped lesbian scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -225,9 +237,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/lesbian.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedLesbian # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-lesbian
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedPan
|
||||
name: striped pan scarf
|
||||
description: A stylish striped pan scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -238,9 +252,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/pan.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedPan # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-pan
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedNonBinary
|
||||
name: striped non-binary scarf
|
||||
description: A stylish striped non-binary scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -251,9 +267,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/non.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedNonBinary # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-nonbinary
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedRainbow
|
||||
name: rainbow scarf
|
||||
description: A stylish rainbow scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -264,9 +282,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/rainbow.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedRainbow # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedTrans
|
||||
name: striped trans scarf
|
||||
description: A stylish striped trans scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks.
|
||||
|
|
@ -277,9 +297,11 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/trans.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedTrans # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
thingType: obvious-type-pride-trans
|
||||
|
||||
- type: entity
|
||||
parent: ClothingGenderScarfBase # DeltaV - Chameleon pride clothing
|
||||
parent: [ ClothingGenderScarfBase, BaseObviousScarf ] # DeltaV - Chameleon pride clothing, porting imp's examine
|
||||
id: ClothingNeckScarfStripedLesbianLong
|
||||
name: long bacon
|
||||
description: Long bacon! Perfect for sharing with your girlfriend!
|
||||
|
|
@ -290,3 +312,6 @@
|
|||
sprite: Clothing/Neck/Scarfs/PrideScarfs/lesbian-long.rsi
|
||||
- type: ChameleonClothing # DeltaV - Chameleon pride clothing
|
||||
default: ClothingNeckScarfStripedLesbianLong # DeltaV - Chameleon pride clothing
|
||||
- type: WearerGetsExamineText # imp
|
||||
examineText: obvious-x-scarf-lesbian-long
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- type: marking
|
||||
id: TattooHiveChest
|
||||
bodyPart: Chest
|
||||
groupWhitelist: [Human, Slime, Felinid, Oni, Kitsune, Avali] # DeltaV - SlimePerson-Avali
|
||||
groupWhitelist: [Human, Slime, Felinid, Oni, Kitsune, Avali, Shadekin] # DeltaV - SlimePerson-Avali # Starlight - Shadekin
|
||||
sexRestriction: [Male] # DeltaV: Splitting the scars and tattoos
|
||||
coloring:
|
||||
default:
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
- type: marking
|
||||
id: TattooNightlingChest
|
||||
bodyPart: Chest
|
||||
groupWhitelist: [Human, Slime, Felinid, Oni, Kitsune, Avali] # DeltaV - SlimePerson-Avali
|
||||
groupWhitelist: [Human, Slime, Felinid, Oni, Kitsune, Avali, Shadekin] # DeltaV - SlimePerson-Avali # Starlight - Shadekin
|
||||
sexRestriction: [Male] # DeltaV: Splitting the scars and tattoos
|
||||
coloring:
|
||||
default:
|
||||
|
|
@ -23,13 +23,13 @@
|
|||
!type:TattooColoring
|
||||
fallbackColor: "#666666"
|
||||
sprites:
|
||||
- sprite: _DV/Mobs/Customization/tattoos.rsi # DeltaV: Splitting the scars and tattoos
|
||||
- sprite: _DV/Mobs/Customization/tattoos.rsi # DeltaV: Splitting the scars and tattoos # Starlight - Shadekin
|
||||
state: tattoo_nightling
|
||||
|
||||
- type: marking
|
||||
id: TattooSilverburghLeftLeg
|
||||
bodyPart: LLeg
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
- type: marking
|
||||
id: TattooSilverburghRightLeg
|
||||
bodyPart: RLeg
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
- type: marking
|
||||
id: TattooCampbellLeftArm
|
||||
bodyPart: LArm
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
- type: marking
|
||||
id: TattooCampbellRightArm
|
||||
bodyPart: RArm
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
- type: marking
|
||||
id: TattooCampbellLeftLeg
|
||||
bodyPart: LLeg
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
- type: marking
|
||||
id: TattooCampbellRightLeg
|
||||
bodyPart: RLeg
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune] # DeltaV - Felinid-Kitsune
|
||||
groupWhitelist: [Human, Felinid, Oni, Kitsune, Shadekin] # DeltaV - Felinid-Kitsune # Starlight - Shadekin
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
|
|
|
|||
|
|
@ -1613,6 +1613,16 @@
|
|||
Blunt: 1
|
||||
clumsySound:
|
||||
path: /Audio/Animals/monkey_scream.ogg
|
||||
#Begin DeltaV additions
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MonkeySounds
|
||||
Female: MonkeySounds
|
||||
Unsexed: MonkeySounds
|
||||
wilhelmProbability: 0.01
|
||||
- type: BodyEmotes
|
||||
soundsId: MonkeySounds
|
||||
#End DeltaV additions
|
||||
|
||||
|
||||
- type: entity
|
||||
|
|
@ -1647,6 +1657,16 @@
|
|||
- type: GhostTakeoverAvailable
|
||||
- type: Loadout
|
||||
prototypes: [SyndicateOperativeGearMonkey]
|
||||
#Begin DeltaV additions
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MonkeySounds
|
||||
Female: MonkeySounds
|
||||
Unsexed: MonkeySounds
|
||||
wilhelmProbability: 0.01
|
||||
- type: BodyEmotes
|
||||
soundsId: MonkeySounds
|
||||
#End DeltaV additions
|
||||
|
||||
- type: entity
|
||||
id: MobMonkeySyndicateAgent
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue