Backpack preferences. (#2864)

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
This commit is contained in:
Swept
2021-01-03 15:22:14 +00:00
committed by GitHub
parent 57b049d173
commit 81730e2612
36 changed files with 1455 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
using Content.Client.GameObjects.Components;
using Content.Client.GameObjects.Components;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.Interfaces;
using Content.Shared.GameTicking;
@@ -43,6 +43,7 @@ namespace Content.Client.UserInterface
private readonly Button _sexMaleButton;
private readonly OptionButton _genderButton;
private readonly OptionButton _clothingButton;
private readonly OptionButton _backpackButton;
private readonly HairStylePicker _hairPicker;
private readonly FacialHairStylePicker _facialHairPicker;
@@ -333,6 +334,33 @@ namespace Content.Client.UserInterface
}
#endregion Clothing
#region Backpack
{
var panel = HighlightedContainer();
var hBox = new HBoxContainer();
var backpackLabel = new Label { Text = Loc.GetString("Backpack:") };
_backpackButton = new OptionButton();
_backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack);
_backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel);
_backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag);
_backpackButton.OnItemSelected += args =>
{
_backpackButton.SelectId(args.Id);
SetBackpack((BackpackPreference) args.Id);
};
hBox.AddChild(backpackLabel);
hBox.AddChild(_backpackButton);
panel.AddChild(hBox);
appearanceVBox.AddChild(panel);
}
#endregion Clothing
}
#endregion
@@ -669,6 +697,12 @@ namespace Content.Client.UserInterface
IsDirty = true;
}
private void SetBackpack(BackpackPreference newBackpack)
{
Profile = Profile?.WithBackpackPreference(newBackpack);
IsDirty = true;
}
public void Save()
{
IsDirty = false;
@@ -723,6 +757,11 @@ namespace Content.Client.UserInterface
_clothingButton.SelectId((int) Profile.Clothing);
}
private void UpdateBackpackControls()
{
_backpackButton.SelectId((int) Profile.Backpack);
}
private void UpdateHairPickers()
{
_hairPicker.SetData(
@@ -754,6 +793,7 @@ namespace Content.Client.UserInterface
UpdateSexControls();
UpdateGenderControls();
UpdateClothingControls();
UpdateBackpackControls();
UpdateAgeEdit();
UpdateHairPickers();
UpdateSaveButton();

View File

@@ -0,0 +1,575 @@
// <auto-generated />
using System;
using System.Net;
using Content.Server.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Content.Server.Database.Migrations.Postgres
{
[DbContext(typeof(PostgresServerDbContext))]
[Migration("20210103151756_BackpackPreference")]
partial class BackpackPreference
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.UseIdentityByDefaultColumns()
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.0");
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasColumnName("user_id");
b.Property<int?>("AdminRankId")
.HasColumnType("integer")
.HasColumnName("admin_rank_id");
b.Property<string>("Title")
.HasColumnType("text")
.HasColumnName("title");
b.HasKey("UserId");
b.HasIndex("AdminRankId");
b.ToTable("admin");
});
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("admin_flag_id")
.UseIdentityByDefaultColumn();
b.Property<Guid>("AdminId")
.HasColumnType("uuid")
.HasColumnName("admin_id");
b.Property<string>("Flag")
.IsRequired()
.HasColumnType("text")
.HasColumnName("flag");
b.Property<bool>("Negative")
.HasColumnType("boolean")
.HasColumnName("negative");
b.HasKey("Id");
b.HasIndex("AdminId");
b.HasIndex("Flag", "AdminId")
.IsUnique();
b.ToTable("admin_flag");
});
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("admin_rank_id")
.UseIdentityByDefaultColumn();
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.HasKey("Id");
b.ToTable("admin_rank");
});
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("admin_rank_flag_id")
.UseIdentityByDefaultColumn();
b.Property<int>("AdminRankId")
.HasColumnType("integer")
.HasColumnName("admin_rank_id");
b.Property<string>("Flag")
.IsRequired()
.HasColumnType("text")
.HasColumnName("flag");
b.HasKey("Id");
b.HasIndex("AdminRankId");
b.HasIndex("Flag", "AdminRankId")
.IsUnique();
b.ToTable("admin_rank_flag");
});
modelBuilder.Entity("Content.Server.Database.Antag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("antag_id")
.UseIdentityByDefaultColumn();
b.Property<string>("AntagName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("antag_name");
b.Property<int>("ProfileId")
.HasColumnType("integer")
.HasColumnName("profile_id");
b.HasKey("Id");
b.HasIndex("ProfileId", "AntagName")
.IsUnique();
b.ToTable("antag");
});
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("assigned_user_id_id")
.UseIdentityByDefaultColumn();
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("user_name");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserName")
.IsUnique();
b.ToTable("assigned_user_id");
});
modelBuilder.Entity("Content.Server.Database.Job", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("job_id")
.UseIdentityByDefaultColumn();
b.Property<string>("JobName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("job_name");
b.Property<int>("Priority")
.HasColumnType("integer")
.HasColumnName("priority");
b.Property<int>("ProfileId")
.HasColumnType("integer")
.HasColumnName("profile_id");
b.HasKey("Id");
b.HasIndex("ProfileId");
b.ToTable("job");
});
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("connection_log_id")
.UseIdentityByDefaultColumn();
b.Property<IPAddress>("Address")
.IsRequired()
.HasColumnType("inet")
.HasColumnName("address");
b.Property<DateTime>("Time")
.HasColumnType("timestamp with time zone")
.HasColumnName("time");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("user_name");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("connection_log");
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
});
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("player_id")
.UseIdentityByDefaultColumn();
b.Property<DateTime>("FirstSeenTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("first_seen_time");
b.Property<IPAddress>("LastSeenAddress")
.IsRequired()
.HasColumnType("inet")
.HasColumnName("last_seen_address");
b.Property<DateTime>("LastSeenTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_seen_time");
b.Property<string>("LastSeenUserName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("last_seen_user_name");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("LastSeenUserName");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("player");
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
});
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("server_ban_id")
.UseIdentityByDefaultColumn();
b.Property<ValueTuple<IPAddress, int>?>("Address")
.HasColumnType("inet")
.HasColumnName("address");
b.Property<DateTime>("BanTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("ban_time");
b.Property<Guid?>("BanningAdmin")
.HasColumnType("uuid")
.HasColumnName("banning_admin");
b.Property<DateTime?>("ExpirationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("expiration_time");
b.Property<string>("Reason")
.IsRequired()
.HasColumnType("text")
.HasColumnName("reason");
b.Property<Guid?>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("Address");
b.HasIndex("UserId");
b.ToTable("server_ban");
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
});
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("unban_id")
.UseIdentityByDefaultColumn();
b.Property<int>("BanId")
.HasColumnType("integer")
.HasColumnName("ban_id");
b.Property<DateTime>("UnbanTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("unban_time");
b.Property<Guid?>("UnbanningAdmin")
.HasColumnType("uuid")
.HasColumnName("unbanning_admin");
b.HasKey("Id");
b.HasIndex("BanId")
.IsUnique();
b.ToTable("server_unban");
});
modelBuilder.Entity("Content.Server.Database.Preference", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("preference_id")
.UseIdentityByDefaultColumn();
b.Property<int>("SelectedCharacterSlot")
.HasColumnType("integer")
.HasColumnName("selected_character_slot");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("preference");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("profile_id")
.UseIdentityByDefaultColumn();
b.Property<int>("Age")
.HasColumnType("integer")
.HasColumnName("age");
b.Property<string>("Backpack")
.IsRequired()
.HasColumnType("text")
.HasColumnName("backpack");
b.Property<string>("CharacterName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("char_name");
b.Property<string>("Clothing")
.IsRequired()
.HasColumnType("text")
.HasColumnName("clothing");
b.Property<string>("EyeColor")
.IsRequired()
.HasColumnType("text")
.HasColumnName("eye_color");
b.Property<string>("FacialHairColor")
.IsRequired()
.HasColumnType("text")
.HasColumnName("facial_hair_color");
b.Property<string>("FacialHairName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("facial_hair_name");
b.Property<string>("Gender")
.IsRequired()
.HasColumnType("text")
.HasColumnName("gender");
b.Property<string>("HairColor")
.IsRequired()
.HasColumnType("text")
.HasColumnName("hair_color");
b.Property<string>("HairName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("hair_name");
b.Property<int>("PreferenceId")
.HasColumnType("integer")
.HasColumnName("preference_id");
b.Property<int>("PreferenceUnavailable")
.HasColumnType("integer")
.HasColumnName("pref_unavailable");
b.Property<string>("Sex")
.IsRequired()
.HasColumnType("text")
.HasColumnName("sex");
b.Property<string>("SkinColor")
.IsRequired()
.HasColumnType("text")
.HasColumnName("skin_color");
b.Property<int>("Slot")
.HasColumnType("integer")
.HasColumnName("slot");
b.HasKey("Id");
b.HasIndex("PreferenceId");
b.HasIndex("Slot", "PreferenceId")
.IsUnique();
b.ToTable("profile");
});
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
.WithMany("Admins")
.HasForeignKey("AdminRankId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("AdminRank");
});
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
{
b.HasOne("Content.Server.Database.Admin", "Admin")
.WithMany("Flags")
.HasForeignKey("AdminId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Admin");
});
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
{
b.HasOne("Content.Server.Database.AdminRank", "Rank")
.WithMany("Flags")
.HasForeignKey("AdminRankId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Rank");
});
modelBuilder.Entity("Content.Server.Database.Antag", b =>
{
b.HasOne("Content.Server.Database.Profile", "Profile")
.WithMany("Antags")
.HasForeignKey("ProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Profile");
});
modelBuilder.Entity("Content.Server.Database.Job", b =>
{
b.HasOne("Content.Server.Database.Profile", "Profile")
.WithMany("Jobs")
.HasForeignKey("ProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Profile");
});
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
{
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
.WithOne("Unban")
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ban");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.HasOne("Content.Server.Database.Preference", "Preference")
.WithMany("Profiles")
.HasForeignKey("PreferenceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Preference");
});
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.Navigation("Flags");
});
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
{
b.Navigation("Admins");
b.Navigation("Flags");
});
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
{
b.Navigation("Unban");
});
modelBuilder.Entity("Content.Server.Database.Preference", b =>
{
b.Navigation("Profiles");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.Navigation("Antags");
b.Navigation("Jobs");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Content.Server.Database.Migrations.Postgres
{
public partial class BackpackPreference : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "backpack",
table: "profile",
type: "text",
nullable: false,
defaultValue: "");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "backpack",
table: "profile");
}
}
}

