Upstrearm sync (#94)
* Fix for the salvage ice labs map. (#26928)
* done
* more work
* Automatic changelog update
* Update Credits (#26938)
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
* Fix cryostorage identifying unknown characters as captain (#26927)
Fixed cryostorage getting captain's record for unknown jobs.
Also localized Unknown job string.
* Automatic changelog update
* Fixed Honkbot/jonkbot honking like crazy, gave honkbot/jonkbot standard idle ai. (#26939)
* Fixed Honkbot/jonkbot honking like crazy, gave honkbot/jonkbot standard idle ai.
* Update Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
---------
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
* Automatic changelog update
* Bug fix: Force cancellation of RCD constructions if the construction type is changed (#26935)
Force cancellation of RCD constructions if the construction type is changed
* Fix standart -> standard and dressfilled test fail (#26942)
Fix standart -> standard
* Add Ability to stop sound when MobState is Dead (#26905)
* Add stopsWhenEntityDead to sound components
* Convert component
* Review
* Fix dupe sub
---------
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
* Automatic changelog update
* Fix rockets and lasers looking like they have nothing loaded (#26933)
* Automatic changelog update
* You can now see paper on crates (with color!) (#26834)
* Implement changes on not-cooked branch
* Made it work
* Fix update appearance calls
* Fix extra indents, clean-up code, fix tests hopefully
* Fix hammy cagecrate
* Fix messing up the yml, add artifact crate specific labels back in
* Visual Studio hates yml, sad
* Seperate the colors for cargonia
* sorry json
* make label move with artifact door
* Apply suggestion changes
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
* Fix remaining crate offsets, add a few for livestock and graves (why are you labeling graves) and coffin label sprites (why are you labeling coffins??)
---------
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
* Make UtensilSystem and SharpSystem not run AfterInteract if it has already been handled (#25826)
* Make UtensilSystem and SharpSystem not run AfterInteract if it has already been handled
* merge conflicts
---------
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
* Automatic changelog update
* Add two-message overload to PopupPredicted (#26907)
Added two-message overload to PopupPredicted
* Update submodule to 218.0.0 (#26945)
* Autism pins! (#25597)
* hee hee he ha ha
* added gold varients, forgive me for my spritework
* maints loot, copying from past PRs
* Trying to fix RSI
* speedran these sprites in break time, pictures will be later
* Fixed/Tweaked glows
* consensus
* gregregation
* dam copiryte
* oops i forgot to delete 2 fields hope this works
* Automatic changelog update
* Fix database round start date issues (#26838)
How can ONE DATABASE COLUMN have so many cursed issues I don't know, but it certainly pissed off the devil in its previous life.
The start_date column on round entities in the database was added by https://github.com/space-wizards/space-station-14/pull/21153. For some reason, this PR gave the column a nonsensical default value instead of making it nullable. This default value causes the code from #25280 to break. It actually trips an assert though that's not what the original issue report ran into.
This didn't get noticed on wizden servers because we at some point backfilled the start_date column based on the stored admin logs.
So I change the database model to make this column nullable, updated the C# code to match, and made the existing migration set the invalid values to be NULL instead. Cool.
Wait how's SQLite handle in this scenario anyways? Well actually turns out the column was *completely broken* in the first place!
The code for inserting into the round table was copy pasted between SQLite and PostgreSQL, with the only difference being that the SQLite key manually assigned the primary key instead of letting SQLite AUTOINCREMENT it. And then the code to give a start_date value was only added to the PostgreSQL version (which is actually in the base class already). So for SQLite that column's been filled up with the same invalid default the whole time.
Why was the code manually assigning a PK? I checked the SQLite docs for AUTOINCREMENT[1], and the behavior seems appropriate.
I removed the SQLite-specific code path and it just seems to work regardless. The migration just sets the old values to NULL too.
BUT WAIT, THERE'S MORE!
Turns out just doing the migration on SQLite is a pain in the ass! EF Core has to create a new table to apply the nullability change, because SQLite doesn't support proper ALTER COLUMN. This causes the generated SQL commands to be weird and the UPDATE for the migration goes BEFORE the nullability change... I ended up having to make TWO migrations for SQLite. Yay.
Fixes #26800
[1]: https://www.sqlite.org/autoinc.html
* Fix options menu crashing in replays (#26911)
Not having the nullable set properly is annoying but fixing that would probably be a significant amount of work.
* Greyscale color clothing (#26943)
* greyscales color gloves, color jumpsuits, and shoes
* remove popbob
* fix test fails
* Automatic changelog update
* WT550 Buffs + Burst Mode for WT550 & C-20R (#26886)
* Slightly increased WT550 Firerate, drastically reduced recoil, and given it the option to fire in 5 round bursts.
* Given the C-20 a 5 round burst aswell
* Automatic changelog update
* make holoparasites actually holographic (#26862)
it's over
* Automatic changelog update
* Add character sheets to board game crate (#26926)
add character sheets to board game crate
* Automatic changelog update
* Game server admin API (#26880)
* Reapply "Game server api" (#26871)
This reverts commit 3aee197923.
* Rewrite 75% of the code it's good now
* Wield recoil components (#26915)
* WieldRecoilComponents
* WieldRecoilComponents
* Update Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs
Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com>
* Update Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs
---------
Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
* Clown shoes make you waddle, as God intended (#26338)
* Clown shoes make you waddle, as God intended
* OOPS
* Toned down, client system name fix
* Tidy namespacing for @deltanedas
* Refactor to handle prediction better, etc.
* Resolve PR comments.
* Automatic changelog update
* Use round time instead of server time for criminal history (#26949)
make criminal records computer use round time for history instead of the server time
* Rotate and Offset station CCVar nuke (#26175)
* no content
* add noRot to Europa
* bruh. and this
* yay
* fix
* Update debug.yml
---------
Co-authored-by: Boaz1111 <149967078+Boaz1111@users.noreply.github.com>
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: superjj18 <gagnonjake@gmail.com>
Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: GreaseMonk <1354802+GreaseMonk@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com>
Co-authored-by: Verm <32827189+Vermidia@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: Terraspark4941 <terraspark4941@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
Co-authored-by: BramvanZijp <56019239+BramvanZijp@users.noreply.github.com>
Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com>
Co-authored-by: Tyzemol <85772526+Tyzemol@users.noreply.github.com>
Co-authored-by: Froffy025 <78222136+Froffy025@users.noreply.github.com>
Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com>
Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>
Co-authored-by: ilya.mikheev.coder <imc-ext+github@ilyamikcoder.com>
31
Content.Client/Clothing/Systems/WaddleClothingSystem.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Inventory.Events;
|
||||
|
||||
namespace Content.Client.Clothing.Systems;
|
||||
|
||||
public sealed class WaddleClothingSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<WaddleWhenWornComponent, GotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<WaddleWhenWornComponent, GotUnequippedEvent>(OnGotUnequipped);
|
||||
}
|
||||
|
||||
private void OnGotEquipped(EntityUid entity, WaddleWhenWornComponent comp, GotEquippedEvent args)
|
||||
{
|
||||
var waddleAnimComp = EnsureComp<WaddleAnimationComponent>(args.Equipee);
|
||||
|
||||
waddleAnimComp.AnimationLength = comp.AnimationLength;
|
||||
waddleAnimComp.HopIntensity = comp.HopIntensity;
|
||||
waddleAnimComp.RunAnimationLengthMultiplier = comp.RunAnimationLengthMultiplier;
|
||||
waddleAnimComp.TumbleIntensity = comp.TumbleIntensity;
|
||||
}
|
||||
|
||||
private void OnGotUnequipped(EntityUid entity, WaddleWhenWornComponent comp, GotUnequippedEvent args)
|
||||
{
|
||||
RemComp<WaddleAnimationComponent>(args.Equipee);
|
||||
}
|
||||
}
|
||||
135
Content.Client/Movement/Systems/WaddleAnimationSystem.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Gravity;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Movement.Systems;
|
||||
|
||||
public sealed class WaddleAnimationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||
[Dependency] private readonly GravitySystem _gravity = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<WaddleAnimationComponent, MoveInputEvent>(OnMovementInput);
|
||||
SubscribeLocalEvent<WaddleAnimationComponent, StartedWaddlingEvent>(OnStartedWalking);
|
||||
SubscribeLocalEvent<WaddleAnimationComponent, StoppedWaddlingEvent>(OnStoppedWalking);
|
||||
SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||
}
|
||||
|
||||
private void OnMovementInput(EntityUid entity, WaddleAnimationComponent component, MoveInputEvent args)
|
||||
{
|
||||
// Prediction mitigation. Prediction means that MoveInputEvents are spammed repeatedly, even though you'd assume
|
||||
// they're once-only for the user actually doing something. As such do nothing if we're just repeating this FoR.
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.HasDirectionalMovement && component.IsCurrentlyWaddling)
|
||||
{
|
||||
component.IsCurrentlyWaddling = false;
|
||||
|
||||
var stopped = new StoppedWaddlingEvent(entity);
|
||||
|
||||
RaiseLocalEvent(entity, ref stopped);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Only start waddling if we're not currently AND we're actually moving.
|
||||
if (component.IsCurrentlyWaddling || !args.HasDirectionalMovement)
|
||||
return;
|
||||
|
||||
component.IsCurrentlyWaddling = true;
|
||||
|
||||
var started = new StartedWaddlingEvent(entity);
|
||||
|
||||
RaiseLocalEvent(entity, ref started);
|
||||
}
|
||||
|
||||
private void OnStartedWalking(EntityUid uid, WaddleAnimationComponent component, StartedWaddlingEvent args)
|
||||
{
|
||||
if (_animation.HasRunningAnimation(uid, component.KeyName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<InputMoverComponent>(uid, out var mover))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_gravity.IsWeightless(uid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tumbleIntensity = component.LastStep ? 360 - component.TumbleIntensity : component.TumbleIntensity;
|
||||
var len = mover.Sprinting ? component.AnimationLength * component.RunAnimationLengthMultiplier : component.AnimationLength;
|
||||
|
||||
component.LastStep = !component.LastStep;
|
||||
component.IsCurrentlyWaddling = true;
|
||||
|
||||
var anim = new Animation()
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(len),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Rotation),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(tumbleIntensity), len/2),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), len/2),
|
||||
}
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(new Vector2(), 0),
|
||||
new AnimationTrackProperty.KeyFrame(component.HopIntensity, len/2),
|
||||
new AnimationTrackProperty.KeyFrame(new Vector2(), len/2),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_animation.Play(uid, anim, component.KeyName);
|
||||
}
|
||||
|
||||
private void OnStoppedWalking(EntityUid uid, WaddleAnimationComponent component, StoppedWaddlingEvent args)
|
||||
{
|
||||
_animation.Stop(uid, component.KeyName);
|
||||
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sprite.Offset = new Vector2();
|
||||
sprite.Rotation = Angle.FromDegrees(0);
|
||||
component.IsCurrentlyWaddling = false;
|
||||
}
|
||||
|
||||
private void OnAnimationCompleted(EntityUid uid, WaddleAnimationComponent component, AnimationCompletedEvent args)
|
||||
{
|
||||
var started = new StartedWaddlingEvent(uid);
|
||||
|
||||
RaiseLocalEvent(uid, ref started);
|
||||
}
|
||||
}
|
||||
@@ -59,8 +59,10 @@ namespace Content.Client.Options.UI.Tabs
|
||||
UpdateApplyButton();
|
||||
};
|
||||
|
||||
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel.UserData.PatronTier is { } patron;
|
||||
|
||||
// Channel can be null in replays so.
|
||||
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
|
||||
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel?.UserData.PatronTier is { };
|
||||
|
||||
HudThemeOption.OnItemSelected += OnHudThemeChanged;
|
||||
DiscordRich.OnToggled += OnCheckBoxToggled;
|
||||
ShowOocPatronColor.OnToggled += OnCheckBoxToggled;
|
||||
|
||||
@@ -184,6 +184,12 @@ namespace Content.Client.Popups
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient != null && _timing.IsFirstTimePredicted)
|
||||
PopupEntity(recipientMessage, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Network Event Handlers
|
||||
|
||||
@@ -40,7 +40,7 @@ public sealed partial class GunSystem
|
||||
|
||||
if (sprite == null) return;
|
||||
|
||||
if (args.AppearanceData.TryGetValue(AmmoVisuals.MagLoaded, out var magloaded) &&
|
||||
if (!args.AppearanceData.TryGetValue(AmmoVisuals.MagLoaded, out var magloaded) ||
|
||||
magloaded is true)
|
||||
{
|
||||
if (!args.AppearanceData.TryGetValue(AmmoVisuals.AmmoMax, out var capacity))
|
||||
|
||||
1766
Content.Server.Database/Migrations/Postgres/20240409013837_FixRoundStartDateNullability.Designer.cs
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixRoundStartDateNullability : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "round",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldDefaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.Sql("UPDATE round SET start_date = NULL WHERE start_date = '-Infinity';");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "round",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,10 +845,8 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("server_id");
|
||||
|
||||
b.Property<DateTime>("StartDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
b.Property<DateTime?>("StartDate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValue(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified))
|
||||
.HasColumnName("start_date");
|
||||
|
||||
b.HasKey("Id")
|
||||
|
||||
1697
Content.Server.Database/Migrations/Sqlite/20240409013832_FixRoundStartDateNullability.Designer.cs
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixRoundStartDateNullability : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "round",
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "TEXT",
|
||||
oldDefaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "round",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "TEXT",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
1697
Content.Server.Database/Migrations/Sqlite/20240409014937_FixRoundStartDateNullability2.Designer.cs
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixRoundStartDateNullability2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// This needs to be its own separate migration,
|
||||
// because EF Core re-arranges the order of the commands if it's a single migration...
|
||||
// (only relevant for SQLite since it needs cursed shit to do ALTER COLUMN)
|
||||
migrationBuilder.Sql("UPDATE round SET start_date = NULL WHERE start_date = '0001-01-01 00:00:00';");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,10 +796,8 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("server_id");
|
||||
|
||||
b.Property<DateTime>("StartDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
b.Property<DateTime?>("StartDate")
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValue(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified))
|
||||
.HasColumnName("start_date");
|
||||
|
||||
b.HasKey("Id")
|
||||
|
||||
@@ -118,10 +118,6 @@ namespace Content.Server.Database
|
||||
modelBuilder.Entity<Round>()
|
||||
.HasIndex(round => round.StartDate);
|
||||
|
||||
modelBuilder.Entity<Round>()
|
||||
.Property(round => round.StartDate)
|
||||
.HasDefaultValue(default(DateTime));
|
||||
|
||||
modelBuilder.Entity<AdminLogPlayer>()
|
||||
.HasKey(logPlayer => new {logPlayer.RoundId, logPlayer.LogId, logPlayer.PlayerUserId});
|
||||
|
||||
@@ -494,7 +490,7 @@ namespace Content.Server.Database
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
public List<Player> Players { get; set; } = default!;
|
||||
|
||||
|
||||
147
Content.Server/Administration/ServerApi.Utility.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Server.ServerStatus;
|
||||
|
||||
namespace Content.Server.Administration;
|
||||
|
||||
public sealed partial class ServerApi
|
||||
{
|
||||
private void RegisterHandler(HttpMethod method, string exactPath, Func<IStatusHandlerContext, Task> handler)
|
||||
{
|
||||
_statusHost.AddHandler(async context =>
|
||||
{
|
||||
if (context.RequestMethod != method || context.Url.AbsolutePath != exactPath)
|
||||
return false;
|
||||
|
||||
if (!await CheckAccess(context))
|
||||
return true;
|
||||
|
||||
await handler(context);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void RegisterActorHandler(HttpMethod method, string exactPath, Func<IStatusHandlerContext, Actor, Task> handler)
|
||||
{
|
||||
RegisterHandler(method, exactPath, async context =>
|
||||
{
|
||||
if (await CheckActor(context) is not { } actor)
|
||||
return;
|
||||
|
||||
await handler(context, actor);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Async helper function which runs a task on the main thread and returns the result.
|
||||
/// </summary>
|
||||
private async Task<T> RunOnMainThread<T>(Func<T> func)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<T>();
|
||||
_taskManager.RunOnMainThread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
taskCompletionSource.TrySetResult(func());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
taskCompletionSource.TrySetException(e);
|
||||
}
|
||||
});
|
||||
|
||||
var result = await taskCompletionSource.Task;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs an action on the main thread. This does not return any value and is meant to be used for void functions. Use <see cref="RunOnMainThread{T}"/> for functions that return a value.
|
||||
/// </summary>
|
||||
private async Task RunOnMainThread(Action action)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource();
|
||||
_taskManager.RunOnMainThread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
taskCompletionSource.TrySetResult();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
taskCompletionSource.TrySetException(e);
|
||||
}
|
||||
});
|
||||
|
||||
await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
private async Task RunOnMainThread(Func<Task> action)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource();
|
||||
// ReSharper disable once AsyncVoidLambda
|
||||
_taskManager.RunOnMainThread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await action();
|
||||
taskCompletionSource.TrySetResult();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
taskCompletionSource.TrySetException(e);
|
||||
}
|
||||
});
|
||||
|
||||
await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to read JSON encoded data from the request body.
|
||||
/// </summary>
|
||||
private static async Task<T?> ReadJson<T>(IStatusHandlerContext context) where T : notnull
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = await context.RequestBodyJsonAsync<T>();
|
||||
if (json == null)
|
||||
await RespondBadRequest(context, "Request body is null");
|
||||
|
||||
return json;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await RespondBadRequest(context, "Unable to parse request body", ExceptionData.FromException(e));
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RespondError(
|
||||
IStatusHandlerContext context,
|
||||
ErrorCode errorCode,
|
||||
HttpStatusCode statusCode,
|
||||
string message,
|
||||
ExceptionData? exception = null)
|
||||
{
|
||||
await context.RespondJsonAsync(new BaseResponse(message, errorCode, exception), statusCode)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task RespondBadRequest(
|
||||
IStatusHandlerContext context,
|
||||
string message,
|
||||
ExceptionData? exception = null)
|
||||
{
|
||||
await RespondError(context, ErrorCode.BadRequest, HttpStatusCode.BadRequest, message, exception)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task RespondOk(IStatusHandlerContext context)
|
||||
{
|
||||
await context.RespondJsonAsync(new BaseResponse("OK"))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string FormatLogActor(Actor actor) => $"{actor.Name} ({actor.Guid})";
|
||||
}
|
||||
711
Content.Server/Administration/ServerApi.cs
Normal file
@@ -0,0 +1,711 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Administration.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Presets;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Maps;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Prototypes;
|
||||
using Robust.Server.ServerStatus;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration;
|
||||
|
||||
/// <summary>
|
||||
/// Exposes various admin-related APIs via the game server's <see cref="StatusHost"/>.
|
||||
/// </summary>
|
||||
public sealed partial class ServerApi : IPostInjectInit
|
||||
{
|
||||
private const string SS14TokenScheme = "SS14Token";
|
||||
|
||||
private static readonly HashSet<string> PanicBunkerCVars =
|
||||
[
|
||||
CCVars.PanicBunkerEnabled.Name,
|
||||
CCVars.PanicBunkerDisableWithAdmins.Name,
|
||||
CCVars.PanicBunkerEnableWithoutAdmins.Name,
|
||||
CCVars.PanicBunkerCountDeadminnedAdmins.Name,
|
||||
CCVars.PanicBunkerShowReason.Name,
|
||||
CCVars.PanicBunkerMinAccountAge.Name,
|
||||
CCVars.PanicBunkerMinOverallHours.Name,
|
||||
CCVars.PanicBunkerCustomReason.Name,
|
||||
];
|
||||
|
||||
[Dependency] private readonly IStatusHost _statusHost = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly ISharedAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly IGameMapManager _gameMapManager = default!;
|
||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly ITaskManager _taskManager = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
|
||||
private string _token = string.Empty;
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_sawmill = _logManager.GetSawmill("serverApi");
|
||||
|
||||
// Get
|
||||
RegisterActorHandler(HttpMethod.Get, "/admin/info", InfoHandler);
|
||||
RegisterHandler(HttpMethod.Get, "/admin/game_rules", GetGameRules);
|
||||
RegisterHandler(HttpMethod.Get, "/admin/presets", GetPresets);
|
||||
|
||||
// Post
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/round/start", ActionRoundStart);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/round/end", ActionRoundEnd);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/round/restartnow", ActionRoundRestartNow);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/kick", ActionKick);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/add_game_rule", ActionAddGameRule);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/end_game_rule", ActionEndGameRule);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/force_preset", ActionForcePreset);
|
||||
RegisterActorHandler(HttpMethod.Post, "/admin/actions/set_motd", ActionForceMotd);
|
||||
RegisterActorHandler(HttpMethod.Patch, "/admin/actions/panic_bunker", ActionPanicPunker);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_config.OnValueChanged(CCVars.AdminApiToken, UpdateToken, true);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_config.UnsubValueChanged(CCVars.AdminApiToken, UpdateToken);
|
||||
}
|
||||
|
||||
private void UpdateToken(string token)
|
||||
{
|
||||
_token = token;
|
||||
}
|
||||
|
||||
|
||||
#region Actions
|
||||
|
||||
/// <summary>
|
||||
/// Changes the panic bunker settings.
|
||||
/// </summary>
|
||||
private async Task ActionPanicPunker(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var request = await ReadJson<JsonObject>(context);
|
||||
if (request == null)
|
||||
return;
|
||||
|
||||
var toSet = new Dictionary<string, object>();
|
||||
foreach (var (cVar, value) in request)
|
||||
{
|
||||
if (!PanicBunkerCVars.Contains(cVar))
|
||||
{
|
||||
await RespondBadRequest(context, $"Invalid panic bunker CVar: '{cVar}'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
await RespondBadRequest(context, $"Value is null: '{cVar}'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is not JsonValue jsonValue)
|
||||
{
|
||||
await RespondBadRequest(context, $"Value is not valid: '{cVar}'");
|
||||
return;
|
||||
}
|
||||
|
||||
object castValue;
|
||||
var cVarType = _config.GetCVarType(cVar);
|
||||
if (cVarType == typeof(bool))
|
||||
{
|
||||
if (!jsonValue.TryGetValue(out bool b))
|
||||
{
|
||||
await RespondBadRequest(context, $"CVar '{cVar}' must be of type bool.");
|
||||
return;
|
||||
}
|
||||
|
||||
castValue = b;
|
||||
}
|
||||
else if (cVarType == typeof(int))
|
||||
{
|
||||
if (!jsonValue.TryGetValue(out int i))
|
||||
{
|
||||
await RespondBadRequest(context, $"CVar '{cVar}' must be of type int.");
|
||||
return;
|
||||
}
|
||||
|
||||
castValue = i;
|
||||
}
|
||||
else if (cVarType == typeof(string))
|
||||
{
|
||||
if (!jsonValue.TryGetValue(out string? s))
|
||||
{
|
||||
await RespondBadRequest(context, $"CVar '{cVar}' must be of type string.");
|
||||
return;
|
||||
}
|
||||
|
||||
castValue = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Unsupported CVar type");
|
||||
}
|
||||
|
||||
toSet[cVar] = castValue;
|
||||
}
|
||||
|
||||
await RunOnMainThread(() =>
|
||||
{
|
||||
foreach (var (cVar, value) in toSet)
|
||||
{
|
||||
_config.SetCVar(cVar, value);
|
||||
_sawmill.Info(
|
||||
$"Panic bunker property '{cVar}' changed to '{value}' by {FormatLogActor(actor)}.");
|
||||
}
|
||||
});
|
||||
|
||||
await RespondOk(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current MOTD.
|
||||
/// </summary>
|
||||
private async Task ActionForceMotd(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var motd = await ReadJson<MotdActionBody>(context);
|
||||
if (motd == null)
|
||||
return;
|
||||
|
||||
_sawmill.Info($"MOTD changed to \"{motd.Motd}\" by {FormatLogActor(actor)}.");
|
||||
|
||||
await RunOnMainThread(() => _config.SetCVar(CCVars.MOTD, motd.Motd));
|
||||
// A hook in the MOTD system sends the changes to each client
|
||||
await RespondOk(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the next preset-
|
||||
/// </summary>
|
||||
private async Task ActionForcePreset(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var body = await ReadJson<PresetActionBody>(context);
|
||||
if (body == null)
|
||||
return;
|
||||
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.InvalidRoundState,
|
||||
HttpStatusCode.Conflict,
|
||||
"Game must be in pre-round lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
var preset = ticker.FindGamePreset(body.PresetId);
|
||||
if (preset == null)
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.GameRuleNotFound,
|
||||
HttpStatusCode.UnprocessableContent,
|
||||
$"Game rule '{body.PresetId}' doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
ticker.SetGamePreset(preset);
|
||||
_sawmill.Info($"Forced the game to start with preset {body.PresetId} by {FormatLogActor(actor)}.");
|
||||
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends an active game rule.
|
||||
/// </summary>
|
||||
private async Task ActionEndGameRule(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var body = await ReadJson<GameRuleActionBody>(context);
|
||||
if (body == null)
|
||||
return;
|
||||
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
var gameRule = ticker
|
||||
.GetActiveGameRules()
|
||||
.FirstOrNull(rule =>
|
||||
_entityManager.MetaQuery.GetComponent(rule).EntityPrototype?.ID == body.GameRuleId);
|
||||
|
||||
if (gameRule == null)
|
||||
{
|
||||
await RespondError(context,
|
||||
ErrorCode.GameRuleNotFound,
|
||||
HttpStatusCode.UnprocessableContent,
|
||||
$"Game rule '{body.GameRuleId}' not found or not active");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_sawmill.Info($"Ended game rule {body.GameRuleId} by {FormatLogActor(actor)}.");
|
||||
ticker.EndGameRule(gameRule.Value);
|
||||
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a game rule to the current round.
|
||||
/// </summary>
|
||||
private async Task ActionAddGameRule(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var body = await ReadJson<GameRuleActionBody>(context);
|
||||
if (body == null)
|
||||
return;
|
||||
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
if (!_prototypeManager.HasIndex<EntityPrototype>(body.GameRuleId))
|
||||
{
|
||||
await RespondError(context,
|
||||
ErrorCode.GameRuleNotFound,
|
||||
HttpStatusCode.UnprocessableContent,
|
||||
$"Game rule '{body.GameRuleId}' not found or not active");
|
||||
return;
|
||||
}
|
||||
|
||||
var ruleEntity = ticker.AddGameRule(body.GameRuleId);
|
||||
_sawmill.Info($"Added game rule {body.GameRuleId} by {FormatLogActor(actor)}.");
|
||||
if (ticker.RunLevel == GameRunLevel.InRound)
|
||||
{
|
||||
ticker.StartGameRule(ruleEntity);
|
||||
_sawmill.Info($"Started game rule {body.GameRuleId} by {FormatLogActor(actor)}.");
|
||||
}
|
||||
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kicks a player.
|
||||
/// </summary>
|
||||
private async Task ActionKick(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
var body = await ReadJson<KickActionBody>(context);
|
||||
if (body == null)
|
||||
return;
|
||||
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
if (!_playerManager.TryGetSessionById(new NetUserId(body.Guid), out var player))
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.PlayerNotFound,
|
||||
HttpStatusCode.UnprocessableContent,
|
||||
"Player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
var reason = body.Reason ?? "No reason supplied";
|
||||
reason += " (kicked by admin)";
|
||||
|
||||
_netManager.DisconnectChannel(player.Channel, reason);
|
||||
await RespondOk(context);
|
||||
|
||||
_sawmill.Info($"Kicked player {player.Name} ({player.UserId}) for {reason} by {FormatLogActor(actor)}");
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ActionRoundStart(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
|
||||
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.InvalidRoundState,
|
||||
HttpStatusCode.Conflict,
|
||||
"Round already started");
|
||||
return;
|
||||
}
|
||||
|
||||
ticker.StartRound();
|
||||
_sawmill.Info($"Forced round start by {FormatLogActor(actor)}");
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ActionRoundEnd(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var roundEndSystem = _entitySystemManager.GetEntitySystem<RoundEndSystem>();
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
|
||||
if (ticker.RunLevel != GameRunLevel.InRound)
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.InvalidRoundState,
|
||||
HttpStatusCode.Conflict,
|
||||
"Round is not active");
|
||||
return;
|
||||
}
|
||||
|
||||
roundEndSystem.EndRound();
|
||||
_sawmill.Info($"Forced round end by {FormatLogActor(actor)}");
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ActionRoundRestartNow(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
await RunOnMainThread(async () =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
|
||||
ticker.RestartRound();
|
||||
_sawmill.Info($"Forced instant round restart by {FormatLogActor(actor)}");
|
||||
await RespondOk(context);
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fetching
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array containing all available presets.
|
||||
/// </summary>
|
||||
private async Task GetPresets(IStatusHandlerContext context)
|
||||
{
|
||||
var presets = await RunOnMainThread(() =>
|
||||
{
|
||||
var presets = new List<PresetResponse.Preset>();
|
||||
|
||||
foreach (var preset in _prototypeManager.EnumeratePrototypes<GamePresetPrototype>())
|
||||
{
|
||||
presets.Add(new PresetResponse.Preset
|
||||
{
|
||||
Id = preset.ID,
|
||||
ModeTitle = _loc.GetString(preset.ModeTitle),
|
||||
Description = _loc.GetString(preset.Description)
|
||||
});
|
||||
}
|
||||
|
||||
return presets;
|
||||
});
|
||||
|
||||
await context.RespondJsonAsync(new PresetResponse
|
||||
{
|
||||
Presets = presets
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array containing all game rules.
|
||||
/// </summary>
|
||||
private async Task GetGameRules(IStatusHandlerContext context)
|
||||
{
|
||||
var gameRules = new List<string>();
|
||||
foreach (var gameRule in _prototypeManager.EnumeratePrototypes<EntityPrototype>())
|
||||
{
|
||||
if (gameRule.Abstract)
|
||||
continue;
|
||||
|
||||
if (gameRule.HasComponent<GameRuleComponent>(_componentFactory))
|
||||
gameRules.Add(gameRule.ID);
|
||||
}
|
||||
|
||||
await context.RespondJsonAsync(new GameruleResponse
|
||||
{
|
||||
GameRules = gameRules
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles fetching information.
|
||||
/// </summary>
|
||||
private async Task InfoHandler(IStatusHandlerContext context, Actor actor)
|
||||
{
|
||||
/*
|
||||
Information to display
|
||||
Round number
|
||||
Connected players
|
||||
Active admins
|
||||
Active game rules
|
||||
Active game preset
|
||||
Active map
|
||||
MOTD
|
||||
Panic bunker status
|
||||
*/
|
||||
|
||||
var info = await RunOnMainThread<InfoResponse>(() =>
|
||||
{
|
||||
var ticker = _entitySystemManager.GetEntitySystem<GameTicker>();
|
||||
var adminSystem = _entitySystemManager.GetEntitySystem<AdminSystem>();
|
||||
|
||||
var players = new List<InfoResponse.Player>();
|
||||
|
||||
foreach (var player in _playerManager.Sessions)
|
||||
{
|
||||
var adminData = _adminManager.GetAdminData(player, true);
|
||||
|
||||
players.Add(new InfoResponse.Player
|
||||
{
|
||||
UserId = player.UserId.UserId,
|
||||
Name = player.Name,
|
||||
IsAdmin = adminData != null,
|
||||
IsDeadminned = !adminData?.Active ?? false
|
||||
});
|
||||
}
|
||||
|
||||
InfoResponse.MapInfo? mapInfo = null;
|
||||
if (_gameMapManager.GetSelectedMap() is { } mapPrototype)
|
||||
{
|
||||
mapInfo = new InfoResponse.MapInfo
|
||||
{
|
||||
Id = mapPrototype.ID,
|
||||
Name = mapPrototype.MapName
|
||||
};
|
||||
}
|
||||
|
||||
var gameRules = new List<string>();
|
||||
foreach (var addedGameRule in ticker.GetActiveGameRules())
|
||||
{
|
||||
var meta = _entityManager.MetaQuery.GetComponent(addedGameRule);
|
||||
gameRules.Add(meta.EntityPrototype?.ID ?? meta.EntityPrototype?.Name ?? "Unknown");
|
||||
}
|
||||
|
||||
var panicBunkerCVars = PanicBunkerCVars.ToDictionary(c => c, c => _config.GetCVar(c));
|
||||
return new InfoResponse
|
||||
{
|
||||
Players = players,
|
||||
RoundId = ticker.RoundId,
|
||||
Map = mapInfo,
|
||||
PanicBunker = panicBunkerCVars,
|
||||
GamePreset = ticker.CurrentPreset?.ID,
|
||||
GameRules = gameRules,
|
||||
MOTD = _config.GetCVar(CCVars.MOTD)
|
||||
};
|
||||
});
|
||||
|
||||
await context.RespondJsonAsync(info);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task<bool> CheckAccess(IStatusHandlerContext context)
|
||||
{
|
||||
var auth = context.RequestHeaders.TryGetValue("Authorization", out var authToken);
|
||||
if (!auth)
|
||||
{
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.AuthenticationNeeded,
|
||||
HttpStatusCode.Unauthorized,
|
||||
"Authorization is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
var authHeaderValue = authToken.ToString();
|
||||
var spaceIndex = authHeaderValue.IndexOf(' ');
|
||||
if (spaceIndex == -1)
|
||||
{
|
||||
await RespondBadRequest(context, "Invalid Authorization header value");
|
||||
return false;
|
||||
}
|
||||
|
||||
var authScheme = authHeaderValue[..spaceIndex];
|
||||
var authValue = authHeaderValue[spaceIndex..].Trim();
|
||||
|
||||
if (authScheme != SS14TokenScheme)
|
||||
{
|
||||
await RespondBadRequest(context, "Invalid Authorization scheme");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_token == "")
|
||||
{
|
||||
_sawmill.Debug("No authorization token set for admin API");
|
||||
}
|
||||
else if (CryptographicOperations.FixedTimeEquals(
|
||||
Encoding.UTF8.GetBytes(authValue),
|
||||
Encoding.UTF8.GetBytes(_token)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
await RespondError(
|
||||
context,
|
||||
ErrorCode.AuthenticationInvalid,
|
||||
HttpStatusCode.Unauthorized,
|
||||
"Authorization is invalid");
|
||||
|
||||
// Invalid auth header, no access
|
||||
_sawmill.Info($"Unauthorized access attempt to admin API from {context.RemoteEndPoint}");
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<Actor?> CheckActor(IStatusHandlerContext context)
|
||||
{
|
||||
// The actor is JSON encoded in the header
|
||||
var actor = context.RequestHeaders.TryGetValue("Actor", out var actorHeader) ? actorHeader.ToString() : null;
|
||||
if (actor == null)
|
||||
{
|
||||
await RespondBadRequest(context, "Actor must be supplied");
|
||||
return null;
|
||||
}
|
||||
|
||||
Actor? actorData;
|
||||
try
|
||||
{
|
||||
actorData = JsonSerializer.Deserialize<Actor>(actor);
|
||||
if (actorData == null)
|
||||
{
|
||||
await RespondBadRequest(context, "Actor is null");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (JsonException exception)
|
||||
{
|
||||
await RespondBadRequest(context, "Actor field JSON is invalid", ExceptionData.FromException(exception));
|
||||
return null;
|
||||
}
|
||||
|
||||
return actorData;
|
||||
}
|
||||
|
||||
#region From Client
|
||||
|
||||
private sealed class Actor
|
||||
{
|
||||
public required Guid Guid { get; init; }
|
||||
public required string Name { get; init; }
|
||||
}
|
||||
|
||||
private sealed class KickActionBody
|
||||
{
|
||||
public required Guid Guid { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
|
||||
private sealed class GameRuleActionBody
|
||||
{
|
||||
public required string GameRuleId { get; init; }
|
||||
}
|
||||
|
||||
private sealed class PresetActionBody
|
||||
{
|
||||
public required string PresetId { get; init; }
|
||||
}
|
||||
|
||||
private sealed class MotdActionBody
|
||||
{
|
||||
public required string Motd { get; init; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Responses
|
||||
|
||||
private record BaseResponse(
|
||||
string Message,
|
||||
ErrorCode ErrorCode = ErrorCode.None,
|
||||
ExceptionData? Exception = null);
|
||||
|
||||
private record ExceptionData(string Message, string? StackTrace = null)
|
||||
{
|
||||
public static ExceptionData FromException(Exception e)
|
||||
{
|
||||
return new ExceptionData(e.Message, e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private enum ErrorCode
|
||||
{
|
||||
None = 0,
|
||||
AuthenticationNeeded = 1,
|
||||
AuthenticationInvalid = 2,
|
||||
InvalidRoundState = 3,
|
||||
PlayerNotFound = 4,
|
||||
GameRuleNotFound = 5,
|
||||
BadRequest = 6,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc
|
||||
|
||||
/// <summary>
|
||||
/// Record used to send the response for the info endpoint.
|
||||
/// </summary>
|
||||
private sealed class InfoResponse
|
||||
{
|
||||
public required int RoundId { get; init; }
|
||||
public required List<Player> Players { get; init; }
|
||||
public required List<string> GameRules { get; init; }
|
||||
public required string? GamePreset { get; init; }
|
||||
public required MapInfo? Map { get; init; }
|
||||
public required string? MOTD { get; init; }
|
||||
public required Dictionary<string, object> PanicBunker { get; init; }
|
||||
|
||||
public sealed class Player
|
||||
{
|
||||
public required Guid UserId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public required bool IsAdmin { get; init; }
|
||||
public required bool IsDeadminned { get; init; }
|
||||
}
|
||||
|
||||
public sealed class MapInfo
|
||||
{
|
||||
public required string Id { get; init; }
|
||||
public required string Name { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class PresetResponse
|
||||
{
|
||||
public required List<Preset> Presets { get; init; }
|
||||
|
||||
public sealed class Preset
|
||||
{
|
||||
public required string Id { get; init; }
|
||||
public required string Description { get; init; }
|
||||
public required string ModeTitle { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class GameruleResponse
|
||||
{
|
||||
public required List<string> GameRules { get; init; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace Content.Server.Administration.Systems
|
||||
public IReadOnlySet<NetUserId> RoundActivePlayers => _roundActivePlayers;
|
||||
|
||||
private readonly HashSet<NetUserId> _roundActivePlayers = new();
|
||||
private readonly PanicBunkerStatus _panicBunker = new();
|
||||
public readonly PanicBunkerStatus PanicBunker = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -240,7 +240,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
private void OnPanicBunkerChanged(bool enabled)
|
||||
{
|
||||
_panicBunker.Enabled = enabled;
|
||||
PanicBunker.Enabled = enabled;
|
||||
_chat.SendAdminAlert(Loc.GetString(enabled
|
||||
? "admin-ui-panic-bunker-enabled-admin-alert"
|
||||
: "admin-ui-panic-bunker-disabled-admin-alert"
|
||||
@@ -251,52 +251,52 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
private void OnPanicBunkerDisableWithAdminsChanged(bool enabled)
|
||||
{
|
||||
_panicBunker.DisableWithAdmins = enabled;
|
||||
PanicBunker.DisableWithAdmins = enabled;
|
||||
UpdatePanicBunker();
|
||||
}
|
||||
|
||||
private void OnPanicBunkerEnableWithoutAdminsChanged(bool enabled)
|
||||
{
|
||||
_panicBunker.EnableWithoutAdmins = enabled;
|
||||
PanicBunker.EnableWithoutAdmins = enabled;
|
||||
UpdatePanicBunker();
|
||||
}
|
||||
|
||||
private void OnPanicBunkerCountDeadminnedAdminsChanged(bool enabled)
|
||||
{
|
||||
_panicBunker.CountDeadminnedAdmins = enabled;
|
||||
PanicBunker.CountDeadminnedAdmins = enabled;
|
||||
UpdatePanicBunker();
|
||||
}
|
||||
|
||||
private void OnShowReasonChanged(bool enabled)
|
||||
{
|
||||
_panicBunker.ShowReason = enabled;
|
||||
PanicBunker.ShowReason = enabled;
|
||||
SendPanicBunkerStatusAll();
|
||||
}
|
||||
|
||||
private void OnPanicBunkerMinAccountAgeChanged(int minutes)
|
||||
{
|
||||
_panicBunker.MinAccountAgeHours = minutes / 60;
|
||||
PanicBunker.MinAccountAgeHours = minutes / 60;
|
||||
SendPanicBunkerStatusAll();
|
||||
}
|
||||
|
||||
private void OnPanicBunkerMinOverallHoursChanged(int hours)
|
||||
{
|
||||
_panicBunker.MinOverallHours = hours;
|
||||
PanicBunker.MinOverallHours = hours;
|
||||
SendPanicBunkerStatusAll();
|
||||
}
|
||||
|
||||
private void UpdatePanicBunker()
|
||||
{
|
||||
var admins = _panicBunker.CountDeadminnedAdmins
|
||||
var admins = PanicBunker.CountDeadminnedAdmins
|
||||
? _adminManager.AllAdmins
|
||||
: _adminManager.ActiveAdmins;
|
||||
var hasAdmins = admins.Any();
|
||||
|
||||
if (hasAdmins && _panicBunker.DisableWithAdmins)
|
||||
if (hasAdmins && PanicBunker.DisableWithAdmins)
|
||||
{
|
||||
_config.SetCVar(CCVars.PanicBunkerEnabled, false);
|
||||
}
|
||||
else if (!hasAdmins && _panicBunker.EnableWithoutAdmins)
|
||||
else if (!hasAdmins && PanicBunker.EnableWithoutAdmins)
|
||||
{
|
||||
_config.SetCVar(CCVars.PanicBunkerEnabled, true);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
private void SendPanicBunkerStatusAll()
|
||||
{
|
||||
var ev = new PanicBunkerChangedEvent(_panicBunker);
|
||||
var ev = new PanicBunkerChangedEvent(PanicBunker);
|
||||
foreach (var admin in _adminManager.AllAdmins)
|
||||
{
|
||||
RaiseNetworkEvent(ev, admin);
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Server.CrystallPunk.Temperature;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Mobs;
|
||||
|
||||
namespace Content.Server.Audio;
|
||||
|
||||
|
||||
@@ -225,13 +225,16 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
if (!TryComp<StationRecordsComponent>(station, out var stationRecords))
|
||||
return;
|
||||
|
||||
var key = new StationRecordKey(_stationRecords.GetRecordByName(station.Value, name) ?? default(uint), station.Value);
|
||||
var jobName = "Unknown";
|
||||
var jobName = Loc.GetString("earlyleave-cryo-job-unknown");
|
||||
var recordId = _stationRecords.GetRecordByName(station.Value, name);
|
||||
if (recordId != null)
|
||||
{
|
||||
var key = new StationRecordKey(recordId.Value, station.Value);
|
||||
if (_stationRecords.TryGetRecord<GeneralStationRecord>(key, out var entry, stationRecords))
|
||||
jobName = entry.JobTitle;
|
||||
|
||||
if (_stationRecords.TryGetRecord<GeneralStationRecord>(key, out var entry, stationRecords))
|
||||
jobName = entry.JobTitle;
|
||||
|
||||
_stationRecords.RemoveRecord(key, stationRecords);
|
||||
_stationRecords.RemoveRecord(key, stationRecords);
|
||||
}
|
||||
|
||||
_chatSystem.DispatchStationAnnouncement(station.Value,
|
||||
Loc.GetString(
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Server.StationRecords.Systems;
|
||||
using Content.Shared.CriminalRecords;
|
||||
using Content.Shared.Security;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server.GameTicking;
|
||||
|
||||
namespace Content.Server.CriminalRecords.Systems;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Content.Server.CriminalRecords.Systems;
|
||||
/// </summary>
|
||||
public sealed class CriminalRecordsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly GameTicker _ticker = default!;
|
||||
[Dependency] private readonly StationRecordsSystem _stationRecords = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -71,7 +71,7 @@ public sealed class CriminalRecordsSystem : EntitySystem
|
||||
/// </summary>
|
||||
public bool TryAddHistory(StationRecordKey key, string line)
|
||||
{
|
||||
var entry = new CrimeHistory(_timing.CurTime, line);
|
||||
var entry = new CrimeHistory(_ticker.RoundDuration(), line);
|
||||
return TryAddHistory(key, entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,6 @@ public sealed record PlayerRecord(
|
||||
IPAddress LastSeenAddress,
|
||||
ImmutableArray<byte>? HWId);
|
||||
|
||||
public sealed record RoundRecord(int Id, DateTimeOffset StartDate, ServerRecord Server);
|
||||
public sealed record RoundRecord(int Id, DateTimeOffset? StartDate, ServerRecord Server);
|
||||
|
||||
public sealed record ServerRecord(int Id, string Name);
|
||||
|
||||
@@ -696,7 +696,7 @@ namespace Content.Server.Database
|
||||
await db.DbContext.SaveChangesAsync(cancel);
|
||||
}
|
||||
|
||||
public virtual async Task<int> AddNewRound(Server server, params Guid[] playerIds)
|
||||
public async Task<int> AddNewRound(Server server, params Guid[] playerIds)
|
||||
{
|
||||
await using var db = await GetDb();
|
||||
|
||||
|
||||
@@ -452,34 +452,6 @@ namespace Content.Server.Database
|
||||
return (admins.Select(p => (p.a, p.LastSeenUserName)).ToArray(), adminRanks)!;
|
||||
}
|
||||
|
||||
public override async Task<int> AddNewRound(Server server, params Guid[] playerIds)
|
||||
{
|
||||
await using var db = await GetDb();
|
||||
|
||||
var players = await db.DbContext.Player
|
||||
.Where(player => playerIds.Contains(player.UserId))
|
||||
.ToListAsync();
|
||||
|
||||
var nextId = 1;
|
||||
if (await db.DbContext.Round.AnyAsync())
|
||||
{
|
||||
nextId = db.DbContext.Round.Max(round => round.Id) + 1;
|
||||
}
|
||||
|
||||
var round = new Round
|
||||
{
|
||||
Id = nextId,
|
||||
Players = players,
|
||||
ServerId = server.Id
|
||||
};
|
||||
|
||||
db.DbContext.Round.Add(round);
|
||||
|
||||
await db.DbContext.SaveChangesAsync();
|
||||
|
||||
return round.Id;
|
||||
}
|
||||
|
||||
protected override IQueryable<AdminLog> StartAdminLogsQuery(ServerDbContext db, LogFilter? filter = null)
|
||||
{
|
||||
IQueryable<AdminLog> query = db.AdminLog;
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Content.Server.Entry
|
||||
IoCManager.Resolve<ContentNetworkResourceManager>().Initialize();
|
||||
IoCManager.Resolve<GhostKickManager>().Initialize();
|
||||
IoCManager.Resolve<ServerInfoManager>().Initialize();
|
||||
IoCManager.Resolve<ServerApi>().Initialize();
|
||||
|
||||
_voteManager.Initialize();
|
||||
_updateManager.Initialize();
|
||||
@@ -167,6 +168,7 @@ namespace Content.Server.Entry
|
||||
{
|
||||
_playTimeTracking?.Shutdown();
|
||||
_dbManager?.Shutdown();
|
||||
IoCManager.Resolve<ServerApi>().Shutdown();
|
||||
}
|
||||
|
||||
private static void LoadConfigPresets(IConfigurationManager cfg, IResourceManager res, ISawmill sawmill)
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Content.Server.IoC
|
||||
IoCManager.Register<PoissonDiskSampler>();
|
||||
IoCManager.Register<DiscordWebhook>();
|
||||
IoCManager.Register<ServerDbEntryManager>();
|
||||
IoCManager.Register<ServerApi>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Kitchen.Components;
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Database;
|
||||
@@ -11,9 +13,14 @@ using Content.Shared.Storage;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Kitchen;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -35,7 +42,7 @@ public sealed class SharpSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SharpComponent, AfterInteractEvent>(OnAfterInteract, before: new[] { typeof(UtensilSystem) });
|
||||
SubscribeLocalEvent<SharpComponent, AfterInteractEvent>(OnAfterInteract, before: [typeof(UtensilSystem)]);
|
||||
SubscribeLocalEvent<SharpComponent, SharpDoAfterEvent>(OnDoAfter);
|
||||
|
||||
SubscribeLocalEvent<ButcherableComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
|
||||
@@ -43,16 +50,14 @@ public sealed class SharpSystem : EntitySystem
|
||||
|
||||
private void OnAfterInteract(EntityUid uid, SharpComponent component, AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
if (args.Handled || args.Target is null || !args.CanReach)
|
||||
return;
|
||||
|
||||
if (args.Target is null || !args.CanReach)
|
||||
return;
|
||||
|
||||
args.Handled = TryStartButcherDoAfter(uid, args.Target.Value, args.User);
|
||||
if (TryStartButcherDoafter(uid, args.Target.Value, args.User))
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private bool TryStartButcherDoAfter(EntityUid knife, EntityUid target, EntityUid user)
|
||||
private bool TryStartButcherDoafter(EntityUid knife, EntityUid target, EntityUid user)
|
||||
{
|
||||
if (!TryComp<ButcherableComponent>(target, out var butcher))
|
||||
return false;
|
||||
@@ -66,11 +71,11 @@ public sealed class SharpSystem : EntitySystem
|
||||
if (butcher.Type != ButcheringType.Knife && target != user)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("butcherable-different-tool", ("target", target)), knife, user);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sharp.Butchering.Add(target))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
var doAfter =
|
||||
new DoAfterArgs(EntityManager, user, sharp.ButcherDelayModifier * butcher.ButcherDelay, new SharpDoAfterEvent(), knife, target: target, used: knife)
|
||||
@@ -165,7 +170,7 @@ public sealed class SharpSystem : EntitySystem
|
||||
Act = () =>
|
||||
{
|
||||
if (!disabled)
|
||||
TryStartButcherDoAfter(args.Using!.Value, args.Target, args.User);
|
||||
TryStartButcherDoafter(args.Using!.Value, args.Target, args.User);
|
||||
},
|
||||
Message = message,
|
||||
Disabled = disabled,
|
||||
|
||||
@@ -84,10 +84,7 @@ namespace Content.Server.Labels
|
||||
{
|
||||
_itemSlotsSystem.AddItemSlot(uid, ContainerName, component.LabelSlot);
|
||||
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, PaperLabelVisuals.HasLabel, false, appearance);
|
||||
UpdateAppearance((uid, component));
|
||||
}
|
||||
|
||||
private void OnComponentRemove(EntityUid uid, PaperLabelComponent component, ComponentRemove args)
|
||||
@@ -131,10 +128,18 @@ namespace Content.Server.Labels
|
||||
if (args.Container.ID != label.LabelSlot.ID)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
UpdateAppearance((uid, label));
|
||||
}
|
||||
|
||||
private void UpdateAppearance(Entity<PaperLabelComponent, AppearanceComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp2, false))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, PaperLabelVisuals.HasLabel, label.LabelSlot.HasItem, appearance);
|
||||
var slot = ent.Comp1.LabelSlot;
|
||||
_appearance.SetData(ent, PaperLabelVisuals.HasLabel, slot.HasItem, ent.Comp2);
|
||||
if (TryComp<PaperLabelTypeComponent>(slot.Item, out var type))
|
||||
_appearance.SetData(ent, PaperLabelVisuals.LabelType, type.PaperType, ent.Comp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
@@ -34,10 +33,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
/// </summary>
|
||||
private void OnAfterInteract(EntityUid uid, UtensilComponent component, AfterInteractEvent ev)
|
||||
{
|
||||
if (ev.Handled)
|
||||
return;
|
||||
|
||||
if (ev.Target == null || !ev.CanReach)
|
||||
if (ev.Handled || ev.Target == null || !ev.CanReach)
|
||||
return;
|
||||
|
||||
var result = TryUseUtensil(ev.User, ev.Target.Value, component);
|
||||
|
||||
@@ -126,5 +126,10 @@ namespace Content.Server.Popups
|
||||
RaiseNetworkEvent(new PopupEntityEvent(message, type, GetNetEntity(uid)));
|
||||
}
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
PopupPredicted(othersMessage, uid, recipient, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
|
||||
|
||||
SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
|
||||
SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
|
||||
|
||||
SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Server.Station.Systems;
|
||||
|
||||
namespace Content.Server.Station.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores station parameters that can be randomized by the roundstart
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(StationSystem))]
|
||||
public sealed partial class StationRandomTransformComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float? MaxStationOffset = 100.0f;
|
||||
|
||||
[DataField]
|
||||
public bool EnableStationRotation = true;
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Events;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Fax;
|
||||
using Content.Shared.Station;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -49,17 +50,12 @@ public sealed class StationSystem : EntitySystem
|
||||
_sawmill = _logManager.GetSawmill("station");
|
||||
|
||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRoundEnd);
|
||||
SubscribeLocalEvent<PreGameMapLoad>(OnPreGameMapLoad);
|
||||
SubscribeLocalEvent<PostGameMapLoad>(OnPostGameMapLoad);
|
||||
SubscribeLocalEvent<StationDataComponent, ComponentStartup>(OnStationAdd);
|
||||
SubscribeLocalEvent<StationDataComponent, ComponentShutdown>(OnStationDeleted);
|
||||
SubscribeLocalEvent<StationMemberComponent, ComponentShutdown>(OnStationGridDeleted);
|
||||
SubscribeLocalEvent<StationMemberComponent, PostGridSplitEvent>(OnStationSplitEvent);
|
||||
|
||||
Subs.CVar(_configurationManager, CCVars.StationOffset, x => _randomStationOffset = x, true);
|
||||
Subs.CVar(_configurationManager, CCVars.MaxStationOffset, x => _maxRandomStationOffset = x, true);
|
||||
Subs.CVar(_configurationManager, CCVars.StationRotation, x => _randomStationRotation = x, true);
|
||||
|
||||
_player.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
@@ -112,19 +108,6 @@ public sealed class StationSystem : EntitySystem
|
||||
RaiseNetworkEvent(new StationsUpdatedEvent(GetStationNames()), Filter.Broadcast());
|
||||
}
|
||||
|
||||
private void OnPreGameMapLoad(PreGameMapLoad ev)
|
||||
{
|
||||
// this is only for maps loaded during round setup!
|
||||
if (_gameTicker.RunLevel == GameRunLevel.InRound)
|
||||
return;
|
||||
|
||||
if (_randomStationOffset)
|
||||
ev.Options.Offset += _random.NextVector2(_maxRandomStationOffset);
|
||||
|
||||
if (_randomStationRotation)
|
||||
ev.Options.Rotation = _random.NextAngle();
|
||||
}
|
||||
|
||||
private void OnPostGameMapLoad(PostGameMapLoad ev)
|
||||
{
|
||||
var dict = new Dictionary<string, List<EntityUid>>();
|
||||
@@ -311,6 +294,8 @@ public sealed class StationSystem : EntitySystem
|
||||
// Use overrides for setup.
|
||||
var station = EntityManager.SpawnEntity(stationConfig.StationPrototype, MapCoordinates.Nullspace, stationConfig.StationComponentOverrides);
|
||||
|
||||
|
||||
|
||||
if (name is not null)
|
||||
RenameStation(station, name, false);
|
||||
|
||||
@@ -319,11 +304,48 @@ public sealed class StationSystem : EntitySystem
|
||||
var data = Comp<StationDataComponent>(station);
|
||||
name ??= MetaData(station).EntityName;
|
||||
|
||||
foreach (var grid in gridIds ?? Array.Empty<EntityUid>())
|
||||
var entry = gridIds ?? Array.Empty<EntityUid>();
|
||||
|
||||
foreach (var grid in entry)
|
||||
{
|
||||
AddGridToStation(station, grid, null, data, name);
|
||||
}
|
||||
|
||||
if (TryComp<StationRandomTransformComponent>(station, out var random))
|
||||
{
|
||||
Angle? rotation = null;
|
||||
Vector2? offset = null;
|
||||
|
||||
if (random.MaxStationOffset != null)
|
||||
offset = _random.NextVector2(-random.MaxStationOffset.Value, random.MaxStationOffset.Value);
|
||||
|
||||
if (random.EnableStationRotation)
|
||||
rotation = _random.NextAngle();
|
||||
|
||||
foreach (var grid in entry)
|
||||
{
|
||||
//planetary maps give an error when trying to change from position or rotation.
|
||||
//This is still the case, but it will be irrelevant after the https://github.com/space-wizards/space-station-14/pull/26510
|
||||
if (rotation != null && offset != null)
|
||||
{
|
||||
var pos = _transform.GetWorldPosition(grid);
|
||||
_transform.SetWorldPositionRotation(grid, pos + offset.Value, rotation.Value);
|
||||
continue;
|
||||
}
|
||||
if (rotation != null)
|
||||
{
|
||||
_transform.SetWorldRotation(grid, rotation.Value);
|
||||
continue;
|
||||
}
|
||||
if (offset != null)
|
||||
{
|
||||
var pos = _transform.GetWorldPosition(grid);
|
||||
_transform.SetWorldPosition(grid, pos + offset.Value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ev = new StationPostInitEvent((station, data));
|
||||
RaiseLocalEvent(station, ref ev, true);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Mobs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
@@ -12,6 +13,7 @@ public abstract class SharedAmbientSoundSystem : EntitySystem
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<AmbientSoundComponent, ComponentGetState>(GetCompState);
|
||||
SubscribeLocalEvent<AmbientSoundComponent, ComponentHandleState>(HandleCompState);
|
||||
|
||||
_query = GetEntityQuery<AmbientSoundComponent>();
|
||||
}
|
||||
|
||||
|
||||
10
Content.Shared/Audio/SoundWhileAliveComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Content.Shared.Sound.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Audio;
|
||||
|
||||
/// <summary>
|
||||
/// Toggles <see cref="AmbientSoundComponent"/> and <see cref="SpamEmitSoundComponent"/> off when this entity's MobState isn't Alive.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class SoundWhileAliveComponent : Component;
|
||||
@@ -116,8 +116,9 @@ public sealed class BurialSystem : EntitySystem
|
||||
{
|
||||
if (used != null)
|
||||
{
|
||||
_popupSystem.PopupClient(Loc.GetString("grave-start-digging-user", ("grave", uid), ("tool", used)), user, user);
|
||||
_popupSystem.PopupEntity(Loc.GetString("grave-start-digging-others", ("user", user), ("grave", uid), ("tool", used)), user, Filter.PvsExcept(user), true);
|
||||
var selfMessage = Loc.GetString("grave-start-digging-user", ("grave", uid), ("tool", used));
|
||||
var othersMessage = Loc.GetString("grave-start-digging-others", ("user", user), ("grave", uid), ("tool", used));
|
||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
|
||||
component.ActiveShovelDigging = true;
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
@@ -229,25 +229,6 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<bool>
|
||||
GameCryoSleepRejoining = CVarDef.Create("game.cryo_sleep_rejoining", false, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a random position offset will be applied to the station on roundstart.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> StationOffset =
|
||||
CVarDef.Create("game.station_offset", true);
|
||||
|
||||
/// <summary>
|
||||
/// When the default blueprint is loaded what is the maximum amount it can be offset from 0,0.
|
||||
/// Does nothing without <see cref="StationOffset"/> as true.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> MaxStationOffset =
|
||||
CVarDef.Create("game.maxstationoffset", 1000.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a random rotation will be applied to the station on roundstart.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> StationRotation =
|
||||
CVarDef.Create("game.station_rotation", true);
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
|
||||
/// </summary>
|
||||
@@ -776,6 +757,13 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<bool> AdminAnnounceLogout =
|
||||
CVarDef.Create("admin.announce_logout", true, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The token used to authenticate with the admin API. Leave empty to disable the admin API. This is a secret! Do not share!
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> AdminApiToken =
|
||||
CVarDef.Create("admin.api_token", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should users be able to see their own notes? Admins will be able to see and set notes regardless
|
||||
/// </summary>
|
||||
|
||||
@@ -57,9 +57,11 @@ public sealed partial class BonkSystem : EntitySystem
|
||||
if (user == source)
|
||||
{
|
||||
// Non-local, non-bonking players
|
||||
_popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, Filter.PvsExcept(user), true);
|
||||
var othersMessage = Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName));
|
||||
// Local, bonking player
|
||||
_popupSystem.PopupClient(Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName)), user, user);
|
||||
var selfMessage = Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName));
|
||||
|
||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
|
||||
}
|
||||
else if (source != null)
|
||||
{
|
||||
|
||||
@@ -307,8 +307,7 @@ public sealed partial class ClimbSystem : VirtualController
|
||||
("climbable", climbable));
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(othersMessage, uid, Filter.PvsExcept(user, entityManager: EntityManager), true);
|
||||
_popupSystem.PopupClient(selfMessage, uid, user);
|
||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, uid, user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Shared.Clothing.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Defines something as causing waddling when worn.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class WaddleWhenWornComponent : Component
|
||||
{
|
||||
///<summary>
|
||||
/// How high should they hop during the waddle? Higher hop = more energy.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 HopIntensity = new(0, 0.25f);
|
||||
|
||||
/// <summary>
|
||||
/// How far should they rock backward and forward during the waddle?
|
||||
/// Each step will alternate between this being a positive and negative rotation. More rock = more scary.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TumbleIntensity = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How long should a complete step take? Less time = more chaos.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float AnimationLength = 0.66f;
|
||||
|
||||
/// <summary>
|
||||
/// How much shorter should the animation be when running?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float RunAnimationLengthMultiplier = 0.568f;
|
||||
}
|
||||
16
Content.Shared/Labels/Components/PaperLabelTypeComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Labels.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the paper type (see textures/storage/crates/labels.rsi to see currently supported paper types) to show on crates this label is attached to.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class PaperLabelTypeComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of label to show.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string PaperType = "Paper";
|
||||
}
|
||||
@@ -13,9 +13,11 @@ namespace Content.Shared.Labels
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum PaperLabelVisuals
|
||||
public enum PaperLabelVisuals : byte
|
||||
{
|
||||
Layer,
|
||||
HasLabel,
|
||||
LabelType
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Shared.Movement.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Declares that an entity has started to waddle like a duck/clown.
|
||||
/// </summary>
|
||||
/// <param name="Entity">The newly be-waddled.</param>
|
||||
[ByRefEvent]
|
||||
public record struct StartedWaddlingEvent(EntityUid Entity)
|
||||
{
|
||||
public EntityUid Entity = Entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares that an entity has stopped waddling like a duck/clown.
|
||||
/// </summary>
|
||||
/// <param name="Entity">The former waddle-er.</param>
|
||||
[ByRefEvent]
|
||||
public record struct StoppedWaddlingEvent(EntityUid Entity)
|
||||
{
|
||||
public EntityUid Entity = Entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines something as having a waddle animation when it moves.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class WaddleAnimationComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What's the name of this animation? Make sure it's unique so it can play along side other animations.
|
||||
/// This prevents someone accidentally causing two identical waddling effects to play on someone at the same time.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string KeyName = "Waddle";
|
||||
|
||||
///<summary>
|
||||
/// How high should they hop during the waddle? Higher hop = more energy.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 HopIntensity = new(0, 0.25f);
|
||||
|
||||
/// <summary>
|
||||
/// How far should they rock backward and forward during the waddle?
|
||||
/// Each step will alternate between this being a positive and negative rotation. More rock = more scary.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TumbleIntensity = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How long should a complete step take? Less time = more chaos.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float AnimationLength = 0.66f;
|
||||
|
||||
/// <summary>
|
||||
/// How much shorter should the animation be when running?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float RunAnimationLengthMultiplier = 0.568f;
|
||||
|
||||
/// <summary>
|
||||
/// Stores which step we made last, so if someone cancels out of the animation mid-step then restarts it looks more natural.
|
||||
/// </summary>
|
||||
public bool LastStep;
|
||||
|
||||
/// <summary>
|
||||
/// Stores if we're currently waddling so we can start/stop as appropriate and can tell other systems our state.
|
||||
/// </summary>
|
||||
public bool IsCurrentlyWaddling;
|
||||
}
|
||||
@@ -94,6 +94,12 @@ namespace Content.Shared.Popups
|
||||
/// will do nothing and the server will show the message to every player in PVS range.
|
||||
/// </summary>
|
||||
public abstract void PopupPredicted(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small);
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="PopupPredicted(string?, EntityUid, EntityUid?, PopupType)"/> that displays <paramref name="recipientMessage"/>
|
||||
/// to the recipient and <paramref name="othersMessage"/> to everyone else in PVS range.
|
||||
/// </summary>
|
||||
public abstract void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -230,13 +230,19 @@ public class RCDSystem : EntitySystem
|
||||
|
||||
// Exit if the RCD prototype has changed
|
||||
if (component.ProtoId != args.Event.StartingProtoId)
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the RCD operation is still valid
|
||||
var location = GetCoordinates(args.Event.Location);
|
||||
|
||||
if (!TryGetMapGridData(location, out var mapGridData))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsRCDOperationStillValid(uid, component, mapGridData.Value, args.Event.Target, args.Event.User))
|
||||
args.Cancel();
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Sound.Components;
|
||||
using Content.Shared.Throwing;
|
||||
@@ -28,7 +31,8 @@ public abstract class SharedEmitSoundSystem : EntitySystem
|
||||
[Dependency] private readonly INetManager _netMan = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
||||
[Dependency] protected readonly IRobustRandom Random = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambient = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -44,6 +48,20 @@ public abstract class SharedEmitSoundSystem : EntitySystem
|
||||
SubscribeLocalEvent<EmitSoundOnInteractUsingComponent, InteractUsingEvent>(OnEmitSoundOnInteractUsing);
|
||||
|
||||
SubscribeLocalEvent<EmitSoundOnCollideComponent, StartCollideEvent>(OnEmitSoundOnCollide);
|
||||
|
||||
SubscribeLocalEvent<SoundWhileAliveComponent, MobStateChangedEvent>(OnMobState);
|
||||
}
|
||||
|
||||
private void OnMobState(Entity<SoundWhileAliveComponent> entity, ref MobStateChangedEvent args)
|
||||
{
|
||||
// Disable this component rather than removing it because it can be brought back to life.
|
||||
if (TryComp<SpamEmitSoundComponent>(entity, out var comp))
|
||||
{
|
||||
comp.Enabled = args.NewMobState == MobState.Alive;
|
||||
Dirty(entity.Owner, comp);
|
||||
}
|
||||
|
||||
_ambient.SetAmbience(entity.Owner, args.NewMobState != MobState.Dead);
|
||||
}
|
||||
|
||||
private void OnEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, MapInitEvent args)
|
||||
|
||||
@@ -17,4 +17,20 @@ public sealed partial class GunWieldBonusComponent : Component
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("maxAngle"), AutoNetworkedField]
|
||||
public Angle MaxAngle = Angle.FromDegrees(-43);
|
||||
|
||||
/// <summary>
|
||||
/// Recoil bonuses applied upon being wielded.
|
||||
/// Higher angle decay bonus, quicker recovery.
|
||||
/// Lower angle increase bonus (negative numbers), slower buildup.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public Angle AngleDecay = Angle.FromDegrees(0);
|
||||
|
||||
/// <summary>
|
||||
/// Recoil bonuses applied upon being wielded.
|
||||
/// Higher angle decay bonus, quicker recovery.
|
||||
/// Lower angle increase bonus (negative numbers), slower buildup.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public Angle AngleIncrease = Angle.FromDegrees(0);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
@@ -13,6 +12,7 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
protected virtual void InitializeMagazine()
|
||||
{
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, MapInitEvent>(OnMagazineMapInit);
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, TakeAmmoEvent>(OnMagazineTakeAmmo);
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, GetAmmoCountEvent>(OnMagazineAmmoCount);
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, GetVerbsEvent<AlternativeVerb>>(OnMagazineVerb);
|
||||
@@ -22,6 +22,11 @@ public abstract partial class SharedGunSystem
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, ExaminedEvent>(OnMagazineExamine);
|
||||
}
|
||||
|
||||
private void OnMagazineMapInit(Entity<MagazineAmmoProviderComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
MagazineSlotChanged(ent);
|
||||
}
|
||||
|
||||
private void OnMagazineExamine(EntityUid uid, MagazineAmmoProviderComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
@@ -62,16 +67,21 @@ public abstract partial class SharedGunSystem
|
||||
if (MagazineSlot != args.Container.ID)
|
||||
return;
|
||||
|
||||
UpdateAmmoCount(uid);
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
MagazineSlotChanged((uid, component));
|
||||
}
|
||||
|
||||
private void MagazineSlotChanged(Entity<MagazineAmmoProviderComponent> ent)
|
||||
{
|
||||
UpdateAmmoCount(ent);
|
||||
if (!TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
var magEnt = GetMagazineEntity(uid);
|
||||
Appearance.SetData(uid, AmmoVisuals.MagLoaded, magEnt != null, appearance);
|
||||
var magEnt = GetMagazineEntity(ent);
|
||||
Appearance.SetData(ent, AmmoVisuals.MagLoaded, magEnt != null, appearance);
|
||||
|
||||
if (magEnt != null)
|
||||
{
|
||||
UpdateMagazineAppearance(uid, component, magEnt.Value);
|
||||
UpdateMagazineAppearance(ent, ent, magEnt.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,8 @@ public sealed class WieldableSystem : EntitySystem
|
||||
{
|
||||
args.MinAngle += bonus.Comp.MinAngle;
|
||||
args.MaxAngle += bonus.Comp.MaxAngle;
|
||||
args.AngleDecay += bonus.Comp.AngleDecay;
|
||||
args.AngleIncrease += bonus.Comp.AngleIncrease;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +197,9 @@ public sealed class WieldableSystem : EntitySystem
|
||||
&& !_delay.TryResetDelay((used, useDelay), true))
|
||||
return false;
|
||||
|
||||
_popupSystem.PopupClient(Loc.GetString("wieldable-component-successful-wield", ("item", used)), user, user);
|
||||
_popupSystem.PopupEntity(Loc.GetString("wieldable-component-successful-wield-other", ("user", user), ("item", used)), user, Filter.PvsExcept(user), true);
|
||||
var selfMessage = Loc.GetString("wieldable-component-successful-wield", ("item", used));
|
||||
var othersMessage = Loc.GetString("wieldable-component-successful-wield-other", ("user", user), ("item", used));
|
||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
|
||||
|
||||
var targEv = new ItemWieldedEvent();
|
||||
RaiseLocalEvent(used, ref targEv);
|
||||
@@ -239,10 +242,9 @@ public sealed class WieldableSystem : EntitySystem
|
||||
if (component.UnwieldSound != null)
|
||||
_audioSystem.PlayPredicted(component.UnwieldSound, uid, args.User);
|
||||
|
||||
_popupSystem.PopupClient(Loc.GetString("wieldable-component-failed-wield",
|
||||
("item", uid)), args.User.Value, args.User.Value);
|
||||
_popupSystem.PopupEntity(Loc.GetString("wieldable-component-failed-wield-other",
|
||||
("user", args.User.Value), ("item", uid)), args.User.Value, Filter.PvsExcept(args.User.Value), true);
|
||||
var selfMessage = Loc.GetString("wieldable-component-failed-wield", ("item", uid));
|
||||
var othersMessage = Loc.GetString("wieldable-component-failed-wield-other", ("user", args.User.Value), ("item", uid));
|
||||
_popupSystem.PopupPredicted(selfMessage, othersMessage, args.User.Value, args.User.Value);
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, WieldableVisuals.Wielded, false);
|
||||
|
||||
@@ -1,94 +1,4 @@
|
||||
Entries:
|
||||
- author: Jajsha
|
||||
changes:
|
||||
- message: Emagged borgs now recieve laws recontextualizing who's a crew member
|
||||
instead of recieving a completely new lawset.
|
||||
type: Tweak
|
||||
id: 5843
|
||||
time: '2024-02-01T05:02:49.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24698
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: Health analyzers now show if somebody is starving.
|
||||
type: Add
|
||||
id: 5844
|
||||
time: '2024-02-01T06:28:17.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24789
|
||||
- author: PixelTK
|
||||
changes:
|
||||
- message: The arachnid plushie now has a new sprite.
|
||||
type: Tweak
|
||||
id: 5845
|
||||
time: '2024-02-01T06:36:43.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24747
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Yellow oxygen tank was removed to standardise gas tank colourings.
|
||||
type: Remove
|
||||
id: 5846
|
||||
time: '2024-02-01T06:53:33.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24374
|
||||
- author: koteq
|
||||
changes:
|
||||
- message: Fixed indicator near SSD players
|
||||
type: Fix
|
||||
id: 5847
|
||||
time: '2024-02-01T08:30:07.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24589
|
||||
- author: TheShuEd
|
||||
changes:
|
||||
- message: Anomaly generator can now only be used by a scientist.
|
||||
type: Tweak
|
||||
id: 5848
|
||||
time: '2024-02-01T08:45:24.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24464
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: Removed starvation damage
|
||||
type: Remove
|
||||
id: 5849
|
||||
time: '2024-02-01T09:01:52.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24790
|
||||
- author: SlamBamActionman
|
||||
changes:
|
||||
- message: The Visitor job can now be given to ID cards via the ID Card Console/Agent
|
||||
IDs.
|
||||
type: Add
|
||||
id: 5850
|
||||
time: '2024-02-01T10:13:44.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/23972
|
||||
- author: Dygon
|
||||
changes:
|
||||
- message: When slipping on lube you now keep sliding until you reach a tile without
|
||||
lube.
|
||||
type: Tweak
|
||||
id: 5851
|
||||
time: '2024-02-01T10:39:10.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24801
|
||||
- author: FungiFellow
|
||||
changes:
|
||||
- message: Added Binary Key in RD's Locker
|
||||
type: Add
|
||||
- message: 50% off Binary Key
|
||||
type: Tweak
|
||||
id: 5852
|
||||
time: '2024-02-01T10:42:12.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24778
|
||||
- author: Dygon
|
||||
changes:
|
||||
- message: Paraplegic entities have their legs healed when zombified.
|
||||
type: Fix
|
||||
id: 5853
|
||||
time: '2024-02-01T11:06:05.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24169
|
||||
- author: PJB3005
|
||||
changes:
|
||||
- message: The AME can now single-handedly power the entire station until one of
|
||||
our cool coders gets their shit together and fixes engineering.
|
||||
type: Fix
|
||||
id: 5854
|
||||
time: '2024-02-01T11:06:52.0000000+00:00'
|
||||
url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24806
|
||||
- author: Varen
|
||||
changes:
|
||||
- message: Cutting wires will now properly electrocute if enough power is available.
|
||||
@@ -3828,3 +3738,104 @@
|
||||
id: 6342
|
||||
time: '2024-04-13T15:36:05.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26499
|
||||
- author: Boaz1111
|
||||
changes:
|
||||
- message: The doors on the ice expedition map can now be accessed by anyone instead
|
||||
of... botanists.
|
||||
type: Fix
|
||||
id: 6343
|
||||
time: '2024-04-13T20:49:02.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26928
|
||||
- author: Tayrtahn
|
||||
changes:
|
||||
- message: Placing a player with no entry in the manifest into cryostorage no longer
|
||||
removes the captain from the crew manifest.
|
||||
type: Fix
|
||||
id: 6344
|
||||
time: '2024-04-14T02:19:42.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26927
|
||||
- author: superjj18
|
||||
changes:
|
||||
- message: Honkbot's basic AI has been restored and honks have returned to being
|
||||
at random intervals!
|
||||
type: Fix
|
||||
id: 6345
|
||||
time: '2024-04-14T02:51:24.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26939
|
||||
- author: GreaseMonk
|
||||
changes:
|
||||
- message: Added StopsWhenEntityDead property to audio components
|
||||
type: Add
|
||||
id: 6346
|
||||
time: '2024-04-14T03:12:38.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26905
|
||||
- author: DrSmugleaf
|
||||
changes:
|
||||
- message: Fixed rocket launchers and laser guns looking like they have nothing
|
||||
loaded.
|
||||
type: Fix
|
||||
id: 6347
|
||||
time: '2024-04-14T03:17:17.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26933
|
||||
- author: Vermidia
|
||||
changes:
|
||||
- message: You can now see paper attached on crates. Color differs depending on
|
||||
the paper used.
|
||||
type: Add
|
||||
- message: The labels on bodybags also have different colors depending on the paper
|
||||
used.
|
||||
type: Tweak
|
||||
- message: Cargo Invoices are now blueish (to differentiate them from Cargo Bounties)
|
||||
type: Tweak
|
||||
id: 6348
|
||||
time: '2024-04-14T03:39:02.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26834
|
||||
- author: Terraspark4941
|
||||
changes:
|
||||
- message: Autism pins have been added to maintenance loot!
|
||||
type: Add
|
||||
id: 6349
|
||||
time: '2024-04-14T05:35:35.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/25597
|
||||
- author: Flareguy
|
||||
changes:
|
||||
- message: Colored jumpsuits, shoes, and (most) colored gloves are now colorized
|
||||
off of one set of greyscale sprites. They should now be more consistent & significantly
|
||||
less ugly.
|
||||
type: Tweak
|
||||
id: 6350
|
||||
time: '2024-04-14T08:41:39.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26943
|
||||
- author: BramvanZijp
|
||||
changes:
|
||||
- message: Nanotrasen's Small Arms Division has slightly improved the firerate and
|
||||
drastically improved the accuracy on its WT550 SMGs.
|
||||
type: Tweak
|
||||
- message: The WT550 and C-20R SMGs can now fire in a 5 round burst-fire mode, making
|
||||
it easier for their users to control the recoil on these weapons.
|
||||
type: Add
|
||||
id: 6351
|
||||
time: '2024-04-14T08:51:07.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26886
|
||||
- author: Dutch-VanDerLinde
|
||||
changes:
|
||||
- message: Holoparasites and holoclowns will now phase through projectiles such
|
||||
as bullets, like a holocarp.
|
||||
type: Tweak
|
||||
id: 6352
|
||||
time: '2024-04-14T08:52:57.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26862
|
||||
- author: Tyzemol
|
||||
changes:
|
||||
- message: Board game crate now comes with character sheets
|
||||
type: Add
|
||||
id: 6353
|
||||
time: '2024-04-14T08:54:40.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26926
|
||||
- author: FairlySadPanda
|
||||
changes:
|
||||
- message: Clown shoes make you waddle, as God intended.
|
||||
type: Add
|
||||
id: 6354
|
||||
time: '2024-04-14T12:12:54.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/26338
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
### Announcement
|
||||
|
||||
earlyleave-cryo-job-unknown = Unknown
|
||||
earlyleave-cryo-announcement = {$character} ({$job}) has entered cryogenic storage!
|
||||
earlyleave-cryo-sender = Station
|
||||
|
||||
@@ -180,6 +180,8 @@
|
||||
- id: GrassBattlemap
|
||||
- id: DiceBag
|
||||
amount: 6
|
||||
- id: PaperCNCSheet
|
||||
amount: 6
|
||||
|
||||
- type: entity
|
||||
id: CrateFunSadTromboneImplants
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
amount: 3
|
||||
- id: ClothingUniformRandomArmless
|
||||
amount: 5
|
||||
- id: ClothingUniformRandomStandart
|
||||
- id: ClothingUniformRandomStandard
|
||||
amount: 5
|
||||
- id: ClothingUniformRandomBra
|
||||
amount: 5
|
||||
|
||||
@@ -34,3 +34,13 @@
|
||||
spawned:
|
||||
- id: MaterialCloth1
|
||||
amount: 1
|
||||
|
||||
# gloves that cover the fingertips and have synthetic fibers
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: ClothingHandsButcherable
|
||||
id: ClothingHandsGlovesSyntheticBase
|
||||
components:
|
||||
- type: Fiber
|
||||
fiberMaterial: fibers-synthetic
|
||||
- type: FingerprintMask
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
# gloves that cover the fingertips and have synthetic fibers
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: ClothingHandsButcherable
|
||||
id: ClothingHandsGlovesSyntheticBase
|
||||
components:
|
||||
- type: Fiber
|
||||
fiberMaterial: fibers-synthetic
|
||||
- type: FingerprintMask
|
||||
#DO NOT MAKE THESE THE SAME COLOR AS THE JUMPSUIT. It is going to cause contrast issues for those wearing the full set of color clothing and is almost definitely going to look worse.
|
||||
#If you want to make it similar to the jumpsuit color, it should be slightly off.
|
||||
#P.S: Most of these just use the shoe colors, so they end up having a nice "secondary" color when wearing the full set of color clothing.
|
||||
|
||||
# Purple Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorPurple
|
||||
@@ -15,12 +10,28 @@
|
||||
description: Regular purple gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/purple.rsi
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9C0DE1"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9C0DE1"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9C0DE1"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/purple.rsi
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#9C0DE1"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-purple
|
||||
|
||||
# Red Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorRed
|
||||
@@ -28,12 +39,232 @@
|
||||
description: Regular red gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/red.rsi
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#940000"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#940000"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#940000"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/red.rsi
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#940000"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-red
|
||||
|
||||
# Blue Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorBlue
|
||||
name: blue gloves
|
||||
description: Regular blue gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#0089EF"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#0089EF"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#0089EF"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#0089EF"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-blue
|
||||
|
||||
# Brown Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorBrown
|
||||
name: brown gloves
|
||||
description: Regular brown gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#723A02"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#723A02"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#723A02"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#723A02"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-brown
|
||||
|
||||
# Grey Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorGray
|
||||
name: grey gloves
|
||||
description: Regular grey gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#999999"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#999999"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#999999"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#999999"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-grey
|
||||
|
||||
# Green Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorGreen
|
||||
name: green gloves
|
||||
description: Regular green gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#5ABF2F"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#5ABF2F"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#5ABF2F"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#5ABF2F"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-green
|
||||
|
||||
# Light Brown Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorLightBrown
|
||||
name: light brown gloves
|
||||
description: Regular light brown gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#C09F72"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#C09F72"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#C09F72"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#C09F72"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-brown
|
||||
|
||||
# Orange Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorOrange
|
||||
name: orange gloves
|
||||
description: Regular orange gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#EF8100"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#EF8100"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#EF8100"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#EF8100"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-orange
|
||||
|
||||
# White Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorWhite
|
||||
name: white gloves
|
||||
description: Regular white gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#EAE8E8"
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#EAE8E8"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#EAE8E8"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/color.rsi
|
||||
clothingVisuals:
|
||||
gloves:
|
||||
- state: equipped-HAND
|
||||
color: "#EAE8E8"
|
||||
- type: Fiber
|
||||
fiberColor: fibers-white
|
||||
|
||||
# Black Gloves
|
||||
# TECHNICALLY, if you ported the worn state to the RSI, this could be greyscaled, but I do not really feel like doing that.
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorBlack
|
||||
@@ -42,6 +273,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/black.rsi
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#535353"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#535353"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/black.rsi
|
||||
- type: GloveHeatResistance
|
||||
@@ -53,97 +292,8 @@
|
||||
- type: Fiber
|
||||
fiberColor: fibers-black
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorBlue
|
||||
name: blue gloves
|
||||
description: Regular blue gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/blue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/blue.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-blue
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorBrown
|
||||
name: brown gloves
|
||||
description: Regular brown gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/brown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/brown.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-brown
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorGray
|
||||
name: grey gloves
|
||||
description: Regular grey gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/gray.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/gray.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-grey
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorGreen
|
||||
name: green gloves
|
||||
description: Regular green gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/green.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/green.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-green
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorLightBrown
|
||||
name: light brown gloves
|
||||
description: Regular light brown gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/lightbrown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/lightbrown.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-brown
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorOrange
|
||||
name: orange gloves
|
||||
description: Regular orange gloves that do not keep you from frying.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/orange.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/orange.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-orange
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesSyntheticBase
|
||||
id: ClothingHandsGlovesColorWhite
|
||||
name: white gloves
|
||||
description: Those gloves look fancy.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Hands/Gloves/Color/white.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/Color/white.rsi
|
||||
- type: Fiber
|
||||
fiberColor: fibers-white
|
||||
|
||||
# Insulated Gloves (Yellow Gloves)
|
||||
# Currently can not be greyscaled without looking like shit.
|
||||
- type: entity
|
||||
parent: ClothingHandsBase
|
||||
id: ClothingHandsGlovesColorYellow
|
||||
@@ -166,6 +316,7 @@
|
||||
fiberMaterial: fibers-insulative
|
||||
fiberColor: fibers-yellow
|
||||
|
||||
# Budget Insulated Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesColorYellow
|
||||
id: ClothingHandsGlovesColorYellowBudget
|
||||
@@ -192,6 +343,7 @@
|
||||
- 3.5
|
||||
- 4
|
||||
|
||||
# Conductive Insulated Gloves
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesColorYellow
|
||||
id: ClothingHandsGlovesConducting
|
||||
|
||||
@@ -151,3 +151,35 @@
|
||||
clothingVisuals:
|
||||
neck:
|
||||
- state: trans-equipped
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckPinBase
|
||||
id: ClothingNeckAutismPin
|
||||
name: autism pin
|
||||
description: be autism do crime
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Neck/Misc/autismpin.rsi
|
||||
layers:
|
||||
- state: autism
|
||||
- type: Clothing
|
||||
sprite: Clothing/Neck/Misc/autismpin.rsi
|
||||
clothingVisuals:
|
||||
neck:
|
||||
- state: autism-equipped
|
||||
|
||||
- type: entity
|
||||
parent: ClothingNeckPinBase
|
||||
id: ClothingNeckGoldAutismPin
|
||||
name: golden autism pin
|
||||
description: be autism do warcrime
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Neck/Misc/goldautismpin.rsi
|
||||
layers:
|
||||
- state: goldautism
|
||||
- type: Clothing
|
||||
sprite: Clothing/Neck/Misc/goldautismpin.rsi
|
||||
clothingVisuals:
|
||||
neck:
|
||||
- state: goldautism-equipped
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# DO NOT ARBITRARILY CHANGE THESE TO MAKE THEM "CONSISTENT" WITH THE COLOR JUMPSUITS. You are probably just going to make them look worse.
|
||||
|
||||
# Black Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorBlack
|
||||
@@ -5,76 +8,30 @@
|
||||
description: Stylish black shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/black.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3f3f3f" #Different from the worn state for contrast reasons.
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3f3f3f"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3f3f3f"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/black.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorBlue
|
||||
name: blue shoes
|
||||
description: Stylish blue shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/blue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/blue.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorBrown
|
||||
name: brown shoes
|
||||
description: A pair of brown shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/brown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/brown.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorGreen
|
||||
name: green shoes
|
||||
description: Stylish green shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/green.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/green.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorOrange
|
||||
name: orange shoes
|
||||
description: Stylish orange shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/orange.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/orange.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorPurple
|
||||
name: purple shoes
|
||||
description: Stylish purple shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/purple.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/purple.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorRed
|
||||
name: red shoes
|
||||
description: Stylish red shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/red.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/red.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#1d1d1d"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# White Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorWhite
|
||||
@@ -82,10 +39,183 @@
|
||||
description: Don't take them off at your office Christmas party.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/white.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#EAE8E8" #Deliberately NOT pure white
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals: #We don't want the sole icons. Since this is white, it's just going to look weird (white on white doesn't really contrast.)
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#EAE8E8"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#EAE8E8"
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/white.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#EAE8E8"
|
||||
- state: contrastedsoles-equipped-FEET
|
||||
|
||||
# Blue Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorBlue
|
||||
name: blue shoes
|
||||
description: Stylish blue shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#0089EF"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#0089EF"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#0089EF"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#0089EF"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Brown Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorBrown
|
||||
name: brown shoes
|
||||
description: A pair of brown shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#723A02"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#723A02"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#723A02"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#592D01"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Green Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorGreen
|
||||
name: green shoes
|
||||
description: Stylish green shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#5ABF2F"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#5ABF2F"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#5ABF2F"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#5ABF2F"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Orange Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorOrange
|
||||
name: orange shoes
|
||||
description: Stylish orange shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#EF8100"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#EF8100"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#EF8100"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#EF8100"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Red Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorRed
|
||||
name: red shoes
|
||||
description: Stylish red shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#940000"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#940000"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#940000"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#940000"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Yellow Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorYellow
|
||||
@@ -93,6 +223,56 @@
|
||||
description: Stylish yellow shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/yellow.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#EBE216"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#EBE216"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#EBE216"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/yellow.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#EBE216"
|
||||
- state: soles-equipped-FEET
|
||||
|
||||
# Purple Shoes
|
||||
- type: entity
|
||||
parent: ClothingShoesBaseButcherable
|
||||
id: ClothingShoesColorPurple
|
||||
name: purple shoes
|
||||
description: Stylish purple shoes.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9C0DE1"
|
||||
- state: soles-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9C0DE1"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9C0DE1"
|
||||
- state: soles-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#9C0DE1"
|
||||
- state: soles-equipped-FEET
|
||||
@@ -15,6 +15,7 @@
|
||||
parent: [ClothingShoesBaseButcherable, ClothingSlotBase]
|
||||
id: ClothingShoesClownBase
|
||||
components:
|
||||
- type: WaddleWhenWorn
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
item:
|
||||
@@ -157,9 +158,28 @@
|
||||
- type: Tag
|
||||
tags: [] # ignore "WhitelistChameleon" tag
|
||||
- type: Sprite
|
||||
sprite: Clothing/Shoes/Color/black.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3f3f3f"
|
||||
- state: soles-icon
|
||||
- type: Clothing
|
||||
sprite: Clothing/Shoes/Color/black.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#1d1d1d"
|
||||
- state: soles-equipped-FEET
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3f3f3f"
|
||||
- state: soles-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3f3f3f"
|
||||
- state: soles-inhand-right
|
||||
- type: ChameleonClothing
|
||||
slot: [FEET]
|
||||
default: ClothingShoesColorBlack
|
||||
|
||||
@@ -0,0 +1,491 @@
|
||||
# White Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorWhite
|
||||
name: white jumpskirt
|
||||
description: A generic white jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Grey Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorGrey
|
||||
name: grey jumpskirt
|
||||
description: A tasteful grey jumpskirt that reminds you of the good old days.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Black Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorBlack
|
||||
name: black jumpskirt
|
||||
description: A generic black jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Blue Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorBlue
|
||||
name: blue jumpskirt
|
||||
description: A generic blue jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#52aecc"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#52aecc"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#52aecc"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#52aecc"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Dark Blue Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorDarkBlue
|
||||
name: dark blue jumpskirt
|
||||
description: A generic dark blue jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3285ba"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3285ba"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3285ba"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#3285ba"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Teal Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorTeal
|
||||
name: teal jumpskirt
|
||||
description: A generic teal jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Green Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorGreen
|
||||
name: green jumpskirt
|
||||
description: A generic green jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Dark Green Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorDarkGreen
|
||||
name: dark green jumpskirt
|
||||
description: A generic dark green jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#79CC26"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#79CC26"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#79CC26"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#79CC26"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Orange Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorOrange
|
||||
name: orange jumpskirt
|
||||
description: Don't wear this near paranoid security officers.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Pink Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorPink
|
||||
name: pink jumpskirt
|
||||
description: Just looking at this makes you feel <i>fabulous</i>.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Red Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorRed
|
||||
name: red jumpskirt
|
||||
description: A generic red jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Yellow Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorYellow
|
||||
name: yellow jumpskirt
|
||||
description: A generic yellow jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Purple Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorPurple
|
||||
name: purple jumpskirt
|
||||
description: A generic light purple jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Light Brown Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorLightBrown
|
||||
name: light brown jumpskirt
|
||||
description: A generic light brown jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#c59431"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#c59431"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#c59431"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#c59431"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Brown Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorBrown
|
||||
name: brown jumpskirt
|
||||
description: A generic brown jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#a17229"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#a17229"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#a17229"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#a17229"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Maroon Jumpskirt
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtColorMaroon
|
||||
name: maroon jumpskirt
|
||||
description: A generic maroon jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#cc295f"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#cc295f"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#cc295f"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#cc295f"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
@@ -0,0 +1,503 @@
|
||||
# White Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorWhite
|
||||
name: white jumpsuit
|
||||
description: A generic white jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Grey Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorGrey
|
||||
name: grey jumpsuit
|
||||
description: A tasteful grey jumpsuit that reminds you of the good old days.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#b3b3b3"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Black Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBlack
|
||||
name: black jumpsuit
|
||||
description: A generic black jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Blue Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBlue
|
||||
name: blue jumpsuit
|
||||
description: A generic blue jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#52aecc"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#52aecc"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#52aecc"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#52aecc"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Dark Blue Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorDarkBlue
|
||||
name: dark blue jumpsuit
|
||||
description: A generic dark blue jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3285ba"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3285ba"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3285ba"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#3285ba"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Teal Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorTeal
|
||||
name: teal jumpsuit
|
||||
description: A generic teal jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#77f3b7"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Green Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorGreen
|
||||
name: green jumpsuit
|
||||
description: A generic green jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#9ed63a"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Dark Green Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorDarkGreen
|
||||
name: dark green jumpsuit
|
||||
description: A generic dark green jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#79CC26"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#79CC26"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#79CC26"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#79CC26"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Orange Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorOrange
|
||||
name: orange jumpsuit
|
||||
description: Don't wear this near paranoid security officers.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ff8c19"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Pink Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorPink
|
||||
name: pink jumpsuit
|
||||
description: Just looking at this makes you feel <i>fabulous</i>.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ffa69b"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Red Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorRed
|
||||
name: red jumpsuit
|
||||
description: A generic red jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#eb0c07"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Yellow Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorYellow
|
||||
name: yellow jumpsuit
|
||||
description: A generic yellow jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ffe14d"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Purple Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorPurple
|
||||
name: purple jumpsuit
|
||||
description: A generic light purple jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#9f70cc"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Light Brown Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorLightBrown
|
||||
name: light brown jumpsuit
|
||||
description: A generic light brown jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#c59431"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#c59431"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#c59431"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#c59431"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Brown Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBrown
|
||||
name: brown jumpsuit
|
||||
description: A generic brown jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#a17229"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#a17229"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#a17229"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#a17229"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Maroon Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorMaroon
|
||||
name: maroon jumpsuit
|
||||
description: A generic maroon jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#cc295f"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#cc295f"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#cc295f"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#cc295f"
|
||||
- state: trinkets-equipped-INNERCLOTHING
|
||||
|
||||
# Rainbow Jumpsuit
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformColorRainbow
|
||||
name: rainbow jumpsuit
|
||||
description: A multi-colored jumpsuit!
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/rainbow.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/rainbow.rsi
|
||||
@@ -263,15 +263,34 @@
|
||||
sprite: Clothing/Uniforms/Jumpskirt/brigmedic.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtPrisoner
|
||||
name: prisoner jumpskirt
|
||||
description: Busted.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/prisoner.rsi
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ff8300"
|
||||
- state: prisoner-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ff8300"
|
||||
- state: prisoner-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ff8300"
|
||||
- state: prisoner-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/prisoner.rsi
|
||||
sprite: Clothing/Uniforms/Jumpskirt/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ff8300"
|
||||
- state: prisoner-equipped-INNERCLOTHING
|
||||
- type: SuitSensor
|
||||
controlsLocked: true
|
||||
randomMode: false
|
||||
@@ -279,8 +298,8 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- ClothMade
|
||||
- WhitelistChameleon
|
||||
- PrisonUniform
|
||||
- WhitelistChameleon
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
@@ -359,184 +378,6 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/warden.rsi
|
||||
|
||||
# COLORS
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorGrey
|
||||
description: A tasteful grey jumpskirt that reminds you of the good old days.
|
||||
name: grey jumpskirt
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/grey.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/grey.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorBlack
|
||||
name: black jumpskirt
|
||||
description: A generic black jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/black.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/black.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorBlue
|
||||
name: blue jumpskirt
|
||||
description: A generic blue jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/blue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/blue.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorGreen
|
||||
name: green jumpskirt
|
||||
description: A generic green jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/green.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/green.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorOrange
|
||||
name: orange jumpskirt
|
||||
description: "Don't wear this near paranoid security officers."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/orange.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/orange.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorPink
|
||||
name: pink jumpskirt
|
||||
description: "Just looking at this makes you feel fabulous."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/pink.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/pink.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorRed
|
||||
name: red jumpskirt
|
||||
description: A generic red jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/red.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/red.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorWhite
|
||||
name: white jumpskirt
|
||||
description: A generic white jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/white.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/white.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorYellow
|
||||
name: yellow jumpskirt
|
||||
description: A generic yellow jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/yellow.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/yellow.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorDarkBlue
|
||||
name: dark blue jumpskirt
|
||||
description: A generic dark blue jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/darkblue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/darkblue.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorTeal
|
||||
name: teal jumpskirt
|
||||
description: A generic teal jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/teal.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/teal.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorPurple
|
||||
name: purple jumpskirt
|
||||
description: A generic purple jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/lightpurple.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/lightpurple.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorDarkGreen
|
||||
name: dark green jumpskirt
|
||||
description: A generic dark green jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/darkgreen.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/darkgreen.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorLightBrown
|
||||
name: light brown jumpskirt
|
||||
description: A generic light brown jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/lightbrown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/lightbrown.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorBrown
|
||||
name: brown jumpskirt
|
||||
description: A generic brown jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/brown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/brown.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtColorMaroon
|
||||
name: maroon jumpskirt
|
||||
description: A generic maroon jumpskirt with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/maroon.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpskirt/Color/maroon.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformJumpskirtLibrarian
|
||||
|
||||
@@ -458,9 +458,28 @@
|
||||
description: Busted.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/prisoner.rsi
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#ff8300"
|
||||
- state: prisoner-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ff8300"
|
||||
- state: prisoner-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ff8300"
|
||||
- state: prisoner-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/prisoner.rsi
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: equipped-INNERCLOTHING
|
||||
color: "#ff8300"
|
||||
- state: prisoner-equipped-INNERCLOTHING
|
||||
- type: SuitSensor
|
||||
controlsLocked: true
|
||||
randomMode: false
|
||||
@@ -592,195 +611,6 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/warden.rsi
|
||||
|
||||
# COLORS
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorGrey
|
||||
description: A tasteful grey jumpsuit that reminds you of the good old days.
|
||||
name: grey jumpsuit
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/grey.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/grey.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBlack
|
||||
name: black jumpsuit
|
||||
description: A generic black jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/black.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/black.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBlue
|
||||
name: blue jumpsuit
|
||||
description: A generic blue jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/blue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/blue.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorGreen
|
||||
name: green jumpsuit
|
||||
description: A generic green jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/green.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/green.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorOrange
|
||||
name: orange jumpsuit
|
||||
description: "Don't wear this near paranoid security officers."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/orange.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/orange.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorPink
|
||||
name: pink jumpsuit
|
||||
description: "Just looking at this makes you feel fabulous."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/pink.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/pink.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorRed
|
||||
name: red jumpsuit
|
||||
description: A generic red jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/red.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/red.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorWhite
|
||||
name: white jumpsuit
|
||||
description: A generic white jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/white.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/white.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorYellow
|
||||
name: yellow jumpsuit
|
||||
description: A generic yellow jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/yellow.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/yellow.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorDarkBlue
|
||||
name: dark blue jumpsuit
|
||||
description: A generic dark blue jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/darkblue.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/darkblue.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorTeal
|
||||
name: teal jumpsuit
|
||||
description: A generic teal jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/teal.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/teal.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorPurple
|
||||
name: purple jumpsuit
|
||||
description: A generic purple jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/lightpurple.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/lightpurple.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorDarkGreen
|
||||
name: dark green jumpsuit
|
||||
description: A generic dark green jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/darkgreen.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/darkgreen.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorLightBrown
|
||||
name: light brown jumpsuit
|
||||
description: A generic light brown jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/lightbrown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/lightbrown.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorBrown
|
||||
name: brown jumpsuit
|
||||
description: A generic brown jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/brown.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/brown.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitColorMaroon
|
||||
name: maroon jumpsuit
|
||||
description: A generic maroon jumpsuit with no rank markings.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/maroon.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/maroon.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformColorRainbow
|
||||
name: rainbow jumpsuit
|
||||
description: A multi-colored jumpsuit!
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/rainbow.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/rainbow.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformOveralls
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/procedural.rsi
|
||||
layers:
|
||||
- state: base_torso_standart
|
||||
- state: base_torso_standard
|
||||
map: [ "torso" ]
|
||||
- state: base_leg_standart
|
||||
- state: base_leg_standard
|
||||
map: [ "leg" ]
|
||||
- state: mask_null
|
||||
map: [ "decor" ]
|
||||
@@ -24,9 +24,9 @@
|
||||
sprite: Clothing/Uniforms/procedural.rsi
|
||||
clothingVisuals:
|
||||
jumpsuit:
|
||||
- state: base_torso_standart
|
||||
- state: base_torso_standard
|
||||
map: [ "torso" ]
|
||||
- state: base_leg_standart
|
||||
- state: base_leg_standard
|
||||
map: [ "leg" ]
|
||||
- state: mask_null
|
||||
map: [ "decor" ]
|
||||
@@ -42,7 +42,7 @@
|
||||
offset: 0
|
||||
prototypes:
|
||||
- ClothingUniformRandomArmless
|
||||
- ClothingUniformRandomStandart
|
||||
- ClothingUniformRandomStandard
|
||||
- ClothingUniformRandomBra
|
||||
- ClothingUniformRandomShorts
|
||||
- ClothingUniformRandomShirt
|
||||
@@ -57,7 +57,7 @@
|
||||
- torso:
|
||||
base_torso_armless: Sixteen
|
||||
leg:
|
||||
base_leg_standart: Sixteen
|
||||
base_leg_standard: Sixteen
|
||||
base_leg_short: Sixteen
|
||||
base_leg_skirt: Sixteen
|
||||
base_leg_skirt_long: Sixteen
|
||||
@@ -76,16 +76,16 @@
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformRandom
|
||||
id: ClothingUniformRandomStandart
|
||||
id: ClothingUniformRandomStandard
|
||||
name: colorful costume
|
||||
components:
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- torso:
|
||||
base_torso_standart: Sixteen
|
||||
base_torso_standart2: Sixteen
|
||||
base_torso_standard: Sixteen
|
||||
base_torso_standard2: Sixteen
|
||||
leg:
|
||||
base_leg_standart: Sixteen
|
||||
base_leg_standard: Sixteen
|
||||
base_leg_short: Sixteen
|
||||
base_leg_skirt: Sixteen
|
||||
base_leg_skirt_long: Sixteen
|
||||
@@ -100,15 +100,15 @@
|
||||
decor_torso_armless8: Sixteen
|
||||
decor_torso_armless9: Sixteen
|
||||
decor_torso_armless10: Sixteen
|
||||
decor_torso_standart1: Sixteen
|
||||
decor_torso_standart2: Sixteen
|
||||
decor_torso_standart3: Sixteen
|
||||
decor_torso_standart4: Sixteen
|
||||
decor_torso_standart5: Sixteen
|
||||
decor_torso_standart6: Sixteen
|
||||
decor_torso_standart7: Sixteen
|
||||
decor_torso_standart8: Sixteen
|
||||
decor_torso_standart9: Sixteen
|
||||
decor_torso_standard1: Sixteen
|
||||
decor_torso_standard2: Sixteen
|
||||
decor_torso_standard3: Sixteen
|
||||
decor_torso_standard4: Sixteen
|
||||
decor_torso_standard5: Sixteen
|
||||
decor_torso_standard6: Sixteen
|
||||
decor_torso_standard7: Sixteen
|
||||
decor_torso_standard8: Sixteen
|
||||
decor_torso_standard9: Sixteen
|
||||
mask_null: ""
|
||||
|
||||
- type: entity
|
||||
@@ -121,7 +121,7 @@
|
||||
- torso:
|
||||
base_torso_bra: Sixteen
|
||||
leg:
|
||||
base_leg_standart: Sixteen
|
||||
base_leg_standard: Sixteen
|
||||
base_leg_short: Sixteen
|
||||
base_leg_skirt: Sixteen
|
||||
base_leg_skirt_long: Sixteen
|
||||
@@ -143,7 +143,7 @@
|
||||
- torso:
|
||||
mask_null: ""
|
||||
leg:
|
||||
base_leg_standart: Sixteen
|
||||
base_leg_standard: Sixteen
|
||||
base_leg_short: Sixteen
|
||||
base_leg_skirt: Sixteen
|
||||
base_leg_skirt_long: Sixteen
|
||||
@@ -159,11 +159,11 @@
|
||||
base_torso_armless: Sixteen
|
||||
mask_null: ""
|
||||
leg:
|
||||
base_leg_standart: Sixteen
|
||||
base_leg_standard: Sixteen
|
||||
base_leg_short: Sixteen
|
||||
decor:
|
||||
base_torso_shirt: Sixteen
|
||||
overlay:
|
||||
decor_torso_shirt1: Sixteen
|
||||
decor_torso_shirt2: Sixteen
|
||||
decor_torso_shirt3: Sixteen
|
||||
decor_torso_shirt3: Sixteen
|
||||
|
||||
@@ -8,9 +8,28 @@
|
||||
- type: Tag
|
||||
tags: [] # ignore "WhitelistChameleon" tag
|
||||
- type: Sprite
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/black.rsi
|
||||
sprite: Clothing/Uniforms/Jumpsuit/color.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-icon
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#3f3f3f"
|
||||
- state: trinkets-inhand-right
|
||||
- type: Clothing
|
||||
sprite: Clothing/Uniforms/Jumpsuit/Color/black.rsi
|
||||
sprite: Clothing/Shoes/color.rsi
|
||||
clothingVisuals:
|
||||
shoes:
|
||||
- state: equipped-FEET
|
||||
color: "#1d1d1d"
|
||||
- state: soles-equipped-FEET
|
||||
- type: SuitSensor
|
||||
randomMode: false
|
||||
mode: SensorOff
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
- ClothingUniformJumpsuitPirate
|
||||
- ClothingShoesBootsCowboyFancy
|
||||
- ClothingHeadHatCowboyBountyHunter
|
||||
- ClothingNeckAutismPin
|
||||
- ClothingNeckGoldAutismPin
|
||||
rareChance: 0.01
|
||||
prototypes:
|
||||
- Lighter
|
||||
|
||||
@@ -114,11 +114,16 @@
|
||||
description: Horrifying.
|
||||
components:
|
||||
- type: SpamEmitSound
|
||||
minInterval: 2
|
||||
maxInterval: 12
|
||||
sound:
|
||||
collection: BikeHorn
|
||||
- type: Sprite
|
||||
sprite: Mobs/Silicon/Bots/honkbot.rsi
|
||||
state: honkbot
|
||||
- type: HTN
|
||||
rootTask:
|
||||
task: HonkbotCompound
|
||||
- type: Slippery
|
||||
launchForwardsMultiplier: 2
|
||||
- type: Speech
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- Opaque
|
||||
- type: Damageable
|
||||
damageContainer: Biological
|
||||
- type: MobState
|
||||
@@ -86,6 +86,8 @@
|
||||
animation: WeaponArcFist
|
||||
attackRate: 1.8
|
||||
autoAttack: true
|
||||
soundHit:
|
||||
collection: Punch
|
||||
damage:
|
||||
types:
|
||||
Blunt: 20
|
||||
@@ -227,6 +229,8 @@
|
||||
angle: 30
|
||||
animation: WeaponArcFist
|
||||
attackRate: 1.8
|
||||
soundHit:
|
||||
collection: BikeHorn
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
description: "Like a cigar, but for tough teens. (WARNING:Pour only water into the vape)"
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Smokeables/Vapes/vape-standart.rsi
|
||||
state: icon
|
||||
sprite: Objects/Consumable/Smokeables/Vapes/vape-standard.rsi
|
||||
state: icon
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
map: ["enum.PaperVisualLayers.Stamp"]
|
||||
visible: false
|
||||
- type: Paper
|
||||
- type: PaperLabelType
|
||||
- type: ActivatableUI
|
||||
key: enum.PaperUiKey.Key
|
||||
closeOnHandDeselect: false
|
||||
@@ -143,6 +144,8 @@
|
||||
- state: paper_stamp-generic
|
||||
map: ["enum.PaperVisualLayers.Stamp"]
|
||||
visible: false
|
||||
- type: PaperLabelType
|
||||
paperType: CaptainsPaper
|
||||
- type: PaperVisuals
|
||||
headerImagePath: "/Textures/Interface/Paper/paper_heading_captains_thoughts.svg.96dpi.png"
|
||||
backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"
|
||||
@@ -160,19 +163,21 @@
|
||||
sprite: Objects/Misc/bureaucracy.rsi
|
||||
layers:
|
||||
- state: paper
|
||||
color: "#f7e574"
|
||||
color: "#9ef5ff"
|
||||
- state: paper_words
|
||||
map: ["enum.PaperVisualLayers.Writing"]
|
||||
color: "#f7e574"
|
||||
color: "#9ef5ff"
|
||||
visible: false
|
||||
- state: paper_stamp-generic
|
||||
map: ["enum.PaperVisualLayers.Stamp"]
|
||||
visible: false
|
||||
- type: PaperLabelType
|
||||
paperType: Invoice
|
||||
- type: PaperVisuals
|
||||
backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"
|
||||
contentImagePath: "/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png"
|
||||
backgroundModulate: "#f7e574"
|
||||
contentImageModulate: "#f7e574"
|
||||
backgroundModulate: "#9ef5ff"
|
||||
contentImageModulate: "#9ef5ff"
|
||||
backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0
|
||||
contentMargin: 16.0, 16.0, 16.0, 16.0
|
||||
headerImagePath: "/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png"
|
||||
@@ -184,6 +189,29 @@
|
||||
name: bounty manifest
|
||||
description: A paper label designating a crate as containing a bounty. Selling a crate with this label will fulfill the bounty.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/bureaucracy.rsi
|
||||
layers:
|
||||
- state: paper
|
||||
color: "#f7e574"
|
||||
- state: paper_words
|
||||
map: ["enum.PaperVisualLayers.Writing"]
|
||||
color: "#f7e574"
|
||||
visible: false
|
||||
- state: paper_stamp-generic
|
||||
map: ["enum.PaperVisualLayers.Stamp"]
|
||||
visible: false
|
||||
- type: PaperLabelType
|
||||
paperType: Bounty
|
||||
- type: PaperVisuals
|
||||
backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"
|
||||
contentImagePath: "/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png"
|
||||
backgroundModulate: "#f7e574"
|
||||
contentImageModulate: "#f7e574"
|
||||
backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0
|
||||
contentMargin: 16.0, 16.0, 16.0, 16.0
|
||||
headerImagePath: "/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png"
|
||||
headerMargin: 0.0, 12.0, 0.0, 0.0
|
||||
- type: CargoBountyLabel
|
||||
- type: StaticPrice
|
||||
price: 0
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
visible: false
|
||||
- state: open_overlay
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: label_overlay
|
||||
map: ["enum.BodyBagVisualLayers.Label"]
|
||||
- state: paper
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Objects/Specific/Medical/Morgue/bodybags.rsi
|
||||
state: bag
|
||||
@@ -62,9 +62,15 @@
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.PaperLabelVisuals.HasLabel:
|
||||
enum.BodyBagVisualLayers.Label:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
True: {visible: true}
|
||||
False: {visible: false}
|
||||
enum.PaperLabelVisuals.LabelType:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
Paper: { state: paper }
|
||||
Bounty: { state: bounty }
|
||||
CaptainsPaper: { state: captains_paper }
|
||||
Invoice: { state: invoice }
|
||||
enum.FoldedVisuals.State:
|
||||
foldedLayer:
|
||||
True: {visible: true}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- type: entity
|
||||
- type: entity
|
||||
id: CrateArtifactContainer
|
||||
parent: BaseStructureDynamic
|
||||
name: artifact container
|
||||
@@ -24,6 +24,8 @@
|
||||
- state: locked
|
||||
map: ["enum.LockVisualLayers.Lock"]
|
||||
shader: unshaded
|
||||
- state: paper
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: InteractionOutline
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
@@ -73,6 +75,23 @@
|
||||
- type: EntityStorageVisuals
|
||||
stateDoorOpen: artifact_container_open
|
||||
stateDoorClosed: artifact_container_door
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.PaperLabelVisuals.HasLabel:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.PaperLabelVisuals.LabelType:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
Paper: { state: paper }
|
||||
Bounty: { state: bounty }
|
||||
CaptainsPaper: { state: captains_paper }
|
||||
Invoice: { state: invoice }
|
||||
enum.StorageVisuals.Open:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
True: { offset: "0.0,0.3125" }
|
||||
False: { offset: "0.0,0.0" }
|
||||
|
||||
- type: LockVisuals
|
||||
- type: ItemSlots
|
||||
- type: ContainerContainer
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
maxAngle: 16
|
||||
fireRate: 8
|
||||
angleIncrease: 3
|
||||
angleDecay: 16
|
||||
angleDecay: 16
|
||||
selectedMode: FullAuto
|
||||
availableModes:
|
||||
- SemiAuto
|
||||
@@ -95,6 +95,11 @@
|
||||
- type: Clothing
|
||||
sprite: Objects/Weapons/Guns/SMGs/c20r.rsi
|
||||
- type: Gun
|
||||
shotsPerBurst: 5
|
||||
availableModes:
|
||||
- SemiAuto
|
||||
- Burst
|
||||
- FullAuto
|
||||
soundGunshot:
|
||||
path: /Audio/Weapons/Guns/Gunshots/c-20r.ogg
|
||||
- type: ChamberMagazineAmmoProvider
|
||||
@@ -222,9 +227,16 @@
|
||||
- type: ChamberMagazineAmmoProvider
|
||||
boltClosed: null
|
||||
- type: Gun
|
||||
fireRate: 5
|
||||
fireRate: 5.5
|
||||
minAngle: 1
|
||||
maxAngle: 6
|
||||
angleIncrease: 1.5
|
||||
angleDecay: 6
|
||||
selectedMode: FullAuto
|
||||
shotsPerBurst: 5
|
||||
availableModes:
|
||||
- SemiAuto
|
||||
- Burst
|
||||
- FullAuto
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
components:
|
||||
- type: StationData
|
||||
|
||||
- type: entity
|
||||
id: BaseRandomStation
|
||||
abstract: true
|
||||
components:
|
||||
- type: StationRandomTransform
|
||||
|
||||
- type: entity
|
||||
id: BaseStationCargo
|
||||
abstract: true
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- BaseStationSiliconLawCrewsimov
|
||||
- BaseStationAllEventsEligible
|
||||
- BaseStationNanotrasen
|
||||
- BaseRandomStation
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Transform
|
||||
|
||||
@@ -53,18 +53,6 @@
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: ClothingUniformRandomArmless
|
||||
prob: 0.05
|
||||
orGroup: dressermainloot
|
||||
- id: ClothingUniformRandomStandart
|
||||
prob: 0.05
|
||||
orGroup: dressermainloot
|
||||
- id: ClothingUniformRandomBra
|
||||
prob: 0.05
|
||||
orGroup: dressermainloot
|
||||
- id: ClothingUniformRandomShorts
|
||||
prob: 0.05
|
||||
orGroup: dressermainloot
|
||||
- id: ClothingNeckLGBTPin
|
||||
prob: 0.06
|
||||
orGroup: dressermainloot
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
- state: welded
|
||||
visible: false
|
||||
map: ["enum.WeldableLayers.BaseWelded"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: InteractionOutline
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
@@ -55,6 +58,18 @@
|
||||
- type: EntityStorageVisuals
|
||||
stateDoorOpen: open
|
||||
stateDoorClosed: closed
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.PaperLabelVisuals.HasLabel:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.PaperLabelVisuals.LabelType:
|
||||
enum.PaperLabelVisuals.Layer:
|
||||
Paper: { state: paper }
|
||||
Bounty: { state: bounty }
|
||||
CaptainsPaper: { state: captains_paper }
|
||||
Invoice: { state: invoice }
|
||||
- type: PaperLabel
|
||||
labelSlot:
|
||||
insertVerbText: Attach Label
|
||||
@@ -106,6 +121,9 @@
|
||||
- state: locked
|
||||
map: ["enum.LockVisualLayers.Lock"]
|
||||
shader: unshaded
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: StructuralMetallic
|
||||
|
||||
@@ -138,6 +138,9 @@
|
||||
map: ["enum.StorageVisualLayers.Base"]
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Construction
|
||||
graph: WebStructures
|
||||
node: crate
|
||||
@@ -320,6 +323,10 @@
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "-0.25,0.625"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/livestock.rsi
|
||||
state: base
|
||||
@@ -371,6 +378,10 @@
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "0.0,0.125"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/cage.rsi
|
||||
- type: Destructible
|
||||
@@ -424,6 +435,10 @@
|
||||
- state: welded
|
||||
visible: false
|
||||
map: ["enum.WeldableLayers.BaseWelded"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "0.0,-0.09375"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/piratechest.rsi
|
||||
state: crate_icon
|
||||
@@ -449,6 +464,8 @@
|
||||
- state: welded
|
||||
visible: false
|
||||
map: ["enum.WeldableLayers.BaseWelded"]
|
||||
- state: paper
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/toybox.rsi
|
||||
state: crate_icon
|
||||
@@ -465,6 +482,8 @@
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/coffin.rsi
|
||||
state: base
|
||||
@@ -503,6 +522,10 @@
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "-0.28125,0.625"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/wooden_grave.rsi
|
||||
state: base
|
||||
@@ -547,6 +570,10 @@
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "-0.3125,0.5625"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/stone_grave.rsi
|
||||
state: base
|
||||
@@ -571,6 +598,17 @@
|
||||
sprite: Structures/Storage/Crates/trashcart.rsi
|
||||
- type: Sprite
|
||||
sprite: Structures/Storage/Crates/trashcart.rsi
|
||||
layers:
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: welded
|
||||
visible: false
|
||||
map: ["enum.WeldableLayers.BaseWelded"]
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "0.0,0.03125"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
|
||||
- type: entity
|
||||
parent: CrateBaseSecure
|
||||
@@ -581,6 +619,20 @@
|
||||
sprite: Structures/Storage/Crates/trashcart_jani.rsi
|
||||
- type: Sprite
|
||||
sprite: Structures/Storage/Crates/trashcart_jani.rsi
|
||||
layers:
|
||||
- state: base
|
||||
- state: closed
|
||||
map: ["enum.StorageVisualLayers.Door"]
|
||||
- state: welded
|
||||
visible: false
|
||||
map: ["enum.WeldableLayers.BaseWelded"]
|
||||
- state: locked
|
||||
map: ["enum.LockVisualLayers.Lock"]
|
||||
shader: unshaded
|
||||
- state: paper
|
||||
sprite: Structures/Storage/Crates/labels.rsi
|
||||
offset: "0.0,0.03125"
|
||||
map: ["enum.PaperLabelVisuals.Layer"]
|
||||
- type: AccessReader
|
||||
access: [["Janitor"]]
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
Dev:
|
||||
stationProto: StandardNanotrasenStation
|
||||
components:
|
||||
- type: StationRandomTransform
|
||||
enableStationRotation: false
|
||||
maxStationOffset: null
|
||||
- type: StationBiome
|
||||
- type: StationNameSetup
|
||||
mapNameTemplate: "Dev"
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
# Europa:
|
||||
# stationProto: StandardNanotrasenStation
|
||||
# components:
|
||||
# - type: StationRandomTransform
|
||||
# enableStationRotation: false
|
||||
# maxStationOffset: null
|
||||
# - type: StationNameSetup
|
||||
# mapNameTemplate: '{0} Europa {1}'
|
||||
# nameGenerator:
|
||||
@@ -61,3 +64,4 @@
|
||||
# Mime: [ 1, 1 ]
|
||||
# Musician: [ 1, 1 ]
|
||||
# Reporter: [ 1, 1 ]
|
||||
#
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
# Train:
|
||||
# stationProto: StandardNanotrasenStation
|
||||
# components:
|
||||
# - type: StationRandomTransform
|
||||
# enableStationRotation: false
|
||||
# - type: StationNameSetup
|
||||
# mapNameTemplate: 'Train "Sentipode" {0}-{1}'
|
||||
# nameGenerator:
|
||||
|
||||
6
Resources/Prototypes/NPCs/honkbot.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
- type: htnCompound
|
||||
id: HonkbotCompound
|
||||
branches:
|
||||
- tasks:
|
||||
- !type:HTNCompoundTask
|
||||
task: IdleCompound
|
||||
@@ -292,11 +292,11 @@
|
||||
- !type:JunctionPostGen
|
||||
width: 1
|
||||
entities:
|
||||
- AirlockHydroGlassLocked
|
||||
- AirlockGlass
|
||||
|
||||
- !type:JunctionPostGen
|
||||
entities:
|
||||
- AirlockHydroGlassLocked
|
||||
- AirlockGlass
|
||||
|
||||
- !type:AutoCablingPostGen
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
- type: latheRecipe
|
||||
id: Vape
|
||||
icon:
|
||||
sprite: Objects/Consumable/Smokeables/Vapes/vape-standart.rsi
|
||||
sprite: Objects/Consumable/Smokeables/Vapes/vape-standard.rsi
|
||||
state: icon
|
||||
result: Vape
|
||||
completetime: 2
|
||||
|
||||
|
Before Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 366 B |
|
Before Width: | Height: | Size: 357 B |
|
Before Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 446 B |
|
Before Width: | Height: | Size: 365 B |
|
Before Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 355 B |
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "icon"
|
||||
},
|
||||
{
|
||||
"name": "equipped-HAND",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 291 B |
|
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 225 B After Width: | Height: | Size: 225 B |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e",
|
||||
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e and modified by Flareguy for Space Station 14",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
|
Before Width: | Height: | Size: 428 B |
|
Before Width: | Height: | Size: 342 B |
|
Before Width: | Height: | Size: 324 B |