View File

@@ -386,6 +386,11 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("integer")
.HasColumnName("age");
b.Property<string>("Backpack")
.IsRequired()
.HasColumnType("text")
.HasColumnName("backpack");
b.Property<string>("CharacterName")
.IsRequired()
.HasColumnType("text")

View File

@@ -0,0 +1,542 @@
// <auto-generated />
using System;
using Content.Server.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Content.Server.Database.Migrations.Sqlite
{
[DbContext(typeof(SqliteServerDbContext))]
[Migration("20210103151752_BackpackPreference")]
partial class BackpackPreference
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.0");
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.Property<int?>("AdminRankId")
.HasColumnType("INTEGER")
.HasColumnName("admin_rank_id");
b.Property<string>("Title")
.HasColumnType("TEXT")
.HasColumnName("title");
b.HasKey("UserId");
b.HasIndex("AdminRankId");
b.ToTable("admin");
});
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("admin_flag_id");
b.Property<Guid>("AdminId")
.HasColumnType("TEXT")
.HasColumnName("admin_id");
b.Property<string>("Flag")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("flag");
b.Property<bool>("Negative")
.HasColumnType("INTEGER")
.HasColumnName("negative");
b.HasKey("Id");
b.HasIndex("AdminId");
b.HasIndex("Flag", "AdminId")
.IsUnique();
b.ToTable("admin_flag");
});
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("admin_rank_id");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.HasKey("Id");
b.ToTable("admin_rank");
});
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("admin_rank_flag_id");
b.Property<int>("AdminRankId")
.HasColumnType("INTEGER")
.HasColumnName("admin_rank_id");
b.Property<string>("Flag")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("flag");
b.HasKey("Id");
b.HasIndex("AdminRankId");
b.HasIndex("Flag", "AdminRankId")
.IsUnique();
b.ToTable("admin_rank_flag");
});
modelBuilder.Entity("Content.Server.Database.Antag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("antag_id");
b.Property<string>("AntagName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("antag_name");
b.Property<int>("ProfileId")
.HasColumnType("INTEGER")
.HasColumnName("profile_id");
b.HasKey("Id");
b.HasIndex("ProfileId", "AntagName")
.IsUnique();
b.ToTable("antag");
});
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("assigned_user_id_id");
b.Property<Guid>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("user_name");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserName")
.IsUnique();
b.ToTable("assigned_user_id");
});
modelBuilder.Entity("Content.Server.Database.Job", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("job_id");
b.Property<string>("JobName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("job_name");
b.Property<int>("Priority")
.HasColumnType("INTEGER")
.HasColumnName("priority");
b.Property<int>("ProfileId")
.HasColumnType("INTEGER")
.HasColumnName("profile_id");
b.HasKey("Id");
b.HasIndex("ProfileId");
b.ToTable("job");
});
modelBuilder.Entity("Content.Server.Database.Preference", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("preference_id");
b.Property<int>("SelectedCharacterSlot")
.HasColumnType("INTEGER")
.HasColumnName("selected_character_slot");
b.Property<Guid>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("preference");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("profile_id");
b.Property<int>("Age")
.HasColumnType("INTEGER")
.HasColumnName("age");
b.Property<string>("Backpack")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("backpack");
b.Property<string>("CharacterName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("char_name");
b.Property<string>("Clothing")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("clothing");
b.Property<string>("EyeColor")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("eye_color");
b.Property<string>("FacialHairColor")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("facial_hair_color");
b.Property<string>("FacialHairName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("facial_hair_name");
b.Property<string>("Gender")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("gender");
b.Property<string>("HairColor")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("hair_color");
b.Property<string>("HairName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("hair_name");
b.Property<int>("PreferenceId")
.HasColumnType("INTEGER")
.HasColumnName("preference_id");
b.Property<int>("PreferenceUnavailable")
.HasColumnType("INTEGER")
.HasColumnName("pref_unavailable");
b.Property<string>("Sex")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("sex");
b.Property<string>("SkinColor")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("skin_color");
b.Property<int>("Slot")
.HasColumnType("INTEGER")
.HasColumnName("slot");
b.HasKey("Id");
b.HasIndex("PreferenceId");
b.HasIndex("Slot", "PreferenceId")
.IsUnique();
b.ToTable("profile");
});
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("connection_log_id");
b.Property<string>("Address")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("address");
b.Property<DateTime>("Time")
.HasColumnType("TEXT")
.HasColumnName("time");
b.Property<Guid>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("user_name");
b.HasKey("Id");
b.ToTable("connection_log");
});
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("player_id");
b.Property<DateTime>("FirstSeenTime")
.HasColumnType("TEXT")
.HasColumnName("first_seen_time");
b.Property<string>("LastSeenAddress")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("last_seen_address");
b.Property<DateTime>("LastSeenTime")
.HasColumnType("TEXT")
.HasColumnName("last_seen_time");
b.Property<string>("LastSeenUserName")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("last_seen_user_name");
b.Property<Guid>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("Id");
b.HasIndex("LastSeenUserName");
b.ToTable("player");
});
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("ban_id");
b.Property<string>("Address")
.HasColumnType("TEXT")
.HasColumnName("address");
b.Property<DateTime>("BanTime")
.HasColumnType("TEXT")
.HasColumnName("ban_time");
b.Property<Guid?>("BanningAdmin")
.HasColumnType("TEXT")
.HasColumnName("banning_admin");
b.Property<DateTime?>("ExpirationTime")
.HasColumnType("TEXT")
.HasColumnName("expiration_time");
b.Property<string>("Reason")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("reason");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("Id");
b.ToTable("ban");
});
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("unban_id");
b.Property<int>("BanId")
.HasColumnType("INTEGER")
.HasColumnName("ban_id");
b.Property<DateTime>("UnbanTime")
.HasColumnType("TEXT")
.HasColumnName("unban_time");
b.Property<Guid?>("UnbanningAdmin")
.HasColumnType("TEXT")
.HasColumnName("unbanning_admin");
b.HasKey("Id");
b.HasIndex("BanId")
.IsUnique();
b.ToTable("unban");
});
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
.WithMany("Admins")
.HasForeignKey("AdminRankId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("AdminRank");
});
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
{
b.HasOne("Content.Server.Database.Admin", "Admin")
.WithMany("Flags")
.HasForeignKey("AdminId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Admin");
});
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
{
b.HasOne("Content.Server.Database.AdminRank", "Rank")
.WithMany("Flags")
.HasForeignKey("AdminRankId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Rank");
});
modelBuilder.Entity("Content.Server.Database.Antag", b =>
{
b.HasOne("Content.Server.Database.Profile", "Profile")
.WithMany("Antags")
.HasForeignKey("ProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Profile");
});
modelBuilder.Entity("Content.Server.Database.Job", b =>
{
b.HasOne("Content.Server.Database.Profile", "Profile")
.WithMany("Jobs")
.HasForeignKey("ProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Profile");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.HasOne("Content.Server.Database.Preference", "Preference")
.WithMany("Profiles")
.HasForeignKey("PreferenceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Preference");
});
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
{
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
.WithOne("Unban")
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ban");
});
modelBuilder.Entity("Content.Server.Database.Admin", b =>
{
b.Navigation("Flags");
});
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
{
b.Navigation("Admins");
b.Navigation("Flags");
});
modelBuilder.Entity("Content.Server.Database.Preference", b =>
{
b.Navigation("Profiles");
});
modelBuilder.Entity("Content.Server.Database.Profile", b =>
{
b.Navigation("Antags");
b.Navigation("Jobs");
});
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
{
b.Navigation("Unban");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Content.Server.Database.Migrations.Sqlite
{
public partial class BackpackPreference : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "backpack",
table: "profile",
type: "TEXT",
nullable: false,
defaultValue: "");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "backpack",
table: "profile");
}
}
}

View File

@@ -223,6 +223,11 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("INTEGER")
.HasColumnName("age");
b.Property<string>("Backpack")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("backpack");
b.Property<string>("CharacterName")
.IsRequired()
.HasColumnType("TEXT")

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -99,6 +99,7 @@ namespace Content.Server.Database
[Column("eye_color")] public string EyeColor { get; set; } = null!;
[Column("skin_color")] public string SkinColor { get; set; } = null!;
[Column("clothing")] public string Clothing { get; set; } = null!;
[Column("backpack")] public string Backpack { get; set; } = null!;
public List<Job> Jobs { get; } = new();
public List<Antag> Antags { get; } = new();

View File

@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
@@ -140,6 +140,10 @@ namespace Content.Server.Database
if (Enum.TryParse<ClothingPreference>(profile.Clothing, true, out var clothingVal))
clothing = clothingVal;
var backpack = BackpackPreference.Backpack;
if (Enum.TryParse<BackpackPreference>(profile.Backpack, true, out var backpackVal))
backpack = backpackVal;
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
if (Enum.TryParse<Gender>(profile.Gender, true, out var genderVal))
gender = genderVal;
@@ -159,6 +163,7 @@ namespace Content.Server.Database
Color.FromHex(profile.SkinColor)
),
clothing,
backpack,
jobs,
(PreferenceUnavailableMode) profile.PreferenceUnavailable,
antags.ToList()
@@ -182,6 +187,7 @@ namespace Content.Server.Database
EyeColor = appearance.EyeColor.ToHex(),
SkinColor = appearance.SkinColor.ToHex(),
Clothing = humanoid.Clothing.ToString(),
Backpack = humanoid.Backpack.ToString(),
Slot = slot,
PreferenceUnavailable = (DbPreferenceUnavailableMode) humanoid.PreferenceUnavailable
};

View File

@@ -0,0 +1,12 @@
namespace Content.Shared.Preferences
{
/// <summary>
/// The backpack preference for a profile. Stored in database!
/// </summary>
public enum BackpackPreference
{
Backpack,
Satchel,
Duffelbag
}
}

View File

@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
@@ -34,6 +34,7 @@ namespace Content.Shared.Preferences
Gender gender,
HumanoidCharacterAppearance appearance,
ClothingPreference clothing,
BackpackPreference backpack,
Dictionary<string, JobPriority> jobPriorities,
PreferenceUnavailableMode preferenceUnavailable,
List<string> antagPreferences)
@@ -44,6 +45,7 @@ namespace Content.Shared.Preferences
Gender = gender;
Appearance = appearance;
Clothing = clothing;
Backpack = backpack;
_jobPriorities = jobPriorities;
PreferenceUnavailable = preferenceUnavailable;
_antagPreferences = antagPreferences;
@@ -54,7 +56,7 @@ namespace Content.Shared.Preferences
HumanoidCharacterProfile other,
Dictionary<string, JobPriority> jobPriorities,
List<string> antagPreferences)
: this(other.Name, other.Age, other.Sex, other.Gender, other.Appearance, other.Clothing,
: this(other.Name, other.Age, other.Sex, other.Gender, other.Appearance, other.Clothing, other.Backpack,
jobPriorities, other.PreferenceUnavailable, antagPreferences)
{
}
@@ -72,10 +74,11 @@ namespace Content.Shared.Preferences
Gender gender,
HumanoidCharacterAppearance appearance,
ClothingPreference clothing,
BackpackPreference backpack,
IReadOnlyDictionary<string, JobPriority> jobPriorities,
PreferenceUnavailableMode preferenceUnavailable,
IReadOnlyList<string> antagPreferences)
: this(name, age, sex, gender, appearance, clothing, new Dictionary<string, JobPriority>(jobPriorities),
: this(name, age, sex, gender, appearance, clothing, backpack, new Dictionary<string, JobPriority>(jobPriorities),
preferenceUnavailable, new List<string>(antagPreferences))
{
}
@@ -98,7 +101,7 @@ namespace Content.Shared.Preferences
var name = $"{firstName} {lastName}";
var age = random.Next(MinimumAge, MaximumAge);
return new HumanoidCharacterProfile(name, age, sex, gender, HumanoidCharacterAppearance.Random(sex), ClothingPreference.Jumpsuit,
return new HumanoidCharacterProfile(name, age, sex, gender, HumanoidCharacterAppearance.Random(sex), ClothingPreference.Jumpsuit, BackpackPreference.Backpack,
new Dictionary<string, JobPriority>
{
{SharedGameTicker.OverflowJob, JobPriority.High}
@@ -112,6 +115,7 @@ namespace Content.Shared.Preferences
public ICharacterAppearance CharacterAppearance => Appearance;
public HumanoidCharacterAppearance Appearance { get; private set; }
public ClothingPreference Clothing { get; private set; }
public BackpackPreference Backpack { get; private set; }
public IReadOnlyDictionary<string, JobPriority> JobPriorities => _jobPriorities;
public IReadOnlyList<string> AntagPreferences => _antagPreferences;
public PreferenceUnavailableMode PreferenceUnavailable { get; private set; }
@@ -145,7 +149,10 @@ namespace Content.Shared.Preferences
{
return new(this) { Clothing = clothing };
}
public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack)
{
return new(this) { Backpack = backpack };
}
public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities)
{
return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences);
@@ -254,6 +261,14 @@ namespace Content.Shared.Preferences
_ => ClothingPreference.Jumpsuit // Invalid enum values.
};
var backpack = profile.Backpack switch
{
BackpackPreference.Backpack => BackpackPreference.Backpack,
BackpackPreference.Satchel => BackpackPreference.Satchel,
BackpackPreference.Duffelbag => BackpackPreference.Duffelbag,
_ => BackpackPreference.Backpack // Invalid enum values.
};
var priorities = new Dictionary<string, JobPriority>(profile.JobPriorities
.Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch
{
@@ -268,7 +283,7 @@ namespace Content.Shared.Preferences
.Where(prototypeManager.HasIndex<AntagPrototype>)
.ToList();
return new HumanoidCharacterProfile(name, age, sex, gender, appearance, clothing, priorities, prefsUnavailableMode, antags);
return new HumanoidCharacterProfile(name, age, sex, gender, appearance, clothing, backpack, priorities, prefsUnavailableMode, antags);
}
public string Summary =>
@@ -283,6 +298,7 @@ namespace Content.Shared.Preferences
if (Gender != other.Gender) return false;
if (PreferenceUnavailable != other.PreferenceUnavailable) return false;
if (Clothing != other.Clothing) return false;
if (Backpack != other.Backpack) return false;
if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false;
if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false;
return Appearance.MemberwiseEquals(other.Appearance);
@@ -302,7 +318,8 @@ namespace Content.Shared.Preferences
Sex,
Gender,
Appearance,
Clothing
Clothing,
Backpack
),
PreferenceUnavailable,
_jobPriorities,

View File

@@ -21,6 +21,8 @@ namespace Content.Shared.Roles
/// if empty, there is no skirt override - instead the uniform provided in equipment is added.
/// </summary>
private string _innerClothingSkirt = default!;
private string _satchel = default!;
private string _duffelbag = default!;
public IReadOnlyDictionary<string, string> Inhand => _inHand;
/// <summary>
@@ -51,6 +53,8 @@ namespace Content.Shared.Roles
}, type => type.Value);
serializer.DataField(ref _innerClothingSkirt, "innerclothingskirt", string.Empty);
serializer.DataField(ref _satchel, "satchel", string.Empty);
serializer.DataField(ref _duffelbag, "duffelbag", string.Empty);
}
public string GetGear(Slots slot, HumanoidCharacterProfile? profile)
@@ -59,6 +63,10 @@ namespace Content.Shared.Roles
{
if ((slot == Slots.INNERCLOTHING) && (profile.Clothing == ClothingPreference.Jumpskirt) && (_innerClothingSkirt != ""))
return _innerClothingSkirt;
if ((slot == Slots.BACKPACK) && (profile.Backpack == BackpackPreference.Satchel) && (_satchel != ""))
return _satchel;
if ((slot == Slots.BACKPACK) && (profile.Backpack == BackpackPreference.Duffelbag) && (_duffelbag != ""))
return _duffelbag;
}
if (_equipment.ContainsKey(slot))

View File

@@ -36,6 +36,7 @@ namespace Content.Tests.Server.Preferences
Color.Beige
),
ClothingPreference.Jumpskirt,
BackpackPreference.Backpack,
new Dictionary<string, JobPriority>
{
{SharedGameTicker.OverflowJob, JobPriority.High}

View File

@@ -0,0 +1,75 @@
- type: entity
abstract: true
parent: ClothingBackpackDuffel
id: ClothingBackpackDuffelFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- type: entity
abstract: true
parent: ClothingBackpackDuffelClown
id: ClothingBackpackDuffelClownFilled
components:
- type: StorageFill
contents:
- name: BoxHug
- type: entity
abstract: true
parent: ClothingBackpackDuffelSecurity
id: ClothingBackpackDuffelSecurityFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- name: Stunbaton
- name: Flash
- type: entity
abstract: true
parent: ClothingBackpackDuffelMedical
id: ClothingBackpackDuffelMedicalFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- type: entity
abstract: true
parent: ClothingBackpackDuffelCaptain
id: ClothingBackpackDuffelCaptainFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
#- name: StationCharter
#- name: TelescopicBaton
- type: entity
abstract: true
parent: ClothingBackpackDuffelEngineering
id: ClothingBackpackDuffelEngineeringFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
#- type: entity
# abstract: true
# parent: ClothingBackpackDuffelScience
# id: ClothingBackpackDuffelScienceFilled
# components:
# - type: StorageFill
# contents:
# - name: BoxSurvival
#- type: entity
# abstract: true
# parent: ClothingBackpackDuffelChemistry
# id: ClothingBackpackDuffelChemistryFilled
# components:
# - type: StorageFill
# contents:
# - name: BoxSurvival

View File

@@ -0,0 +1,75 @@
- type: entity
abstract: true
parent: ClothingBackpackSatchel
id: ClothingBackpackSatchelFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
#- type: entity
# abstract: true
# parent: ClothingBackpackSatchelClown
# id: ClothingBackpackSatchelClownFilled
# components:
# - type: StorageFill
# contents:
# - name: BoxHug
- type: entity
abstract: true
parent: ClothingBackpackSatchelSecurity
id: ClothingBackpackSatchelSecurityFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- name: Stunbaton
- name: Flash
- type: entity
abstract: true
parent: ClothingBackpackSatchelMedical
id: ClothingBackpackSatchelMedicalFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- type: entity
abstract: true
parent: ClothingBackpackSatchelCaptain
id: ClothingBackpackSatchelCaptainFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
#- name: StationCharter
#- name: TelescopicBaton
- type: entity
abstract: true
parent: ClothingBackpackSatchelEngineering
id: ClothingBackpackSatchelEngineeringFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- type: entity
abstract: true
parent: ClothingBackpackSatchelScience
id: ClothingBackpackSatchelScienceFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival
- type: entity
abstract: true
parent: ClothingBackpackSatchelChemistry
id: ClothingBackpackSatchelChemistryFilled
components:
- type: StorageFill
contents:
- name: BoxSurvival

View File

@@ -21,4 +21,5 @@
idcard: CargoPDA
ears: ClothingHeadsetCargo
innerclothingskirt: ClothingUniformJumpskirtCargo
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -22,4 +22,5 @@
idcard: QuartermasterPDA
ears: ClothingHeadsetCargo
innerclothingskirt: ClothingUniformJumpskirtQM
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -18,4 +18,5 @@
idcard: AssistantPDA
ears: ClothingHeadsetService
innerclothingskirt: ClothingUniformJumpskirtColorGrey
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -22,4 +22,5 @@
idcard: BartenderPDA
ears: ClothingHeadsetService
innerclothingskirt: ClothingUniformJumpskirtBartender
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -22,4 +22,5 @@
ears: ClothingHeadsetService
outerclothing: ClothingOuterApronBotanist
innerclothingskirt: ClothingUniformJumpskirtHydroponics
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -22,4 +22,5 @@
ears: ClothingHeadsetService
outerclothing: ClothingOuterApronChef
innerclothingskirt: ClothingUniformJumpskirtChef
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -21,3 +21,4 @@
pocket1: BikeHorn
idcard: ClownPDA
ears: ClothingHeadsetService
duffelbag: ClothingBackpackDuffelClownFilled

View File

@@ -21,4 +21,5 @@
ears: ClothingHeadsetService
belt: ClothingBeltJanitorFilled
innerclothingskirt: ClothingUniformJumpskirtJanitor
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -48,3 +48,5 @@
outerclothing: ClothingOuterHardsuitCap
idcard: CaptainPDA
ears: ClothingHeadsetAltCommand
satchel: ClothingBackpackSatchelCaptainFilled
duffelbag: ClothingBackpackDuffelCaptainFilled

View File

@@ -29,4 +29,5 @@
idcard: HoPPDA
ears: ClothingHeadsetAltCommand
innerclothingskirt: ClothingUniformJumpskirtHoP
satchel: ClothingBackpackSatchelFilled
duffelbag: ClothingBackpackDuffelFilled

View File

@@ -26,4 +26,5 @@
ears: ClothingHeadsetEngineering
belt: ClothingBeltChiefEngineerFilled
innerclothingskirt: ClothingUniformJumpskirtChiefEngineer
satchel: ClothingBackpackSatchelEngineeringFilled
duffelbag: ClothingBackpackDuffelEngineeringFilled

View File

@@ -24,4 +24,5 @@
belt: ClothingBeltUtilityFilled
ears: ClothingHeadsetEngineering
innerclothingskirt: ClothingUniformJumpskirtEngineering
satchel: ClothingBackpackSatchelEngineeringFilled
duffelbag: ClothingBackpackDuffelEngineeringFilled

View File

@@ -27,4 +27,5 @@
ears: ClothingHeadsetAltMedical
belt: ClothingBeltMedical
innerclothingskirt: ClothingUniformJumpskirtCMO
satchel: ClothingBackpackSatchelMedicalFilled
duffelbag: ClothingBackpackDuffelMedicalFilled

View File

@@ -22,4 +22,5 @@
ears: ClothingHeadsetMedical
belt: ClothingBeltMedical
innerclothingskirt: ClothingUniformJumpskirtMedicalDoctor
satchel: ClothingBackpackSatchelMedicalFilled
duffelbag: ClothingBackpackDuffelMedicalFilled

View File

@@ -23,4 +23,4 @@
idcard: RnDPDA
ears: ClothingHeadsetScience
innerclothingskirt: ClothingUniformJumpskirtResearchDirector
satchel: ClothingBackpackSatchelScienceFilled

View File

@@ -21,4 +21,4 @@
idcard: SciencePDA
ears: ClothingHeadsetScience
innerclothingskirt: ClothingUniformJumpskirtScientist
satchel: ClothingBackpackSatchelScienceFilled

View File

@@ -30,4 +30,5 @@
ears: ClothingHeadsetAltSecurity
belt: ClothingBeltSecurityFilled
innerclothingskirt: ClothingUniformJumpskirtHoS
satchel: ClothingBackpackSatchelSecurityFilled
duffelbag: ClothingBackpackDuffelSecurityFilled

View File

@@ -25,4 +25,5 @@
ears: ClothingHeadsetSecurity
belt: ClothingBeltSecurityFilled
innerclothingskirt: ClothingUniformJumpskirtSec
satchel: ClothingBackpackSatchelSecurityFilled
duffelbag: ClothingBackpackDuffelSecurityFilled

View File

@@ -26,4 +26,5 @@
ears: ClothingHeadsetSecurity
belt: ClothingBeltSecurityFilled
innerclothingskirt: ClothingUniformJumpskirtWarden
satchel: ClothingBackpackSatchelSecurityFilled
duffelbag: ClothingBackpackDuffelSecurityFilled