Loadouts redux (#25715)
* Loadouts redux * Loadout window mockup * More workout * rent * validation * Developments * bcs * More cleanup * Rebuild working * Fix model and loading * obsession * efcore * We got a stew goin * Cleanup * Optional + SeniorEngineering fix * Fixes * Update science.yml * add add * Automatic naming * Update nukeops * Coming together * Right now * stargate * rejig the UI * weh * Loadouts tweaks * Merge conflicts + ordering fix * yerba mate * chocolat * More updates * Add multi-selection support * test h * fikss * a * add tech assistant and hazard suit * huh * Latest changes * add medical loadouts * and science * finish security loadouts * cargo * service done * added wildcards * add command * Move restrictions * Finalising * Fix existing work * Localise next batch * clothing fix * Fix storage names * review * the scooping room * Test fixes * Xamlify * Xamlify this too * Update Resources/Prototypes/Loadouts/Jobs/Medical/paramedic.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/loadout_groups.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/Jobs/Civilian/clown.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/Jobs/Civilian/clown.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/loadout_groups.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/Jobs/Security/detective.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * Update Resources/Prototypes/Loadouts/loadout_groups.yml Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com> * ben * Margins --------- Co-authored-by: Firewatch <54725557+musicmanvr@users.noreply.github.com> Co-authored-by: Mr. 27 <koolthunder019@gmail.com> Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com>
This commit is contained in:
@@ -58,7 +58,7 @@ public class SpawnEquipDeleteBenchmark
|
|||||||
for (var i = 0; i < N; i++)
|
for (var i = 0; i < N; i++)
|
||||||
{
|
{
|
||||||
_entity = server.EntMan.SpawnAttachedTo(Mob, _coords);
|
_entity = server.EntMan.SpawnAttachedTo(Mob, _coords);
|
||||||
_spawnSys.EquipStartingGear(_entity, _gear, null);
|
_spawnSys.EquipStartingGear(_entity, _gear);
|
||||||
server.EntMan.DeleteEntity(_entity);
|
server.EntMan.DeleteEntity(_entity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ using Content.Shared.Module;
|
|||||||
using Content.Client.Guidebook;
|
using Content.Client.Guidebook;
|
||||||
using Content.Client.Replay;
|
using Content.Client.Replay;
|
||||||
using Content.Shared.Administration.Managers;
|
using Content.Shared.Administration.Managers;
|
||||||
|
using Content.Shared.Players.PlayTimeTracking;
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Client.IoC
|
namespace Content.Client.IoC
|
||||||
@@ -29,26 +30,29 @@ namespace Content.Client.IoC
|
|||||||
{
|
{
|
||||||
public static void Register()
|
public static void Register()
|
||||||
{
|
{
|
||||||
IoCManager.Register<IParallaxManager, ParallaxManager>();
|
var collection = IoCManager.Instance!;
|
||||||
IoCManager.Register<IChatManager, ChatManager>();
|
|
||||||
IoCManager.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
collection.Register<IParallaxManager, ParallaxManager>();
|
||||||
IoCManager.Register<IStylesheetManager, StylesheetManager>();
|
collection.Register<IChatManager, ChatManager>();
|
||||||
IoCManager.Register<IScreenshotHook, ScreenshotHook>();
|
collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
||||||
IoCManager.Register<FullscreenHook, FullscreenHook>();
|
collection.Register<IStylesheetManager, StylesheetManager>();
|
||||||
IoCManager.Register<IClickMapManager, ClickMapManager>();
|
collection.Register<IScreenshotHook, ScreenshotHook>();
|
||||||
IoCManager.Register<IClientAdminManager, ClientAdminManager>();
|
collection.Register<FullscreenHook, FullscreenHook>();
|
||||||
IoCManager.Register<ISharedAdminManager, ClientAdminManager>();
|
collection.Register<IClickMapManager, ClickMapManager>();
|
||||||
IoCManager.Register<EuiManager, EuiManager>();
|
collection.Register<IClientAdminManager, ClientAdminManager>();
|
||||||
IoCManager.Register<IVoteManager, VoteManager>();
|
collection.Register<ISharedAdminManager, ClientAdminManager>();
|
||||||
IoCManager.Register<ChangelogManager, ChangelogManager>();
|
collection.Register<EuiManager, EuiManager>();
|
||||||
IoCManager.Register<RulesManager, RulesManager>();
|
collection.Register<IVoteManager, VoteManager>();
|
||||||
IoCManager.Register<ViewportManager, ViewportManager>();
|
collection.Register<ChangelogManager, ChangelogManager>();
|
||||||
IoCManager.Register<ISharedAdminLogManager, SharedAdminLogManager>();
|
collection.Register<RulesManager, RulesManager>();
|
||||||
IoCManager.Register<GhostKickManager>();
|
collection.Register<ViewportManager, ViewportManager>();
|
||||||
IoCManager.Register<ExtendedDisconnectInformationManager>();
|
collection.Register<ISharedAdminLogManager, SharedAdminLogManager>();
|
||||||
IoCManager.Register<JobRequirementsManager>();
|
collection.Register<GhostKickManager>();
|
||||||
IoCManager.Register<DocumentParsingManager>();
|
collection.Register<ExtendedDisconnectInformationManager>();
|
||||||
IoCManager.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
collection.Register<JobRequirementsManager>();
|
||||||
|
collection.Register<DocumentParsingManager>();
|
||||||
|
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
||||||
|
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace Content.Client.Lobby
|
|||||||
_characterSetup.SaveButton.OnPressed += _ =>
|
_characterSetup.SaveButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
_characterSetup.Save();
|
_characterSetup.Save();
|
||||||
_lobby.CharacterPreview.UpdateUI();
|
_userInterfaceManager.GetUIController<LobbyUIController>().UpdateCharacterUI();
|
||||||
};
|
};
|
||||||
|
|
||||||
LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide);
|
LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide);
|
||||||
@@ -84,10 +84,6 @@ namespace Content.Client.Lobby
|
|||||||
_gameTicker.InfoBlobUpdated += UpdateLobbyUi;
|
_gameTicker.InfoBlobUpdated += UpdateLobbyUi;
|
||||||
_gameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
|
_gameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
|
||||||
_gameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
|
_gameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
|
||||||
|
|
||||||
_preferencesManager.OnServerDataLoaded += PreferencesDataLoaded;
|
|
||||||
|
|
||||||
_lobby.CharacterPreview.UpdateUI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Shutdown()
|
protected override void Shutdown()
|
||||||
@@ -109,13 +105,6 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
_characterSetup?.Dispose();
|
_characterSetup?.Dispose();
|
||||||
_characterSetup = null;
|
_characterSetup = null;
|
||||||
|
|
||||||
_preferencesManager.OnServerDataLoaded -= PreferencesDataLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PreferencesDataLoaded()
|
|
||||||
{
|
|
||||||
_lobby?.CharacterPreview.UpdateUI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSetupPressed(BaseButton.ButtonEventArgs args)
|
private void OnSetupPressed(BaseButton.ButtonEventArgs args)
|
||||||
|
|||||||
223
Content.Client/Lobby/LobbyUIController.cs
Normal file
223
Content.Client/Lobby/LobbyUIController.cs
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Client.Humanoid;
|
||||||
|
using Content.Client.Inventory;
|
||||||
|
using Content.Client.Lobby.UI;
|
||||||
|
using Content.Client.Preferences;
|
||||||
|
using Content.Client.Station;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Client.State;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controllers;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Lobby;
|
||||||
|
|
||||||
|
public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState>, IOnStateExited<LobbyState>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||||
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||||
|
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
|
||||||
|
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
|
||||||
|
|
||||||
|
private LobbyCharacterPreviewPanel? _previewPanel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each character profile has its own dummy. There is also a dummy for the lobby screen + character editor
|
||||||
|
* that is shared too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preview dummy for role gear.
|
||||||
|
/// </summary>
|
||||||
|
private EntityUid? _previewDummy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If we currently have a loadout selected.
|
||||||
|
/// </summary>
|
||||||
|
private JobPrototype? _dummyJob;
|
||||||
|
|
||||||
|
// TODO: Load the species directly and don't update entity ever.
|
||||||
|
public event Action<EntityUid>? PreviewDummyUpdated;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_preferencesManager.OnServerDataLoaded += PreferencesDataLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PreferencesDataLoaded()
|
||||||
|
{
|
||||||
|
UpdateCharacterUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnStateEntered(LobbyState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnStateExited(LobbyState state)
|
||||||
|
{
|
||||||
|
EntityManager.DeleteEntity(_previewDummy);
|
||||||
|
_previewDummy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPreviewPanel(LobbyCharacterPreviewPanel? panel)
|
||||||
|
{
|
||||||
|
_previewPanel = panel;
|
||||||
|
UpdateCharacterUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDummyJob(JobPrototype? job)
|
||||||
|
{
|
||||||
|
_dummyJob = job;
|
||||||
|
UpdateCharacterUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateCharacterUI()
|
||||||
|
{
|
||||||
|
// Test moment
|
||||||
|
if (_stateManager.CurrentState is not LobbyState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_preferencesManager.ServerDataLoaded)
|
||||||
|
{
|
||||||
|
_previewPanel?.SetLoaded(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_previewPanel?.SetLoaded(true);
|
||||||
|
|
||||||
|
if (_preferencesManager.Preferences?.SelectedCharacter is not HumanoidCharacterProfile selectedCharacter)
|
||||||
|
{
|
||||||
|
_previewPanel?.SetSummaryText(string.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EntityManager.DeleteEntity(_previewDummy);
|
||||||
|
_previewDummy = EntityManager.SpawnEntity(_prototypeManager.Index<SpeciesPrototype>(selectedCharacter.Species).DollPrototype, MapCoordinates.Nullspace);
|
||||||
|
_previewPanel?.SetSprite(_previewDummy.Value);
|
||||||
|
_previewPanel?.SetSummaryText(selectedCharacter.Summary);
|
||||||
|
_humanoid.LoadProfile(_previewDummy.Value, selectedCharacter);
|
||||||
|
|
||||||
|
GiveDummyJobClothesLoadout(_previewDummy.Value, selectedCharacter);
|
||||||
|
PreviewDummyUpdated?.Invoke(_previewDummy.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the highest priority job's clothes to the dummy.
|
||||||
|
/// </summary>
|
||||||
|
public void GiveDummyJobClothesLoadout(EntityUid dummy, HumanoidCharacterProfile profile)
|
||||||
|
{
|
||||||
|
var job = _dummyJob ?? GetPreferredJob(profile);
|
||||||
|
GiveDummyJobClothes(dummy, profile, job);
|
||||||
|
|
||||||
|
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
|
||||||
|
{
|
||||||
|
var loadout = profile.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), EntityManager, _prototypeManager);
|
||||||
|
GiveDummyLoadout(dummy, loadout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the highest priority job for the profile.
|
||||||
|
/// </summary>
|
||||||
|
public JobPrototype GetPreferredJob(HumanoidCharacterProfile profile)
|
||||||
|
{
|
||||||
|
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
|
||||||
|
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract (what is resharper smoking?)
|
||||||
|
return _prototypeManager.Index<JobPrototype>(highPriorityJob ?? SharedGameTicker.FallbackOverflowJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GiveDummyLoadout(EntityUid uid, RoleLoadout? roleLoadout)
|
||||||
|
{
|
||||||
|
if (roleLoadout == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var group in roleLoadout.SelectedLoadouts.Values)
|
||||||
|
{
|
||||||
|
foreach (var loadout in group)
|
||||||
|
{
|
||||||
|
if (!_prototypeManager.TryIndex(loadout.Prototype, out var loadoutProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_spawn.EquipStartingGear(uid, _prototypeManager.Index(loadoutProto.Equipment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the specified job's clothes to the dummy.
|
||||||
|
/// </summary>
|
||||||
|
public void GiveDummyJobClothes(EntityUid dummy, HumanoidCharacterProfile profile, JobPrototype job)
|
||||||
|
{
|
||||||
|
if (!_inventory.TryGetSlots(dummy, out var slots))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Apply loadout
|
||||||
|
if (profile.Loadouts.TryGetValue(job.ID, out var jobLoadout))
|
||||||
|
{
|
||||||
|
foreach (var loadouts in jobLoadout.SelectedLoadouts.Values)
|
||||||
|
{
|
||||||
|
foreach (var loadout in loadouts)
|
||||||
|
{
|
||||||
|
if (!_prototypeManager.TryIndex(loadout.Prototype, out var loadoutProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// TODO: Need some way to apply starting gear to an entity coz holy fucking shit dude.
|
||||||
|
var loadoutGear = _prototypeManager.Index(loadoutProto.Equipment);
|
||||||
|
|
||||||
|
foreach (var slot in slots)
|
||||||
|
{
|
||||||
|
var itemType = loadoutGear.GetGear(slot.Name);
|
||||||
|
|
||||||
|
if (_inventory.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
|
||||||
|
{
|
||||||
|
EntityManager.DeleteEntity(unequippedItem.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemType != string.Empty)
|
||||||
|
{
|
||||||
|
var item = EntityManager.SpawnEntity(itemType, MapCoordinates.Nullspace);
|
||||||
|
_inventory.TryEquip(dummy, item, slot.Name, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (job.StartingGear == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var gear = _prototypeManager.Index<StartingGearPrototype>(job.StartingGear);
|
||||||
|
|
||||||
|
foreach (var slot in slots)
|
||||||
|
{
|
||||||
|
var itemType = gear.GetGear(slot.Name);
|
||||||
|
|
||||||
|
if (_inventory.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
|
||||||
|
{
|
||||||
|
EntityManager.DeleteEntity(unequippedItem.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemType != string.Empty)
|
||||||
|
{
|
||||||
|
var item = EntityManager.SpawnEntity(itemType, MapCoordinates.Nullspace);
|
||||||
|
_inventory.TryEquip(dummy, item, slot.Name, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityUid? GetPreviewDummy()
|
||||||
|
{
|
||||||
|
return _previewDummy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
using Content.Client.Alerts;
|
|
||||||
using Content.Client.Humanoid;
|
|
||||||
using Content.Client.Inventory;
|
|
||||||
using Content.Client.Preferences;
|
|
||||||
using Content.Client.UserInterface.Controls;
|
|
||||||
using Content.Shared.GameTicking;
|
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Content.Shared.Roles;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
|
||||||
|
|
||||||
namespace Content.Client.Lobby.UI
|
|
||||||
{
|
|
||||||
public sealed class LobbyCharacterPreviewPanel : Control
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
|
|
||||||
private EntityUid? _previewDummy;
|
|
||||||
private readonly Label _summaryLabel;
|
|
||||||
private readonly BoxContainer _loaded;
|
|
||||||
private readonly BoxContainer _viewBox;
|
|
||||||
private readonly Label _unloaded;
|
|
||||||
|
|
||||||
public LobbyCharacterPreviewPanel()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
var header = new NanoHeading
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("lobby-character-preview-panel-header")
|
|
||||||
};
|
|
||||||
|
|
||||||
CharacterSetupButton = new Button
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("lobby-character-preview-panel-character-setup-button"),
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
Margin = new Thickness(0, 5, 0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
_summaryLabel = new Label
|
|
||||||
{
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
Margin = new Thickness(3, 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
var vBox = new BoxContainer
|
|
||||||
{
|
|
||||||
Orientation = LayoutOrientation.Vertical
|
|
||||||
};
|
|
||||||
_unloaded = new Label { Text = Loc.GetString("lobby-character-preview-panel-unloaded-preferences-label") };
|
|
||||||
|
|
||||||
_loaded = new BoxContainer
|
|
||||||
{
|
|
||||||
Orientation = LayoutOrientation.Vertical,
|
|
||||||
Visible = false
|
|
||||||
};
|
|
||||||
_viewBox = new BoxContainer
|
|
||||||
{
|
|
||||||
Orientation = LayoutOrientation.Horizontal,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
};
|
|
||||||
var _vSpacer = new VSpacer();
|
|
||||||
|
|
||||||
_loaded.AddChild(_summaryLabel);
|
|
||||||
_loaded.AddChild(_viewBox);
|
|
||||||
_loaded.AddChild(_vSpacer);
|
|
||||||
_loaded.AddChild(CharacterSetupButton);
|
|
||||||
|
|
||||||
vBox.AddChild(header);
|
|
||||||
vBox.AddChild(_loaded);
|
|
||||||
vBox.AddChild(_unloaded);
|
|
||||||
AddChild(vBox);
|
|
||||||
|
|
||||||
UpdateUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Button CharacterSetupButton { get; }
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
|
|
||||||
if (!disposing) return;
|
|
||||||
if (_previewDummy != null) _entityManager.DeleteEntity(_previewDummy.Value);
|
|
||||||
_previewDummy = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateUI()
|
|
||||||
{
|
|
||||||
if (!_preferencesManager.ServerDataLoaded)
|
|
||||||
{
|
|
||||||
_loaded.Visible = false;
|
|
||||||
_unloaded.Visible = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_loaded.Visible = true;
|
|
||||||
_unloaded.Visible = false;
|
|
||||||
if (_preferencesManager.Preferences?.SelectedCharacter is not HumanoidCharacterProfile selectedCharacter)
|
|
||||||
{
|
|
||||||
_summaryLabel.Text = string.Empty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_previewDummy = _entityManager.SpawnEntity(_prototypeManager.Index<SpeciesPrototype>(selectedCharacter.Species).DollPrototype, MapCoordinates.Nullspace);
|
|
||||||
_viewBox.DisposeAllChildren();
|
|
||||||
var spriteView = new SpriteView
|
|
||||||
{
|
|
||||||
OverrideDirection = Direction.South,
|
|
||||||
Scale = new Vector2(4f, 4f),
|
|
||||||
MaxSize = new Vector2(112, 112),
|
|
||||||
Stretch = SpriteView.StretchMode.Fill,
|
|
||||||
};
|
|
||||||
spriteView.SetEntity(_previewDummy.Value);
|
|
||||||
_viewBox.AddChild(spriteView);
|
|
||||||
_summaryLabel.Text = selectedCharacter.Summary;
|
|
||||||
_entityManager.System<HumanoidAppearanceSystem>().LoadProfile(_previewDummy.Value, selectedCharacter);
|
|
||||||
GiveDummyJobClothes(_previewDummy.Value, selectedCharacter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void GiveDummyJobClothes(EntityUid dummy, HumanoidCharacterProfile profile)
|
|
||||||
{
|
|
||||||
var protoMan = IoCManager.Resolve<IPrototypeManager>();
|
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
|
||||||
var invSystem = EntitySystem.Get<ClientInventorySystem>();
|
|
||||||
|
|
||||||
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
|
|
||||||
|
|
||||||
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract (what is resharper smoking?)
|
|
||||||
var job = protoMan.Index<JobPrototype>(highPriorityJob ?? SharedGameTicker.FallbackOverflowJob);
|
|
||||||
|
|
||||||
if (job.StartingGear != null && invSystem.TryGetSlots(dummy, out var slots))
|
|
||||||
{
|
|
||||||
var gear = protoMan.Index<StartingGearPrototype>(job.StartingGear);
|
|
||||||
|
|
||||||
foreach (var slot in slots)
|
|
||||||
{
|
|
||||||
var itemType = gear.GetGear(slot.Name, profile);
|
|
||||||
|
|
||||||
if (invSystem.TryUnequip(dummy, slot.Name, out var unequippedItem, silent: true, force: true, reparent: false))
|
|
||||||
{
|
|
||||||
entMan.DeleteEntity(unequippedItem.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemType != string.Empty)
|
|
||||||
{
|
|
||||||
var item = entMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
|
|
||||||
invSystem.TryEquip(dummy, item, slot.Name, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
22
Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.xaml
Normal file
22
Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.xaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<Control
|
||||||
|
xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||||
|
<BoxContainer Name="VBox" Orientation="Vertical">
|
||||||
|
<controls:NanoHeading Name="Header" Text="{Loc 'lobby-character-preview-panel-header'}">
|
||||||
|
|
||||||
|
</controls:NanoHeading>
|
||||||
|
<BoxContainer Name="Loaded" Orientation="Vertical"
|
||||||
|
Visible="False">
|
||||||
|
<Label Name="Summary" HorizontalAlignment="Center" Margin="3 3"/>
|
||||||
|
<BoxContainer Name="ViewBox" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
|
||||||
|
</BoxContainer>
|
||||||
|
<controls:VSpacer/>
|
||||||
|
<Button Name="CharacterSetup" Text="{Loc 'lobby-character-preview-panel-character-setup-button'}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Margin="0 5 0 0"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<Label Name="Unloaded" Text="{Loc 'lobby-character-preview-panel-unloaded-preferences-label'}"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</Control>
|
||||||
45
Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.xaml.cs
Normal file
45
Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.xaml.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.Lobby.UI;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class LobbyCharacterPreviewPanel : Control
|
||||||
|
{
|
||||||
|
public Button CharacterSetupButton => CharacterSetup;
|
||||||
|
|
||||||
|
public LobbyCharacterPreviewPanel()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
UserInterfaceManager.GetUIController<LobbyUIController>().SetPreviewPanel(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLoaded(bool value)
|
||||||
|
{
|
||||||
|
Loaded.Visible = value;
|
||||||
|
Unloaded.Visible = !value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSummaryText(string value)
|
||||||
|
{
|
||||||
|
Summary.Text = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSprite(EntityUid uid)
|
||||||
|
{
|
||||||
|
ViewBox.DisposeAllChildren();
|
||||||
|
var spriteView = new SpriteView
|
||||||
|
{
|
||||||
|
OverrideDirection = Direction.South,
|
||||||
|
Scale = new Vector2(4f, 4f),
|
||||||
|
MaxSize = new Vector2(112, 112),
|
||||||
|
Stretch = SpriteView.StretchMode.Fill,
|
||||||
|
};
|
||||||
|
spriteView.SetEntity(uid);
|
||||||
|
ViewBox.AddChild(spriteView);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,9 @@
|
|||||||
using Content.Client.Chat.UI;
|
|
||||||
using Content.Client.Info;
|
|
||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
using Content.Client.Preferences;
|
|
||||||
using Content.Client.Preferences.UI;
|
|
||||||
using Content.Client.UserInterface.Screens;
|
|
||||||
using Content.Client.UserInterface.Systems.Chat.Widgets;
|
|
||||||
using Content.Client.UserInterface.Systems.EscapeMenu;
|
using Content.Client.UserInterface.Systems.EscapeMenu;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.State;
|
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
|
||||||
|
|
||||||
namespace Content.Client.Lobby.UI
|
namespace Content.Client.Lobby.UI
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ using Robust.Client;
|
|||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Players.PlayTimeTracking;
|
namespace Content.Client.Players.PlayTimeTracking;
|
||||||
|
|
||||||
public sealed class JobRequirementsManager
|
public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IBaseClient _client = default!;
|
[Dependency] private readonly IBaseClient _client = default!;
|
||||||
[Dependency] private readonly IClientNetManager _net = default!;
|
[Dependency] private readonly IClientNetManager _net = default!;
|
||||||
@@ -133,5 +134,13 @@ public sealed class JobRequirementsManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, TimeSpan> GetPlayTimes(ICommonSession session)
|
||||||
|
{
|
||||||
|
if (session != _playerManager.LocalSession)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, TimeSpan>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _roles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Client;
|
using Robust.Client;
|
||||||
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
@@ -20,8 +18,7 @@ namespace Content.Client.Preferences
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IBaseClient _baseClient = default!;
|
[Dependency] private readonly IBaseClient _baseClient = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
|
||||||
|
|
||||||
public event Action? OnServerDataLoaded;
|
public event Action? OnServerDataLoaded;
|
||||||
|
|
||||||
@@ -64,7 +61,8 @@ namespace Content.Client.Preferences
|
|||||||
|
|
||||||
public void UpdateCharacter(ICharacterProfile profile, int slot)
|
public void UpdateCharacter(ICharacterProfile profile, int slot)
|
||||||
{
|
{
|
||||||
profile.EnsureValid(_cfg, _prototypes);
|
var collection = IoCManager.Instance!;
|
||||||
|
profile.EnsureValid(_playerManager.LocalSession!, collection);
|
||||||
var characters = new Dictionary<int, ICharacterProfile>(Preferences.Characters) {[slot] = profile};
|
var characters = new Dictionary<int, ICharacterProfile>(Preferences.Characters) {[slot] = profile};
|
||||||
Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor);
|
Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor);
|
||||||
var msg = new MsgUpdateCharacter
|
var msg = new MsgUpdateCharacter
|
||||||
|
|||||||
41
Content.Client/Preferences/UI/AntagPreferenceSelector.cs
Normal file
41
Content.Client/Preferences/UI/AntagPreferenceSelector.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using Content.Client.Players.PlayTimeTracking;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
public sealed class AntagPreferenceSelector : RequirementsSelector<AntagPrototype>
|
||||||
|
{
|
||||||
|
// 0 is yes and 1 is no
|
||||||
|
public bool Preference
|
||||||
|
{
|
||||||
|
get => Options.SelectedValue == 0;
|
||||||
|
set => Options.Select((value && !Disabled) ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<bool>? PreferenceChanged;
|
||||||
|
|
||||||
|
public AntagPreferenceSelector(AntagPrototype proto, ButtonGroup btnGroup)
|
||||||
|
: base(proto, btnGroup)
|
||||||
|
{
|
||||||
|
Options.OnItemSelected += args => PreferenceChanged?.Invoke(Preference);
|
||||||
|
|
||||||
|
var items = new[]
|
||||||
|
{
|
||||||
|
("humanoid-profile-editor-antag-preference-yes-button", 0),
|
||||||
|
("humanoid-profile-editor-antag-preference-no-button", 1)
|
||||||
|
};
|
||||||
|
var title = Loc.GetString(proto.Name);
|
||||||
|
var description = Loc.GetString(proto.Objective);
|
||||||
|
// Not supported yet get fucked.
|
||||||
|
Setup(null, items, title, 250, description);
|
||||||
|
|
||||||
|
// immediately lock requirements if they arent met.
|
||||||
|
// another function checks Disabled after creating the selector so this has to be done now
|
||||||
|
var requirements = IoCManager.Resolve<JobRequirementsManager>();
|
||||||
|
if (proto.Requirements != null && !requirements.CheckRoleTime(proto.Requirements, out var reason))
|
||||||
|
{
|
||||||
|
LockRequirements(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.NanoGold}" ContentMarginTopOverride="2" />
|
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.NanoGold}" ContentMarginTopOverride="2" />
|
||||||
</PanelContainer.PanelOverride>
|
</PanelContainer.PanelOverride>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
<BoxContainer Name="CharEditor" />
|
<BoxContainer Name="CharEditor" HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</Control>
|
</Control>
|
||||||
|
|||||||
@@ -3,27 +3,23 @@ using System.Numerics;
|
|||||||
using Content.Client.Humanoid;
|
using Content.Client.Humanoid;
|
||||||
using Content.Client.Info;
|
using Content.Client.Info;
|
||||||
using Content.Client.Info.PlaytimeStats;
|
using Content.Client.Info.PlaytimeStats;
|
||||||
using Content.Client.Lobby.UI;
|
using Content.Client.Lobby;
|
||||||
using Content.Client.Resources;
|
using Content.Client.Resources;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.ResourceManagement;
|
using Robust.Client.ResourceManagement;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||||
using Direction = Robust.Shared.Maths.Direction;
|
using Direction = Robust.Shared.Maths.Direction;
|
||||||
@@ -36,7 +32,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
private readonly IClientPreferencesManager _preferencesManager;
|
private readonly IClientPreferencesManager _preferencesManager;
|
||||||
private readonly IEntityManager _entityManager;
|
private readonly IEntityManager _entityManager;
|
||||||
private readonly IPrototypeManager _prototypeManager;
|
private readonly IPrototypeManager _prototypeManager;
|
||||||
private readonly IConfigurationManager _configurationManager;
|
|
||||||
private readonly Button _createNewCharacterButton;
|
private readonly Button _createNewCharacterButton;
|
||||||
private readonly HumanoidProfileEditor _humanoidProfileEditor;
|
private readonly HumanoidProfileEditor _humanoidProfileEditor;
|
||||||
|
|
||||||
@@ -51,7 +46,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
_entityManager = entityManager;
|
_entityManager = entityManager;
|
||||||
_prototypeManager = prototypeManager;
|
_prototypeManager = prototypeManager;
|
||||||
_preferencesManager = preferencesManager;
|
_preferencesManager = preferencesManager;
|
||||||
_configurationManager = configurationManager;
|
|
||||||
|
|
||||||
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
||||||
var back = new StyleBoxTexture
|
var back = new StyleBoxTexture
|
||||||
@@ -74,7 +68,7 @@ namespace Content.Client.Preferences.UI
|
|||||||
args.Event.Handle();
|
args.Event.Handle();
|
||||||
};
|
};
|
||||||
|
|
||||||
_humanoidProfileEditor = new HumanoidProfileEditor(preferencesManager, prototypeManager, entityManager, configurationManager);
|
_humanoidProfileEditor = new HumanoidProfileEditor(preferencesManager, prototypeManager, configurationManager);
|
||||||
_humanoidProfileEditor.OnProfileChanged += ProfileChanged;
|
_humanoidProfileEditor.OnProfileChanged += ProfileChanged;
|
||||||
CharEditor.AddChild(_humanoidProfileEditor);
|
CharEditor.AddChild(_humanoidProfileEditor);
|
||||||
|
|
||||||
@@ -105,6 +99,7 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
private void UpdateUI()
|
private void UpdateUI()
|
||||||
{
|
{
|
||||||
|
UserInterfaceManager.GetUIController<LobbyUIController>().UpdateCharacterUI();
|
||||||
var numberOfFullSlots = 0;
|
var numberOfFullSlots = 0;
|
||||||
var characterButtonsGroup = new ButtonGroup();
|
var characterButtonsGroup = new ButtonGroup();
|
||||||
Characters.RemoveAllChildren();
|
Characters.RemoveAllChildren();
|
||||||
@@ -120,11 +115,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
foreach (var (slot, character) in _preferencesManager.Preferences!.Characters)
|
foreach (var (slot, character) in _preferencesManager.Preferences!.Characters)
|
||||||
{
|
{
|
||||||
if (character is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
numberOfFullSlots++;
|
numberOfFullSlots++;
|
||||||
var characterPickerButton = new CharacterPickerButton(_entityManager,
|
var characterPickerButton = new CharacterPickerButton(_entityManager,
|
||||||
_preferencesManager,
|
_preferencesManager,
|
||||||
@@ -148,8 +138,12 @@ namespace Content.Client.Preferences.UI
|
|||||||
_createNewCharacterButton.Disabled =
|
_createNewCharacterButton.Disabled =
|
||||||
numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots;
|
numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots;
|
||||||
Characters.AddChild(_createNewCharacterButton);
|
Characters.AddChild(_createNewCharacterButton);
|
||||||
|
// TODO: Move this shit to the Lobby UI controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows individual characters on the side of the character GUI.
|
||||||
|
/// </summary>
|
||||||
private sealed class CharacterPickerButton : ContainerButton
|
private sealed class CharacterPickerButton : ContainerButton
|
||||||
{
|
{
|
||||||
private EntityUid _previewDummy;
|
private EntityUid _previewDummy;
|
||||||
@@ -180,7 +174,15 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
if (humanoid != null)
|
if (humanoid != null)
|
||||||
{
|
{
|
||||||
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, humanoid);
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
var job = controller.GetPreferredJob(humanoid);
|
||||||
|
controller.GiveDummyJobClothes(_previewDummy, humanoid, job);
|
||||||
|
|
||||||
|
if (prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
|
||||||
|
{
|
||||||
|
var loadout = humanoid.GetLoadoutOrDefault(LoadoutSystem.GetJobPrototype(job.ID), entityManager, prototypeManager);
|
||||||
|
controller.GiveDummyLoadout(_previewDummy, loadout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSelectedCharacter = profile == preferencesManager.Preferences?.SelectedCharacter;
|
var isSelectedCharacter = profile == preferencesManager.Preferences?.SelectedCharacter;
|
||||||
|
|||||||
11
Content.Client/Preferences/UI/HighlightedContainer.xaml
Normal file
11
Content.Client/Preferences/UI/HighlightedContainer.xaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<PanelContainer
|
||||||
|
xmlns="https://spacestation14.io"
|
||||||
|
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
|
||||||
|
<PanelContainer.PanelOverride>
|
||||||
|
<graphics:StyleBoxFlat BackgroundColor="#2F2F35"
|
||||||
|
ContentMarginTopOverride="10"
|
||||||
|
ContentMarginBottomOverride="10"
|
||||||
|
ContentMarginLeftOverride="10"
|
||||||
|
ContentMarginRightOverride="10"/>
|
||||||
|
</PanelContainer.PanelOverride>
|
||||||
|
</PanelContainer>
|
||||||
14
Content.Client/Preferences/UI/HighlightedContainer.xaml.cs
Normal file
14
Content.Client/Preferences/UI/HighlightedContainer.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class HighlightedContainer : PanelContainer
|
||||||
|
{
|
||||||
|
public HighlightedContainer()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
{
|
{
|
||||||
public sealed partial class HumanoidProfileEditor
|
public sealed partial class HumanoidProfileEditor
|
||||||
{
|
{
|
||||||
private readonly IPrototypeManager _prototypeManager;
|
|
||||||
|
|
||||||
private void RandomizeEverything()
|
private void RandomizeEverything()
|
||||||
{
|
{
|
||||||
Profile = HumanoidCharacterProfile.Random();
|
Profile = HumanoidCharacterProfile.Random();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<Control xmlns="https://spacestation14.io"
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:prefUi="clr-namespace:Content.Client.Preferences.UI"
|
xmlns:prefUi="clr-namespace:Content.Client.Preferences.UI"
|
||||||
xmlns:humanoid="clr-namespace:Content.Client.Humanoid"
|
xmlns:humanoid="clr-namespace:Content.Client.Humanoid"
|
||||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls">
|
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||||
<BoxContainer Orientation="Horizontal">
|
HorizontalExpand="True">
|
||||||
<!-- Left side -->
|
<!-- Left side -->
|
||||||
<BoxContainer Orientation="Vertical" Margin="10 10 10 10">
|
<BoxContainer Orientation="Vertical" Margin="10 10 10 10" HorizontalExpand="True">
|
||||||
<!-- Middle container -->
|
<!-- Middle container -->
|
||||||
<BoxContainer Orientation="Horizontal" SeparationOverride="10">
|
<BoxContainer Orientation="Horizontal" SeparationOverride="10">
|
||||||
<!-- Name box-->
|
<!-- Name box-->
|
||||||
@@ -58,7 +58,9 @@
|
|||||||
<BoxContainer HorizontalExpand="True">
|
<BoxContainer HorizontalExpand="True">
|
||||||
<Label Text="{Loc 'humanoid-profile-editor-species-label'}" />
|
<Label Text="{Loc 'humanoid-profile-editor-species-label'}" />
|
||||||
<Control HorizontalExpand="True"/>
|
<Control HorizontalExpand="True"/>
|
||||||
<TextureButton Name="SpeciesInfoButton" Scale="0.3 0.3" VerticalAlignment="Center"></TextureButton>
|
<TextureButton Name="SpeciesInfoButton" Scale="0.3 0.3"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
ToolTip="{Loc 'humanoid-profile-editor-guidebook-button-tooltip'}"/>
|
||||||
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
|
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Age -->
|
<!-- Age -->
|
||||||
@@ -85,18 +87,6 @@
|
|||||||
<Control HorizontalExpand="True"/>
|
<Control HorizontalExpand="True"/>
|
||||||
<Button Name="ShowClothes" Pressed="True" ToggleMode="True" Text="{Loc 'humanoid-profile-editor-clothing-show'}" HorizontalAlignment="Right" />
|
<Button Name="ShowClothes" Pressed="True" ToggleMode="True" Text="{Loc 'humanoid-profile-editor-clothing-show'}" HorizontalAlignment="Right" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Clothing -->
|
|
||||||
<BoxContainer HorizontalExpand="True">
|
|
||||||
<Label Text="{Loc 'humanoid-profile-editor-clothing-label'}" />
|
|
||||||
<Control HorizontalExpand="True"/>
|
|
||||||
<OptionButton Name="CClothingButton" HorizontalAlignment="Right" />
|
|
||||||
</BoxContainer>
|
|
||||||
<!-- Backpack -->
|
|
||||||
<BoxContainer HorizontalExpand="True">
|
|
||||||
<Label Text="{Loc 'humanoid-profile-editor-backpack-label'}" />
|
|
||||||
<Control HorizontalExpand="True"/>
|
|
||||||
<OptionButton Name="CBackpackButton" HorizontalAlignment="Right" />
|
|
||||||
</BoxContainer>
|
|
||||||
<!-- Spawn Priority -->
|
<!-- Spawn Priority -->
|
||||||
<BoxContainer HorizontalExpand="True">
|
<BoxContainer HorizontalExpand="True">
|
||||||
<Label Text="{Loc 'humanoid-profile-editor-spawn-priority-label'}" />
|
<Label Text="{Loc 'humanoid-profile-editor-spawn-priority-label'}" />
|
||||||
@@ -151,7 +141,7 @@
|
|||||||
</TabContainer>
|
</TabContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Right side -->
|
<!-- Right side -->
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" VerticalAlignment="Center">
|
<BoxContainer Orientation="Vertical" VerticalExpand="True" VerticalAlignment="Center">
|
||||||
<SpriteView Name="CSpriteView" Scale="8 8" SizeFlagsStretchRatio="1" />
|
<SpriteView Name="CSpriteView" Scale="8 8" SizeFlagsStretchRatio="1" />
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 5">
|
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 5">
|
||||||
<Button Name="CSpriteRotateLeft" Text="◀" StyleClasses="OpenRight" />
|
<Button Name="CSpriteRotateLeft" Text="◀" StyleClasses="OpenRight" />
|
||||||
@@ -159,5 +149,4 @@
|
|||||||
<Button Name="CSpriteRotateRight" Text="▶" StyleClasses="OpenLeft" />
|
<Button Name="CSpriteRotateRight" Text="▶" StyleClasses="OpenLeft" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</Control>
|
|
||||||
|
|||||||
@@ -2,69 +2,48 @@ using System.Linq;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.Guidebook;
|
using Content.Client.Guidebook;
|
||||||
using Content.Client.Humanoid;
|
using Content.Client.Humanoid;
|
||||||
using Content.Client.Lobby.UI;
|
using Content.Client.Lobby;
|
||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
using Content.Client.Players.PlayTimeTracking;
|
using Content.Client.Players.PlayTimeTracking;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Client.UserInterface.Controls;
|
using Content.Client.UserInterface.Controls;
|
||||||
using Content.Client.UserInterface.Systems.Guidebook;
|
using Content.Client.UserInterface.Systems.Guidebook;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Humanoid.Markings;
|
using Content.Shared.Humanoid.Markings;
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.StatusIcon;
|
|
||||||
using Content.Shared.Traits;
|
using Content.Shared.Traits;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Client.Utility;
|
using Robust.Client.Utility;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
|
||||||
using Direction = Robust.Shared.Maths.Direction;
|
using Direction = Robust.Shared.Maths.Direction;
|
||||||
|
|
||||||
namespace Content.Client.Preferences.UI
|
namespace Content.Client.Preferences.UI
|
||||||
{
|
{
|
||||||
public sealed class HighlightedContainer : PanelContainer
|
|
||||||
{
|
|
||||||
public HighlightedContainer()
|
|
||||||
{
|
|
||||||
PanelOverride = new StyleBoxFlat()
|
|
||||||
{
|
|
||||||
BackgroundColor = new Color(47, 47, 53),
|
|
||||||
ContentMarginTopOverride = 10,
|
|
||||||
ContentMarginBottomOverride = 10,
|
|
||||||
ContentMarginLeftOverride = 10,
|
|
||||||
ContentMarginRightOverride = 10
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class HumanoidProfileEditor : Control
|
public sealed partial class HumanoidProfileEditor : BoxContainer
|
||||||
{
|
{
|
||||||
private readonly IClientPreferencesManager _preferencesManager;
|
private readonly IClientPreferencesManager _preferencesManager;
|
||||||
private readonly IEntityManager _entMan;
|
private readonly IPrototypeManager _prototypeManager;
|
||||||
private readonly IConfigurationManager _configurationManager;
|
|
||||||
private readonly MarkingManager _markingManager;
|
private readonly MarkingManager _markingManager;
|
||||||
private readonly JobRequirementsManager _requirements;
|
private readonly JobRequirementsManager _requirements;
|
||||||
|
|
||||||
private LineEdit _ageEdit => CAgeEdit;
|
private LineEdit _ageEdit => CAgeEdit;
|
||||||
private LineEdit _nameEdit => CNameEdit;
|
private LineEdit _nameEdit => CNameEdit;
|
||||||
private TextEdit _flavorTextEdit = null!;
|
private TextEdit? _flavorTextEdit;
|
||||||
private Button _nameRandomButton => CNameRandomize;
|
private Button _nameRandomButton => CNameRandomize;
|
||||||
private Button _randomizeEverythingButton => CRandomizeEverything;
|
private Button _randomizeEverythingButton => CRandomizeEverything;
|
||||||
private RichTextLabel _warningLabel => CWarningLabel;
|
private RichTextLabel _warningLabel => CWarningLabel;
|
||||||
@@ -72,8 +51,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
private OptionButton _sexButton => CSexButton;
|
private OptionButton _sexButton => CSexButton;
|
||||||
private OptionButton _genderButton => CPronounsButton;
|
private OptionButton _genderButton => CPronounsButton;
|
||||||
private Slider _skinColor => CSkin;
|
private Slider _skinColor => CSkin;
|
||||||
private OptionButton _clothingButton => CClothingButton;
|
|
||||||
private OptionButton _backpackButton => CBackpackButton;
|
|
||||||
private OptionButton _spawnPriorityButton => CSpawnPriorityButton;
|
private OptionButton _spawnPriorityButton => CSpawnPriorityButton;
|
||||||
private SingleMarkingPicker _hairPicker => CHairStylePicker;
|
private SingleMarkingPicker _hairPicker => CHairStylePicker;
|
||||||
private SingleMarkingPicker _facialHairPicker => CFacialHairPicker;
|
private SingleMarkingPicker _facialHairPicker => CFacialHairPicker;
|
||||||
@@ -88,44 +65,39 @@ namespace Content.Client.Preferences.UI
|
|||||||
private readonly Dictionary<string, BoxContainer> _jobCategories;
|
private readonly Dictionary<string, BoxContainer> _jobCategories;
|
||||||
// Mildly hacky, as I don't trust prototype order to stay consistent and don't want the UI to break should a new one get added mid-edit. --moony
|
// Mildly hacky, as I don't trust prototype order to stay consistent and don't want the UI to break should a new one get added mid-edit. --moony
|
||||||
private readonly List<SpeciesPrototype> _speciesList;
|
private readonly List<SpeciesPrototype> _speciesList;
|
||||||
private readonly List<AntagPreferenceSelector> _antagPreferences;
|
private readonly List<AntagPreferenceSelector> _antagPreferences = new();
|
||||||
private readonly List<TraitPreferenceSelector> _traitPreferences;
|
private readonly List<TraitPreferenceSelector> _traitPreferences;
|
||||||
|
|
||||||
private SpriteView _previewSpriteView => CSpriteView;
|
private SpriteView _previewSpriteView => CSpriteView;
|
||||||
private Button _previewRotateLeftButton => CSpriteRotateLeft;
|
private Button _previewRotateLeftButton => CSpriteRotateLeft;
|
||||||
private Button _previewRotateRightButton => CSpriteRotateRight;
|
private Button _previewRotateRightButton => CSpriteRotateRight;
|
||||||
private Direction _previewRotation = Direction.North;
|
private Direction _previewRotation = Direction.North;
|
||||||
private EntityUid? _previewDummy;
|
|
||||||
|
|
||||||
private BoxContainer _rgbSkinColorContainer => CRgbSkinColorContainer;
|
private BoxContainer _rgbSkinColorContainer => CRgbSkinColorContainer;
|
||||||
private ColorSelectorSliders _rgbSkinColorSelector;
|
private ColorSelectorSliders _rgbSkinColorSelector;
|
||||||
|
|
||||||
private bool _isDirty;
|
private bool _isDirty;
|
||||||
private bool _needUpdatePreview;
|
|
||||||
public int CharacterSlot;
|
public int CharacterSlot;
|
||||||
public HumanoidCharacterProfile? Profile;
|
public HumanoidCharacterProfile? Profile;
|
||||||
private MarkingSet _markingSet = new(); // storing this here feels iffy but a few things need it this high up
|
|
||||||
|
|
||||||
public event Action<HumanoidCharacterProfile, int>? OnProfileChanged;
|
public event Action<HumanoidCharacterProfile, int>? OnProfileChanged;
|
||||||
|
|
||||||
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager,
|
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||||
IEntityManager entityManager, IConfigurationManager configurationManager)
|
private const string DefaultSpeciesGuidebook = "Species";
|
||||||
|
|
||||||
|
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager, IConfigurationManager configurationManager)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_prototypeManager = prototypeManager;
|
_prototypeManager = prototypeManager;
|
||||||
_entMan = entityManager;
|
|
||||||
_preferencesManager = preferencesManager;
|
_preferencesManager = preferencesManager;
|
||||||
_configurationManager = configurationManager;
|
|
||||||
_markingManager = IoCManager.Resolve<MarkingManager>();
|
_markingManager = IoCManager.Resolve<MarkingManager>();
|
||||||
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
controller.PreviewDummyUpdated += OnDummyUpdate;
|
||||||
|
|
||||||
SpeciesInfoButton.ToolTip = Loc.GetString("humanoid-profile-editor-guidebook-button-tooltip");
|
_previewSpriteView.SetEntity(controller.GetPreviewDummy());
|
||||||
|
|
||||||
#region Left
|
#region Left
|
||||||
|
|
||||||
#region Randomize
|
|
||||||
|
|
||||||
#endregion Randomize
|
|
||||||
|
|
||||||
#region Name
|
#region Name
|
||||||
|
|
||||||
_nameEdit.OnTextChanged += args => { SetName(args.Text); };
|
_nameEdit.OnTextChanged += args => { SetName(args.Text); };
|
||||||
@@ -139,8 +111,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
_tabContainer.SetTabTitle(0, Loc.GetString("humanoid-profile-editor-appearance-tab"));
|
_tabContainer.SetTabTitle(0, Loc.GetString("humanoid-profile-editor-appearance-tab"));
|
||||||
|
|
||||||
ShowClothes.OnPressed += ToggleClothes;
|
|
||||||
|
|
||||||
#region Sex
|
#region Sex
|
||||||
|
|
||||||
_sexButton.OnItemSelected += args =>
|
_sexButton.OnItemSelected += args =>
|
||||||
@@ -318,33 +288,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
#endregion Hair
|
#endregion Hair
|
||||||
|
|
||||||
#region Clothing
|
|
||||||
|
|
||||||
_clothingButton.AddItem(Loc.GetString("humanoid-profile-editor-preference-jumpsuit"), (int) ClothingPreference.Jumpsuit);
|
|
||||||
_clothingButton.AddItem(Loc.GetString("humanoid-profile-editor-preference-jumpskirt"), (int) ClothingPreference.Jumpskirt);
|
|
||||||
|
|
||||||
_clothingButton.OnItemSelected += args =>
|
|
||||||
{
|
|
||||||
_clothingButton.SelectId(args.Id);
|
|
||||||
SetClothing((ClothingPreference) args.Id);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endregion Clothing
|
|
||||||
|
|
||||||
#region Backpack
|
|
||||||
|
|
||||||
_backpackButton.AddItem(Loc.GetString("humanoid-profile-editor-preference-backpack"), (int) BackpackPreference.Backpack);
|
|
||||||
_backpackButton.AddItem(Loc.GetString("humanoid-profile-editor-preference-satchel"), (int) BackpackPreference.Satchel);
|
|
||||||
_backpackButton.AddItem(Loc.GetString("humanoid-profile-editor-preference-duffelbag"), (int) BackpackPreference.Duffelbag);
|
|
||||||
|
|
||||||
_backpackButton.OnItemSelected += args =>
|
|
||||||
{
|
|
||||||
_backpackButton.SelectId(args.Id);
|
|
||||||
SetBackpack((BackpackPreference) args.Id);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endregion Backpack
|
|
||||||
|
|
||||||
#region SpawnPriority
|
#region SpawnPriority
|
||||||
|
|
||||||
foreach (var value in Enum.GetValues<SpawnPriorityPreference>())
|
foreach (var value in Enum.GetValues<SpawnPriorityPreference>())
|
||||||
@@ -399,40 +342,16 @@ namespace Content.Client.Preferences.UI
|
|||||||
_jobPriorities = new List<JobPrioritySelector>();
|
_jobPriorities = new List<JobPrioritySelector>();
|
||||||
_jobCategories = new Dictionary<string, BoxContainer>();
|
_jobCategories = new Dictionary<string, BoxContainer>();
|
||||||
_requirements = IoCManager.Resolve<JobRequirementsManager>();
|
_requirements = IoCManager.Resolve<JobRequirementsManager>();
|
||||||
|
// TODO: Move this to the LobbyUIController instead of being spaghetti everywhere.
|
||||||
|
_requirements.Updated += UpdateAntagRequirements;
|
||||||
_requirements.Updated += UpdateRoleRequirements;
|
_requirements.Updated += UpdateRoleRequirements;
|
||||||
|
UpdateAntagRequirements();
|
||||||
UpdateRoleRequirements();
|
UpdateRoleRequirements();
|
||||||
|
|
||||||
#endregion Jobs
|
#endregion Jobs
|
||||||
|
|
||||||
#region Antags
|
|
||||||
|
|
||||||
_tabContainer.SetTabTitle(2, Loc.GetString("humanoid-profile-editor-antags-tab"));
|
_tabContainer.SetTabTitle(2, Loc.GetString("humanoid-profile-editor-antags-tab"));
|
||||||
|
|
||||||
_antagPreferences = new List<AntagPreferenceSelector>();
|
|
||||||
|
|
||||||
foreach (var antag in prototypeManager.EnumeratePrototypes<AntagPrototype>().OrderBy(a => Loc.GetString(a.Name)))
|
|
||||||
{
|
|
||||||
if (!antag.SetPreference)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var selector = new AntagPreferenceSelector(antag);
|
|
||||||
_antagList.AddChild(selector);
|
|
||||||
_antagPreferences.Add(selector);
|
|
||||||
if (selector.Disabled)
|
|
||||||
{
|
|
||||||
Profile = Profile?.WithAntagPreference(antag.ID, false);
|
|
||||||
IsDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
selector.PreferenceChanged += preference =>
|
|
||||||
{
|
|
||||||
Profile = Profile?.WithAntagPreference(antag.ID, preference);
|
|
||||||
IsDirty = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Antags
|
|
||||||
|
|
||||||
#region Traits
|
#region Traits
|
||||||
|
|
||||||
var traits = prototypeManager.EnumeratePrototypes<TraitPrototype>().OrderBy(t => Loc.GetString(t.Name)).ToList();
|
var traits = prototypeManager.EnumeratePrototypes<TraitPrototype>().OrderBy(t => Loc.GetString(t.Name)).ToList();
|
||||||
@@ -483,7 +402,7 @@ namespace Content.Client.Preferences.UI
|
|||||||
|
|
||||||
#region FlavorText
|
#region FlavorText
|
||||||
|
|
||||||
if (_configurationManager.GetCVar(CCVars.FlavorText))
|
if (configurationManager.GetCVar(CCVars.FlavorText))
|
||||||
{
|
{
|
||||||
var flavorText = new FlavorText.FlavorText();
|
var flavorText = new FlavorText.FlavorText();
|
||||||
_tabContainer.AddChild(flavorText);
|
_tabContainer.AddChild(flavorText);
|
||||||
@@ -500,22 +419,14 @@ namespace Content.Client.Preferences.UI
|
|||||||
_previewRotateLeftButton.OnPressed += _ =>
|
_previewRotateLeftButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
_previewRotation = _previewRotation.TurnCw();
|
_previewRotation = _previewRotation.TurnCw();
|
||||||
_needUpdatePreview = true;
|
SetPreviewRotation(_previewRotation);
|
||||||
};
|
};
|
||||||
_previewRotateRightButton.OnPressed += _ =>
|
_previewRotateRightButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
_previewRotation = _previewRotation.TurnCcw();
|
_previewRotation = _previewRotation.TurnCcw();
|
||||||
_needUpdatePreview = true;
|
SetPreviewRotation(_previewRotation);
|
||||||
};
|
};
|
||||||
|
|
||||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
|
||||||
var dollProto = _prototypeManager.Index<SpeciesPrototype>(species).DollPrototype;
|
|
||||||
|
|
||||||
if (_previewDummy != null)
|
|
||||||
_entMan.DeleteEntity(_previewDummy!.Value);
|
|
||||||
|
|
||||||
_previewDummy = _entMan.SpawnEntity(dollProto, MapCoordinates.Nullspace);
|
|
||||||
_previewSpriteView.SetEntity(_previewDummy);
|
|
||||||
#endregion Dummy
|
#endregion Dummy
|
||||||
|
|
||||||
#endregion Left
|
#endregion Left
|
||||||
@@ -538,22 +449,54 @@ namespace Content.Client.Preferences.UI
|
|||||||
{
|
{
|
||||||
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
|
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
|
||||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
||||||
var page = "Species";
|
var page = DefaultSpeciesGuidebook;
|
||||||
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
||||||
page = species;
|
page = species;
|
||||||
|
|
||||||
if (_prototypeManager.TryIndex<GuideEntryPrototype>("Species", out var guideRoot))
|
if (_prototypeManager.TryIndex<GuideEntryPrototype>(DefaultSpeciesGuidebook, out var guideRoot))
|
||||||
{
|
{
|
||||||
var dict = new Dictionary<string, GuideEntry>();
|
var dict = new Dictionary<string, GuideEntry>();
|
||||||
dict.Add("Species", guideRoot);
|
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
||||||
//TODO: Don't close the guidebook if its already open, just go to the correct page
|
//TODO: Don't close the guidebook if its already open, just go to the correct page
|
||||||
guidebookController.ToggleGuidebook(dict, includeChildren:true, selected: page);
|
guidebookController.ToggleGuidebook(dict, includeChildren:true, selected: page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleClothes(BaseButton.ButtonEventArgs obj)
|
private void OnDummyUpdate(EntityUid value)
|
||||||
{
|
{
|
||||||
RebuildSpriteView();
|
_previewSpriteView.SetEntity(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAntagRequirements()
|
||||||
|
{
|
||||||
|
_antagList.DisposeAllChildren();
|
||||||
|
_antagPreferences.Clear();
|
||||||
|
var btnGroup = new ButtonGroup();
|
||||||
|
|
||||||
|
foreach (var antag in _prototypeManager.EnumeratePrototypes<AntagPrototype>().OrderBy(a => Loc.GetString(a.Name)))
|
||||||
|
{
|
||||||
|
if (!antag.SetPreference)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var selector = new AntagPreferenceSelector(antag, btnGroup)
|
||||||
|
{
|
||||||
|
Margin = new Thickness(3f, 3f, 3f, 0f),
|
||||||
|
};
|
||||||
|
_antagList.AddChild(selector);
|
||||||
|
_antagPreferences.Add(selector);
|
||||||
|
if (selector.Disabled)
|
||||||
|
{
|
||||||
|
Profile = Profile?.WithAntagPreference(antag.ID, false);
|
||||||
|
IsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
selector.PreferenceChanged += preference =>
|
||||||
|
{
|
||||||
|
Profile = Profile?.WithAntagPreference(antag.ID, preference);
|
||||||
|
IsDirty = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateRoleRequirements()
|
private void UpdateRoleRequirements()
|
||||||
@@ -614,10 +557,16 @@ namespace Content.Client.Preferences.UI
|
|||||||
.Where(job => job.SetPreference)
|
.Where(job => job.SetPreference)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
Array.Sort(jobs, JobUIComparer.Instance);
|
Array.Sort(jobs, JobUIComparer.Instance);
|
||||||
|
var jobLoadoutGroup = new ButtonGroup();
|
||||||
|
|
||||||
foreach (var job in jobs)
|
foreach (var job in jobs)
|
||||||
{
|
{
|
||||||
var selector = new JobPrioritySelector(job, _prototypeManager);
|
RoleLoadout? loadout = null;
|
||||||
|
Profile?.Loadouts.TryGetValue(LoadoutSystem.GetJobPrototype(job.ID), out loadout);
|
||||||
|
var selector = new JobPrioritySelector(loadout, job, jobLoadoutGroup, _prototypeManager)
|
||||||
|
{
|
||||||
|
Margin = new Thickness(3f, 3f, 3f, 0f),
|
||||||
|
};
|
||||||
|
|
||||||
if (!_requirements.IsAllowed(job, out var reason))
|
if (!_requirements.IsAllowed(job, out var reason))
|
||||||
{
|
{
|
||||||
@@ -627,6 +576,13 @@ namespace Content.Client.Preferences.UI
|
|||||||
category.AddChild(selector);
|
category.AddChild(selector);
|
||||||
_jobPriorities.Add(selector);
|
_jobPriorities.Add(selector);
|
||||||
|
|
||||||
|
selector.LoadoutUpdated += args =>
|
||||||
|
{
|
||||||
|
Profile?.SetLoadout(args);
|
||||||
|
UserInterfaceManager.GetUIController<LobbyUIController>().UpdateCharacterUI();
|
||||||
|
IsDirty = true;
|
||||||
|
};
|
||||||
|
|
||||||
selector.PriorityChanged += priority =>
|
selector.PriorityChanged += priority =>
|
||||||
{
|
{
|
||||||
Profile = Profile?.WithJobPriority(job.ID, priority);
|
Profile = Profile?.WithJobPriority(job.ID, priority);
|
||||||
@@ -672,20 +628,10 @@ namespace Content.Client.Preferences.UI
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithMarkings(markings.GetForwardEnumerator().ToList()));
|
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithMarkings(markings.GetForwardEnumerator().ToList()));
|
||||||
_needUpdatePreview = true;
|
UpdatePreview();
|
||||||
IsDirty = true;
|
IsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMarkingColorChange(List<Marking> markings)
|
|
||||||
{
|
|
||||||
if (Profile is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithMarkings(markings));
|
|
||||||
IsDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void OnSkinColorOnValueChanged()
|
private void OnSkinColorOnValueChanged()
|
||||||
{
|
{
|
||||||
if (Profile is null) return;
|
if (Profile is null) return;
|
||||||
@@ -745,33 +691,21 @@ namespace Content.Client.Preferences.UI
|
|||||||
if (!disposing)
|
if (!disposing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_previewDummy != null)
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
_entMan.DeleteEntity(_previewDummy.Value);
|
controller.PreviewDummyUpdated -= OnDummyUpdate;
|
||||||
|
_requirements.Updated -= UpdateAntagRequirements;
|
||||||
_requirements.Updated -= UpdateRoleRequirements;
|
_requirements.Updated -= UpdateRoleRequirements;
|
||||||
_preferencesManager.OnServerDataLoaded -= LoadServerData;
|
_preferencesManager.OnServerDataLoaded -= LoadServerData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RebuildSpriteView()
|
|
||||||
{
|
|
||||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
|
||||||
var dollProto = _prototypeManager.Index<SpeciesPrototype>(species).DollPrototype;
|
|
||||||
|
|
||||||
if (_previewDummy != null)
|
|
||||||
_entMan.DeleteEntity(_previewDummy!.Value);
|
|
||||||
|
|
||||||
_previewDummy = _entMan.SpawnEntity(dollProto, MapCoordinates.Nullspace);
|
|
||||||
_previewSpriteView.SetEntity(_previewDummy);
|
|
||||||
_needUpdatePreview = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadServerData()
|
private void LoadServerData()
|
||||||
{
|
{
|
||||||
Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter;
|
Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter;
|
||||||
CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex;
|
CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex;
|
||||||
|
|
||||||
|
UpdateAntagRequirements();
|
||||||
|
UpdateRoleRequirements();
|
||||||
UpdateControls();
|
UpdateControls();
|
||||||
_needUpdatePreview = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAge(int newAge)
|
private void SetAge(int newAge)
|
||||||
@@ -813,10 +747,9 @@ namespace Content.Client.Preferences.UI
|
|||||||
OnSkinColorOnValueChanged(); // Species may have special color prefs, make sure to update it.
|
OnSkinColorOnValueChanged(); // Species may have special color prefs, make sure to update it.
|
||||||
CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well.
|
CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well.
|
||||||
UpdateSexControls(); // update sex for new species
|
UpdateSexControls(); // update sex for new species
|
||||||
RebuildSpriteView(); // they might have different inv so we need a new dummy
|
|
||||||
UpdateSpeciesGuidebookIcon();
|
UpdateSpeciesGuidebookIcon();
|
||||||
IsDirty = true;
|
IsDirty = true;
|
||||||
_needUpdatePreview = true;
|
UpdatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetName(string newName)
|
private void SetName(string newName)
|
||||||
@@ -825,18 +758,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
IsDirty = true;
|
IsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetClothing(ClothingPreference newClothing)
|
|
||||||
{
|
|
||||||
Profile = Profile?.WithClothingPreference(newClothing);
|
|
||||||
IsDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetBackpack(BackpackPreference newBackpack)
|
|
||||||
{
|
|
||||||
Profile = Profile?.WithBackpackPreference(newBackpack);
|
|
||||||
IsDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetSpawnPriority(SpawnPriorityPreference newSpawnPriority)
|
private void SetSpawnPriority(SpawnPriorityPreference newSpawnPriority)
|
||||||
{
|
{
|
||||||
Profile = Profile?.WithSpawnPriorityPreference(newSpawnPriority);
|
Profile = Profile?.WithSpawnPriorityPreference(newSpawnPriority);
|
||||||
@@ -847,12 +768,11 @@ namespace Content.Client.Preferences.UI
|
|||||||
{
|
{
|
||||||
IsDirty = false;
|
IsDirty = false;
|
||||||
|
|
||||||
if (Profile != null)
|
if (Profile == null)
|
||||||
{
|
return;
|
||||||
|
|
||||||
_preferencesManager.UpdateCharacter(Profile, CharacterSlot);
|
_preferencesManager.UpdateCharacter(Profile, CharacterSlot);
|
||||||
OnProfileChanged?.Invoke(Profile, CharacterSlot);
|
OnProfileChanged?.Invoke(Profile, CharacterSlot);
|
||||||
_needUpdatePreview = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsDirty
|
private bool IsDirty
|
||||||
@@ -861,7 +781,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isDirty = value;
|
_isDirty = value;
|
||||||
_needUpdatePreview = true;
|
|
||||||
UpdateSaveButton();
|
UpdateSaveButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -981,7 +900,7 @@ namespace Content.Client.Preferences.UI
|
|||||||
if (!_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
if (!_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var style = speciesProto.GuideBookIcon;
|
const string style = "SpeciesInfoDefault";
|
||||||
SpeciesInfoButton.StyleClasses.Add(style);
|
SpeciesInfoButton.StyleClasses.Add(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,26 +936,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
_genderButton.SelectId((int) Profile.Gender);
|
_genderButton.SelectId((int) Profile.Gender);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateClothingControls()
|
|
||||||
{
|
|
||||||
if (Profile == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_clothingButton.SelectId((int) Profile.Clothing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBackpackControls()
|
|
||||||
{
|
|
||||||
if (Profile == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_backpackButton.SelectId((int) Profile.Backpack);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSpawnPriorityControls()
|
private void UpdateSpawnPriorityControls()
|
||||||
{
|
{
|
||||||
if (Profile == null)
|
if (Profile == null)
|
||||||
@@ -1166,13 +1065,13 @@ namespace Content.Client.Preferences.UI
|
|||||||
if (Profile is null)
|
if (Profile is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var humanoid = _entMan.System<HumanoidAppearanceSystem>();
|
UserInterfaceManager.GetUIController<LobbyUIController>().UpdateCharacterUI();
|
||||||
humanoid.LoadProfile(_previewDummy!.Value, Profile);
|
SetPreviewRotation(_previewRotation);
|
||||||
|
}
|
||||||
|
|
||||||
if (ShowClothes.Pressed)
|
private void SetPreviewRotation(Direction direction)
|
||||||
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy!.Value, Profile);
|
{
|
||||||
|
_previewSpriteView.OverrideDirection = (Direction) ((int) direction % 4 * 2);
|
||||||
_previewSpriteView.OverrideDirection = (Direction) ((int) _previewRotation % 4 * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateControls()
|
public void UpdateControls()
|
||||||
@@ -1184,17 +1083,15 @@ namespace Content.Client.Preferences.UI
|
|||||||
UpdateGenderControls();
|
UpdateGenderControls();
|
||||||
UpdateSkinColor();
|
UpdateSkinColor();
|
||||||
UpdateSpecies();
|
UpdateSpecies();
|
||||||
UpdateClothingControls();
|
|
||||||
UpdateBackpackControls();
|
|
||||||
UpdateSpawnPriorityControls();
|
UpdateSpawnPriorityControls();
|
||||||
UpdateAgeEdit();
|
UpdateAgeEdit();
|
||||||
UpdateEyePickers();
|
UpdateEyePickers();
|
||||||
UpdateSaveButton();
|
UpdateSaveButton();
|
||||||
|
UpdateLoadouts();
|
||||||
UpdateJobPriorities();
|
UpdateJobPriorities();
|
||||||
UpdateAntagPreferences();
|
UpdateAntagPreferences();
|
||||||
UpdateTraitPreferences();
|
UpdateTraitPreferences();
|
||||||
UpdateMarkings();
|
UpdateMarkings();
|
||||||
RebuildSpriteView();
|
|
||||||
UpdateHairPickers();
|
UpdateHairPickers();
|
||||||
UpdateCMarkingsHair();
|
UpdateCMarkingsHair();
|
||||||
UpdateCMarkingsFacialHair();
|
UpdateCMarkingsFacialHair();
|
||||||
@@ -1202,17 +1099,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
|
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
if (_needUpdatePreview)
|
|
||||||
{
|
|
||||||
UpdatePreview();
|
|
||||||
_needUpdatePreview = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateJobPriorities()
|
private void UpdateJobPriorities()
|
||||||
{
|
{
|
||||||
foreach (var prioritySelector in _jobPriorities)
|
foreach (var prioritySelector in _jobPriorities)
|
||||||
@@ -1225,143 +1111,11 @@ namespace Content.Client.Preferences.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class RequirementsSelector<T> : Control
|
private void UpdateLoadouts()
|
||||||
{
|
{
|
||||||
public T Proto { get; }
|
foreach (var prioritySelector in _jobPriorities)
|
||||||
public bool Disabled => _lockStripe.Visible;
|
|
||||||
|
|
||||||
protected readonly RadioOptions<int> Options;
|
|
||||||
private StripeBack _lockStripe;
|
|
||||||
private Label _requirementsLabel;
|
|
||||||
|
|
||||||
protected RequirementsSelector(T proto)
|
|
||||||
{
|
{
|
||||||
Proto = proto;
|
prioritySelector.CloseLoadout();
|
||||||
|
|
||||||
Options = new RadioOptions<int>(RadioOptionsLayout.Horizontal)
|
|
||||||
{
|
|
||||||
FirstButtonStyle = StyleBase.ButtonOpenRight,
|
|
||||||
ButtonStyle = StyleBase.ButtonOpenBoth,
|
|
||||||
LastButtonStyle = StyleBase.ButtonOpenLeft
|
|
||||||
};
|
|
||||||
//Override default radio option button width
|
|
||||||
Options.GenerateItem = GenerateButton;
|
|
||||||
|
|
||||||
Options.OnItemSelected += args => Options.Select(args.Id);
|
|
||||||
|
|
||||||
_requirementsLabel = new Label()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("role-timer-locked"),
|
|
||||||
Visible = true,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
StyleClasses = {StyleBase.StyleClassLabelSubText},
|
|
||||||
};
|
|
||||||
|
|
||||||
_lockStripe = new StripeBack()
|
|
||||||
{
|
|
||||||
Visible = false,
|
|
||||||
HorizontalExpand = true,
|
|
||||||
MouseFilter = MouseFilterMode.Stop,
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
_requirementsLabel
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setup must be called after
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Actually adds the controls, must be called in the inheriting class' constructor.
|
|
||||||
/// </summary>
|
|
||||||
protected void Setup((string, int)[] items, string title, int titleSize, string? description, TextureRect? icon = null)
|
|
||||||
{
|
|
||||||
foreach (var (text, value) in items)
|
|
||||||
{
|
|
||||||
Options.AddItem(Loc.GetString(text), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
var titleLabel = new Label()
|
|
||||||
{
|
|
||||||
Margin = new Thickness(5f, 0, 5f, 0),
|
|
||||||
Text = title,
|
|
||||||
MinSize = new Vector2(titleSize, 0),
|
|
||||||
MouseFilter = MouseFilterMode.Stop,
|
|
||||||
ToolTip = description
|
|
||||||
};
|
|
||||||
|
|
||||||
var container = new BoxContainer
|
|
||||||
{
|
|
||||||
Orientation = LayoutOrientation.Horizontal,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (icon != null)
|
|
||||||
container.AddChild(icon);
|
|
||||||
container.AddChild(titleLabel);
|
|
||||||
container.AddChild(Options);
|
|
||||||
container.AddChild(_lockStripe);
|
|
||||||
|
|
||||||
AddChild(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LockRequirements(FormattedMessage requirements)
|
|
||||||
{
|
|
||||||
var tooltip = new Tooltip();
|
|
||||||
tooltip.SetMessage(requirements);
|
|
||||||
_lockStripe.TooltipSupplier = _ => tooltip;
|
|
||||||
_lockStripe.Visible = true;
|
|
||||||
Options.Visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Subscribe to roletimers event. I am too lazy to do this RN But I doubt most people will notice fn
|
|
||||||
public void UnlockRequirements()
|
|
||||||
{
|
|
||||||
_lockStripe.Visible = false;
|
|
||||||
Options.Visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Button GenerateButton(string text, int value)
|
|
||||||
{
|
|
||||||
return new Button
|
|
||||||
{
|
|
||||||
Text = text,
|
|
||||||
MinWidth = 90
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class JobPrioritySelector : RequirementsSelector<JobPrototype>
|
|
||||||
{
|
|
||||||
public JobPriority Priority
|
|
||||||
{
|
|
||||||
get => (JobPriority) Options.SelectedValue;
|
|
||||||
set => Options.SelectByValue((int) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<JobPriority>? PriorityChanged;
|
|
||||||
|
|
||||||
public JobPrioritySelector(JobPrototype proto, IPrototypeManager protoMan)
|
|
||||||
: base(proto)
|
|
||||||
{
|
|
||||||
Options.OnItemSelected += args => PriorityChanged?.Invoke(Priority);
|
|
||||||
|
|
||||||
var items = new[]
|
|
||||||
{
|
|
||||||
("humanoid-profile-editor-job-priority-high-button", (int) JobPriority.High),
|
|
||||||
("humanoid-profile-editor-job-priority-medium-button", (int) JobPriority.Medium),
|
|
||||||
("humanoid-profile-editor-job-priority-low-button", (int) JobPriority.Low),
|
|
||||||
("humanoid-profile-editor-job-priority-never-button", (int) JobPriority.Never),
|
|
||||||
};
|
|
||||||
|
|
||||||
var icon = new TextureRect
|
|
||||||
{
|
|
||||||
TextureScale = new Vector2(2, 2),
|
|
||||||
VerticalAlignment = VAlignment.Center
|
|
||||||
};
|
|
||||||
var jobIcon = protoMan.Index<StatusIconPrototype>(proto.Icon);
|
|
||||||
icon.Texture = jobIcon.Icon.Frame0();
|
|
||||||
|
|
||||||
Setup(items, proto.LocalizedName, 200, proto.LocalizedDescription, icon);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1386,41 +1140,6 @@ namespace Content.Client.Preferences.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class AntagPreferenceSelector : RequirementsSelector<AntagPrototype>
|
|
||||||
{
|
|
||||||
// 0 is yes and 1 is no
|
|
||||||
public bool Preference
|
|
||||||
{
|
|
||||||
get => Options.SelectedValue == 0;
|
|
||||||
set => Options.Select((value && !Disabled) ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<bool>? PreferenceChanged;
|
|
||||||
|
|
||||||
public AntagPreferenceSelector(AntagPrototype proto)
|
|
||||||
: base(proto)
|
|
||||||
{
|
|
||||||
Options.OnItemSelected += args => PreferenceChanged?.Invoke(Preference);
|
|
||||||
|
|
||||||
var items = new[]
|
|
||||||
{
|
|
||||||
("humanoid-profile-editor-antag-preference-yes-button", 0),
|
|
||||||
("humanoid-profile-editor-antag-preference-no-button", 1)
|
|
||||||
};
|
|
||||||
var title = Loc.GetString(proto.Name);
|
|
||||||
var description = Loc.GetString(proto.Objective);
|
|
||||||
Setup(items, title, 250, description);
|
|
||||||
|
|
||||||
// immediately lock requirements if they arent met.
|
|
||||||
// another function checks Disabled after creating the selector so this has to be done now
|
|
||||||
var requirements = IoCManager.Resolve<JobRequirementsManager>();
|
|
||||||
if (proto.Requirements != null && !requirements.CheckRoleTime(proto.Requirements, out var reason))
|
|
||||||
{
|
|
||||||
LockRequirements(reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class TraitPreferenceSelector : Control
|
private sealed class TraitPreferenceSelector : Control
|
||||||
{
|
{
|
||||||
public TraitPrototype Trait { get; }
|
public TraitPrototype Trait { get; }
|
||||||
|
|||||||
46
Content.Client/Preferences/UI/JobPrioritySelector.cs
Normal file
46
Content.Client/Preferences/UI/JobPrioritySelector.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.StatusIcon;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.Utility;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
public sealed class JobPrioritySelector : RequirementsSelector<JobPrototype>
|
||||||
|
{
|
||||||
|
public JobPriority Priority
|
||||||
|
{
|
||||||
|
get => (JobPriority) Options.SelectedValue;
|
||||||
|
set => Options.SelectByValue((int) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<JobPriority>? PriorityChanged;
|
||||||
|
|
||||||
|
public JobPrioritySelector(RoleLoadout? loadout, JobPrototype proto, ButtonGroup btnGroup, IPrototypeManager protoMan)
|
||||||
|
: base(proto, btnGroup)
|
||||||
|
{
|
||||||
|
Options.OnItemSelected += args => PriorityChanged?.Invoke(Priority);
|
||||||
|
|
||||||
|
var items = new[]
|
||||||
|
{
|
||||||
|
("humanoid-profile-editor-job-priority-high-button", (int) JobPriority.High),
|
||||||
|
("humanoid-profile-editor-job-priority-medium-button", (int) JobPriority.Medium),
|
||||||
|
("humanoid-profile-editor-job-priority-low-button", (int) JobPriority.Low),
|
||||||
|
("humanoid-profile-editor-job-priority-never-button", (int) JobPriority.Never),
|
||||||
|
};
|
||||||
|
|
||||||
|
var icon = new TextureRect
|
||||||
|
{
|
||||||
|
TextureScale = new Vector2(2, 2),
|
||||||
|
VerticalAlignment = VAlignment.Center
|
||||||
|
};
|
||||||
|
var jobIcon = protoMan.Index<StatusIconPrototype>(proto.Icon);
|
||||||
|
icon.Texture = jobIcon.Icon.Frame0();
|
||||||
|
|
||||||
|
Setup(loadout, items, proto.LocalizedName, 200, proto.LocalizedDescription, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Content.Client/Preferences/UI/LoadoutContainer.xaml
Normal file
15
Content.Client/Preferences/UI/LoadoutContainer.xaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<BoxContainer Name="Container" xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MouseFilter="Ignore"
|
||||||
|
Margin="0 0 0 5">
|
||||||
|
<Button Name="SelectButton" ToggleMode="True" Margin="0 0 5 0" HorizontalExpand="True"/>
|
||||||
|
<PanelContainer SetSize="64 64" HorizontalAlignment="Right">
|
||||||
|
<PanelContainer.PanelOverride>
|
||||||
|
<graphics:StyleBoxFlat BackgroundColor="#1B1B1E" />
|
||||||
|
</PanelContainer.PanelOverride>
|
||||||
|
<SpriteView Name="Sprite" Scale="4 4" MouseFilter="Stop"/>
|
||||||
|
</PanelContainer>
|
||||||
|
</BoxContainer>
|
||||||
74
Content.Client/Preferences/UI/LoadoutContainer.xaml.cs
Normal file
74
Content.Client/Preferences/UI/LoadoutContainer.xaml.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class LoadoutContainer : BoxContainer
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
|
|
||||||
|
private readonly EntityUid? _entity;
|
||||||
|
|
||||||
|
public Button Select => SelectButton;
|
||||||
|
|
||||||
|
public LoadoutContainer(ProtoId<LoadoutPrototype> proto, bool disabled, FormattedMessage? reason)
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
SelectButton.Disabled = disabled;
|
||||||
|
|
||||||
|
if (disabled && reason != null)
|
||||||
|
{
|
||||||
|
var tooltip = new Tooltip();
|
||||||
|
tooltip.SetMessage(reason);
|
||||||
|
SelectButton.TooltipSupplier = _ => tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_protoManager.TryIndex(proto, out var loadProto))
|
||||||
|
{
|
||||||
|
var ent = _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
|
||||||
|
|
||||||
|
if (ent != null)
|
||||||
|
{
|
||||||
|
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
|
||||||
|
Sprite.SetEntity(_entity);
|
||||||
|
|
||||||
|
var spriteTooltip = new Tooltip();
|
||||||
|
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
|
||||||
|
Sprite.TooltipSupplier = _ => spriteTooltip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (!disposing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_entManager.DeleteEntity(_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Pressed
|
||||||
|
{
|
||||||
|
get => SelectButton.Pressed;
|
||||||
|
set => SelectButton.Pressed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Text
|
||||||
|
{
|
||||||
|
get => SelectButton.Text;
|
||||||
|
set => SelectButton.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Content.Client/Preferences/UI/LoadoutGroupContainer.xaml
Normal file
10
Content.Client/Preferences/UI/LoadoutGroupContainer.xaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True">
|
||||||
|
<BoxContainer Name="LoadoutsContainer" Orientation="Vertical"/>
|
||||||
|
</PanelContainer>
|
||||||
|
<!-- Buffer space so we have 10 margin between controls but also 10 to the borders -->
|
||||||
|
<Label Text="{Loc 'loadout-restrictions'}" Margin="5 0 5 5"/>
|
||||||
|
<BoxContainer Name="RestrictionsContainer" Orientation="Vertical" HorizontalExpand="True" />
|
||||||
|
</BoxContainer>
|
||||||
93
Content.Client/Preferences/UI/LoadoutGroupContainer.xaml.cs
Normal file
93
Content.Client/Preferences/UI/LoadoutGroupContainer.xaml.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||||
|
{
|
||||||
|
private readonly LoadoutGroupPrototype _groupProto;
|
||||||
|
|
||||||
|
public event Action<ProtoId<LoadoutPrototype>>? OnLoadoutPressed;
|
||||||
|
public event Action<ProtoId<LoadoutPrototype>>? OnLoadoutUnpressed;
|
||||||
|
|
||||||
|
public LoadoutGroupContainer(RoleLoadout loadout, LoadoutGroupPrototype groupProto, ICommonSession session, IDependencyCollection collection)
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
_groupProto = groupProto;
|
||||||
|
|
||||||
|
RefreshLoadouts(loadout, session, collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates button availabilities and buttons.
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshLoadouts(RoleLoadout loadout, ICommonSession session, IDependencyCollection collection)
|
||||||
|
{
|
||||||
|
var protoMan = collection.Resolve<IPrototypeManager>();
|
||||||
|
var loadoutSystem = collection.Resolve<IEntityManager>().System<LoadoutSystem>();
|
||||||
|
RestrictionsContainer.DisposeAllChildren();
|
||||||
|
|
||||||
|
if (_groupProto.MinLimit > 0)
|
||||||
|
{
|
||||||
|
RestrictionsContainer.AddChild(new Label()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("loadouts-min-limit", ("count", _groupProto.MinLimit)),
|
||||||
|
Margin = new Thickness(5, 0, 5, 5),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_groupProto.MaxLimit > 0)
|
||||||
|
{
|
||||||
|
RestrictionsContainer.AddChild(new Label()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("loadouts-max-limit", ("count", _groupProto.MaxLimit)),
|
||||||
|
Margin = new Thickness(5, 0, 5, 5),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protoMan.TryIndex(loadout.Role, out var roleProto) && roleProto.Points != null && loadout.Points != null)
|
||||||
|
{
|
||||||
|
RestrictionsContainer.AddChild(new Label()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("loadouts-points-limit", ("count", loadout.Points.Value), ("max", roleProto.Points.Value)),
|
||||||
|
Margin = new Thickness(5, 0, 5, 5),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadoutsContainer.DisposeAllChildren();
|
||||||
|
// Didn't use options because this is more robust in future.
|
||||||
|
|
||||||
|
var selected = loadout.SelectedLoadouts[_groupProto.ID];
|
||||||
|
|
||||||
|
foreach (var loadoutProto in _groupProto.Loadouts)
|
||||||
|
{
|
||||||
|
if (!protoMan.TryIndex(loadoutProto, out var loadProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var matchingLoadout = selected.FirstOrDefault(e => e.Prototype == loadoutProto);
|
||||||
|
var pressed = matchingLoadout != null;
|
||||||
|
|
||||||
|
var enabled = loadout.IsValid(session, loadoutProto, collection, out var reason);
|
||||||
|
var loadoutContainer = new LoadoutContainer(loadoutProto, !enabled, reason);
|
||||||
|
loadoutContainer.Select.Pressed = pressed;
|
||||||
|
loadoutContainer.Text = loadoutSystem.GetName(loadProto);
|
||||||
|
|
||||||
|
loadoutContainer.Select.OnPressed += args =>
|
||||||
|
{
|
||||||
|
if (args.Button.Pressed)
|
||||||
|
OnLoadoutPressed?.Invoke(loadoutProto);
|
||||||
|
else
|
||||||
|
OnLoadoutUnpressed?.Invoke(loadoutProto);
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadoutsContainer.AddChild(loadoutContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Content.Client/Preferences/UI/LoadoutWindow.xaml
Normal file
10
Content.Client/Preferences/UI/LoadoutWindow.xaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
|
SetSize="800 800"
|
||||||
|
MinSize="800 64">
|
||||||
|
<VerticalTabContainer Name="LoadoutGroupsContainer"
|
||||||
|
VerticalExpand="True"
|
||||||
|
HorizontalExpand="True">
|
||||||
|
</VerticalTabContainer>
|
||||||
|
</controls:FancyWindow>
|
||||||
60
Content.Client/Preferences/UI/LoadoutWindow.xaml.cs
Normal file
60
Content.Client/Preferences/UI/LoadoutWindow.xaml.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Content.Client.Lobby;
|
||||||
|
using Content.Client.UserInterface.Controls;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class LoadoutWindow : FancyWindow
|
||||||
|
{
|
||||||
|
public event Action<ProtoId<LoadoutGroupPrototype>, ProtoId<LoadoutPrototype>>? OnLoadoutPressed;
|
||||||
|
public event Action<ProtoId<LoadoutGroupPrototype>, ProtoId<LoadoutPrototype>>? OnLoadoutUnpressed;
|
||||||
|
|
||||||
|
private List<LoadoutGroupContainer> _groups = new();
|
||||||
|
|
||||||
|
public LoadoutWindow(RoleLoadout loadout, RoleLoadoutPrototype proto, ICommonSession session, IDependencyCollection collection)
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
var protoManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
foreach (var group in proto.Groups)
|
||||||
|
{
|
||||||
|
if (!protoManager.TryIndex(group, out var groupProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var container = new LoadoutGroupContainer(loadout, protoManager.Index(group), session, collection);
|
||||||
|
LoadoutGroupsContainer.AddTab(container, Loc.GetString(groupProto.Name));
|
||||||
|
_groups.Add(container);
|
||||||
|
|
||||||
|
container.OnLoadoutPressed += args =>
|
||||||
|
{
|
||||||
|
OnLoadoutPressed?.Invoke(group, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
container.OnLoadoutUnpressed += args =>
|
||||||
|
{
|
||||||
|
OnLoadoutUnpressed?.Invoke(group, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
base.Close();
|
||||||
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
controller.SetDummyJob(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshLoadouts(RoleLoadout loadout, ICommonSession session, IDependencyCollection collection)
|
||||||
|
{
|
||||||
|
foreach (var group in _groups)
|
||||||
|
{
|
||||||
|
group.RefreshLoadouts(loadout, session, collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
222
Content.Client/Preferences/UI/RequirementsSelector.cs
Normal file
222
Content.Client/Preferences/UI/RequirementsSelector.cs
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Lobby;
|
||||||
|
using Content.Client.Stylesheets;
|
||||||
|
using Content.Client.UserInterface.Controls;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Preferences.UI;
|
||||||
|
|
||||||
|
public abstract class RequirementsSelector<T> : BoxContainer where T : IPrototype
|
||||||
|
{
|
||||||
|
private ButtonGroup _loadoutGroup;
|
||||||
|
|
||||||
|
public T Proto { get; }
|
||||||
|
public bool Disabled => _lockStripe.Visible;
|
||||||
|
|
||||||
|
protected readonly RadioOptions<int> Options;
|
||||||
|
private readonly StripeBack _lockStripe;
|
||||||
|
private LoadoutWindow? _loadoutWindow;
|
||||||
|
|
||||||
|
private RoleLoadout? _loadout;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised if a loadout has been updated.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<RoleLoadout>? LoadoutUpdated;
|
||||||
|
|
||||||
|
protected RequirementsSelector(T proto, ButtonGroup loadoutGroup)
|
||||||
|
{
|
||||||
|
_loadoutGroup = loadoutGroup;
|
||||||
|
Proto = proto;
|
||||||
|
|
||||||
|
Options = new RadioOptions<int>(RadioOptionsLayout.Horizontal)
|
||||||
|
{
|
||||||
|
FirstButtonStyle = StyleBase.ButtonOpenRight,
|
||||||
|
ButtonStyle = StyleBase.ButtonOpenBoth,
|
||||||
|
LastButtonStyle = StyleBase.ButtonOpenLeft,
|
||||||
|
HorizontalExpand = true,
|
||||||
|
};
|
||||||
|
//Override default radio option button width
|
||||||
|
Options.GenerateItem = GenerateButton;
|
||||||
|
|
||||||
|
Options.OnItemSelected += args => Options.Select(args.Id);
|
||||||
|
|
||||||
|
var requirementsLabel = new Label()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("role-timer-locked"),
|
||||||
|
Visible = true,
|
||||||
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
StyleClasses = {StyleBase.StyleClassLabelSubText},
|
||||||
|
};
|
||||||
|
|
||||||
|
_lockStripe = new StripeBack()
|
||||||
|
{
|
||||||
|
Visible = false,
|
||||||
|
HorizontalExpand = true,
|
||||||
|
HasMargins = false,
|
||||||
|
MouseFilter = MouseFilterMode.Stop,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
requirementsLabel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup must be called after
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actually adds the controls, must be called in the inheriting class' constructor.
|
||||||
|
/// </summary>
|
||||||
|
protected void Setup(RoleLoadout? loadout, (string, int)[] items, string title, int titleSize, string? description, TextureRect? icon = null)
|
||||||
|
{
|
||||||
|
_loadout = loadout;
|
||||||
|
|
||||||
|
foreach (var (text, value) in items)
|
||||||
|
{
|
||||||
|
Options.AddItem(Loc.GetString(text), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var titleLabel = new Label()
|
||||||
|
{
|
||||||
|
Margin = new Thickness(5f, 0, 5f, 0),
|
||||||
|
Text = title,
|
||||||
|
MinSize = new Vector2(titleSize, 0),
|
||||||
|
MouseFilter = MouseFilterMode.Stop,
|
||||||
|
ToolTip = description
|
||||||
|
};
|
||||||
|
|
||||||
|
if (icon != null)
|
||||||
|
AddChild(icon);
|
||||||
|
|
||||||
|
AddChild(titleLabel);
|
||||||
|
AddChild(Options);
|
||||||
|
AddChild(_lockStripe);
|
||||||
|
|
||||||
|
var loadoutWindowBtn = new Button()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("loadout-window"),
|
||||||
|
HorizontalAlignment = HAlignment.Right,
|
||||||
|
Group = _loadoutGroup,
|
||||||
|
Margin = new Thickness(3f, 0f, 0f, 0f),
|
||||||
|
};
|
||||||
|
|
||||||
|
var collection = IoCManager.Instance!;
|
||||||
|
var protoManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
// If no loadout found then disabled button
|
||||||
|
if (!protoManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(Proto.ID)))
|
||||||
|
{
|
||||||
|
loadoutWindowBtn.Disabled = true;
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var session = collection.Resolve<IPlayerManager>().LocalSession!;
|
||||||
|
// TODO: Most of lobby state should be a uicontroller
|
||||||
|
// trying to handle all this shit is a big-ass mess.
|
||||||
|
// Every time I touch it I try to make it slightly better but it needs a howitzer dropped on it.
|
||||||
|
loadoutWindowBtn.OnPressed += args =>
|
||||||
|
{
|
||||||
|
if (args.Button.Pressed)
|
||||||
|
{
|
||||||
|
// We only create a loadout when necessary to avoid unnecessary DB entries.
|
||||||
|
_loadout ??= new RoleLoadout(LoadoutSystem.GetJobPrototype(Proto.ID));
|
||||||
|
_loadout.SetDefault(protoManager);
|
||||||
|
|
||||||
|
_loadoutWindow = new LoadoutWindow(_loadout, protoManager.Index(_loadout.Role), session, collection)
|
||||||
|
{
|
||||||
|
Title = Loc.GetString(Proto.ID + "-loadout"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_loadoutWindow.RefreshLoadouts(_loadout, session, collection);
|
||||||
|
|
||||||
|
// If it's a job preview then refresh it.
|
||||||
|
if (Proto is JobPrototype jobProto)
|
||||||
|
{
|
||||||
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
controller.SetDummyJob(jobProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadoutWindow.OnLoadoutUnpressed += (selectedGroup, selectedLoadout) =>
|
||||||
|
{
|
||||||
|
if (!_loadout.RemoveLoadout(selectedGroup, selectedLoadout, protoManager))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_loadout.EnsureValid(session, collection);
|
||||||
|
_loadoutWindow.RefreshLoadouts(_loadout, session, collection);
|
||||||
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
controller.UpdateCharacterUI();
|
||||||
|
LoadoutUpdated?.Invoke(_loadout);
|
||||||
|
};
|
||||||
|
|
||||||
|
_loadoutWindow.OnLoadoutPressed += (selectedGroup, selectedLoadout) =>
|
||||||
|
{
|
||||||
|
if (!_loadout.AddLoadout(selectedGroup, selectedLoadout, protoManager))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_loadout.EnsureValid(session, collection);
|
||||||
|
_loadoutWindow.RefreshLoadouts(_loadout, session, collection);
|
||||||
|
var controller = UserInterfaceManager.GetUIController<LobbyUIController>();
|
||||||
|
controller.UpdateCharacterUI();
|
||||||
|
LoadoutUpdated?.Invoke(_loadout);
|
||||||
|
};
|
||||||
|
|
||||||
|
_loadoutWindow.OpenCenteredLeft();
|
||||||
|
_loadoutWindow.OnClose += () =>
|
||||||
|
{
|
||||||
|
loadoutWindowBtn.Pressed = false;
|
||||||
|
_loadoutWindow?.Dispose();
|
||||||
|
_loadoutWindow = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseLoadout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AddChild(loadoutWindowBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseLoadout()
|
||||||
|
{
|
||||||
|
_loadoutWindow?.Close();
|
||||||
|
_loadoutWindow?.Dispose();
|
||||||
|
_loadoutWindow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LockRequirements(FormattedMessage requirements)
|
||||||
|
{
|
||||||
|
var tooltip = new Tooltip();
|
||||||
|
tooltip.SetMessage(requirements);
|
||||||
|
_lockStripe.TooltipSupplier = _ => tooltip;
|
||||||
|
_lockStripe.Visible = true;
|
||||||
|
Options.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Subscribe to roletimers event. I am too lazy to do this RN But I doubt most people will notice fn
|
||||||
|
public void UnlockRequirements()
|
||||||
|
{
|
||||||
|
_lockStripe.Visible = false;
|
||||||
|
Options.Visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button GenerateButton(string text, int value)
|
||||||
|
{
|
||||||
|
return new Button
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
MinWidth = 90,
|
||||||
|
HorizontalExpand = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ public sealed partial class MindTests
|
|||||||
await using var pair = await PoolManager.GetServerClient(settings);
|
await using var pair = await PoolManager.GetServerClient(settings);
|
||||||
|
|
||||||
// Client is connected with a valid entity & mind
|
// Client is connected with a valid entity & mind
|
||||||
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.Player?.ControlledEntity));
|
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.AttachedEntity));
|
||||||
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
||||||
|
|
||||||
// Delete **everything**
|
// Delete **everything**
|
||||||
@@ -28,6 +28,12 @@ public sealed partial class MindTests
|
|||||||
await pair.RunTicksSync(5);
|
await pair.RunTicksSync(5);
|
||||||
|
|
||||||
Assert.That(pair.Server.EntMan.EntityCount, Is.EqualTo(0));
|
Assert.That(pair.Server.EntMan.EntityCount, Is.EqualTo(0));
|
||||||
|
|
||||||
|
foreach (var ent in pair.Client.EntMan.GetEntities())
|
||||||
|
{
|
||||||
|
Console.WriteLine(pair.Client.EntMan.ToPrettyString(ent));
|
||||||
|
}
|
||||||
|
|
||||||
Assert.That(pair.Client.EntMan.EntityCount, Is.EqualTo(0));
|
Assert.That(pair.Client.EntMan.EntityCount, Is.EqualTo(0));
|
||||||
|
|
||||||
// Create a new map.
|
// Create a new map.
|
||||||
@@ -36,7 +42,7 @@ public sealed partial class MindTests
|
|||||||
await pair.RunTicksSync(5);
|
await pair.RunTicksSync(5);
|
||||||
|
|
||||||
// Client is not attached to anything
|
// Client is not attached to anything
|
||||||
Assert.That(pair.Client.Player?.ControlledEntity, Is.Null);
|
Assert.That(pair.Client.AttachedEntity, Is.Null);
|
||||||
Assert.That(pair.PlayerData?.Mind, Is.Null);
|
Assert.That(pair.PlayerData?.Mind, Is.Null);
|
||||||
|
|
||||||
// Attempt to ghost
|
// Attempt to ghost
|
||||||
@@ -45,9 +51,9 @@ public sealed partial class MindTests
|
|||||||
await pair.RunTicksSync(10);
|
await pair.RunTicksSync(10);
|
||||||
|
|
||||||
// Client should be attached to a ghost placed on the new map.
|
// Client should be attached to a ghost placed on the new map.
|
||||||
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.Player?.ControlledEntity));
|
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.AttachedEntity));
|
||||||
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
||||||
var xform = pair.Client.Transform(pair.Client.Player!.ControlledEntity!.Value);
|
var xform = pair.Client.Transform(pair.Client.AttachedEntity!.Value);
|
||||||
Assert.That(xform.MapID, Is.EqualTo(new MapId(mapId)));
|
Assert.That(xform.MapID, Is.EqualTo(new MapId(mapId)));
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
await pair.CleanReturnAsync();
|
||||||
|
|||||||
44
Content.IntegrationTests/Tests/Preferences/LoadoutTests.cs
Normal file
44
Content.IntegrationTests/Tests/Preferences/LoadoutTests.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Content.Server.Station.Systems;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Roles.Jobs;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Preferences;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
[Ignore("HumanoidAppearance crashes upon loading default profiles.")]
|
||||||
|
public sealed class LoadoutTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks that an empty loadout still spawns with default gear and not naked.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task TestEmptyLoadout()
|
||||||
|
{
|
||||||
|
var pair = await PoolManager.GetServerClient(new PoolSettings()
|
||||||
|
{
|
||||||
|
Dirty = true,
|
||||||
|
});
|
||||||
|
var server = pair.Server;
|
||||||
|
|
||||||
|
var entManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
|
||||||
|
// Check that an empty role loadout spawns gear
|
||||||
|
var stationSystem = entManager.System<StationSpawningSystem>();
|
||||||
|
var testMap = await pair.CreateTestMap();
|
||||||
|
|
||||||
|
// That's right I can't even spawn a dummy profile without station spawning / humanoidappearance code crashing.
|
||||||
|
var profile = new HumanoidCharacterProfile();
|
||||||
|
|
||||||
|
profile.SetLoadout(new RoleLoadout("TestRoleLoadout"));
|
||||||
|
|
||||||
|
stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
|
||||||
|
{
|
||||||
|
// Sue me, there's so much involved in setting up jobs
|
||||||
|
Prototype = "CargoTechnician"
|
||||||
|
}, profile, station: null);
|
||||||
|
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ using Content.Server.Database;
|
|||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
@@ -53,8 +55,6 @@ namespace Content.IntegrationTests.Tests.Preferences
|
|||||||
Color.Beige,
|
Color.Beige,
|
||||||
new ()
|
new ()
|
||||||
),
|
),
|
||||||
ClothingPreference.Jumpskirt,
|
|
||||||
BackpackPreference.Backpack,
|
|
||||||
SpawnPriorityPreference.None,
|
SpawnPriorityPreference.None,
|
||||||
new Dictionary<string, JobPriority>
|
new Dictionary<string, JobPriority>
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,8 @@ namespace Content.IntegrationTests.Tests.Preferences
|
|||||||
},
|
},
|
||||||
PreferenceUnavailableMode.StayInLobby,
|
PreferenceUnavailableMode.StayInLobby,
|
||||||
new List<string> (),
|
new List<string> (),
|
||||||
new List<string>()
|
new List<string>(),
|
||||||
|
new Dictionary<string, RoleLoadout>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1838
Content.Server.Database/Migrations/Postgres/20240301130641_ClothingRemoval.Designer.cs
generated
Normal file
1838
Content.Server.Database/Migrations/Postgres/20240301130641_ClothingRemoval.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ClothingRemoval : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "backpack",
|
||||||
|
table: "profile");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "clothing",
|
||||||
|
table: "profile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "backpack",
|
||||||
|
table: "profile",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "clothing",
|
||||||
|
table: "profile",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1884
Content.Server.Database/Migrations/Postgres/20240403072242_Loadouts.Designer.cs
generated
Normal file
1884
Content.Server.Database/Migrations/Postgres/20240403072242_Loadouts.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Loadouts : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_role_loadout",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_role_loadout_id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
profile_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
role_name = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_role_loadout", x => x.profile_role_loadout_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_role_loadout_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_loadout_group",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_loadout_group_id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
profile_role_loadout_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
group_name = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_loadout_group", x => x.profile_loadout_group_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_loadout_group_profile_role_loadout_profile_role_loa~",
|
||||||
|
column: x => x.profile_role_loadout_id,
|
||||||
|
principalTable: "profile_role_loadout",
|
||||||
|
principalColumn: "profile_role_loadout_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_loadout",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_loadout_id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
profile_loadout_group_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
loadout_name = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_loadout", x => x.profile_loadout_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_loadout_profile_loadout_group_profile_loadout_group~",
|
||||||
|
column: x => x.profile_loadout_group_id,
|
||||||
|
principalTable: "profile_loadout_group",
|
||||||
|
principalColumn: "profile_loadout_group_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_loadout_profile_loadout_group_id",
|
||||||
|
table: "profile_loadout",
|
||||||
|
column: "profile_loadout_group_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_loadout_group_profile_role_loadout_id",
|
||||||
|
table: "profile_loadout_group",
|
||||||
|
column: "profile_role_loadout_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_role_loadout_profile_id",
|
||||||
|
table: "profile_role_loadout",
|
||||||
|
column: "profile_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_loadout");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_loadout_group");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_role_loadout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -735,21 +735,11 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("age");
|
.HasColumnName("age");
|
||||||
|
|
||||||
b.Property<string>("Backpack")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("backpack");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
b.Property<string>("CharacterName")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("char_name");
|
.HasColumnName("char_name");
|
||||||
|
|
||||||
b.Property<string>("Clothing")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("clothing");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
b.Property<string>("EyeColor")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
@@ -832,6 +822,84 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
b.ToTable("profile", (string)null);
|
b.ToTable("profile", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_loadout_id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("LoadoutName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("loadout_name");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileLoadoutGroupId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_loadout_group_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_loadout");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileLoadoutGroupId");
|
||||||
|
|
||||||
|
b.ToTable("profile_loadout", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_loadout_group_id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("GroupName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("group_name");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileRoleLoadoutId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_role_loadout_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_loadout_group");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileRoleLoadoutId");
|
||||||
|
|
||||||
|
b.ToTable("profile_loadout_group", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_role_loadout_id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("profile_id");
|
||||||
|
|
||||||
|
b.Property<string>("RoleName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("role_name");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_role_loadout");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("profile_role_loadout", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1519,6 +1587,42 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
b.Navigation("Preference");
|
b.Navigation("Preference");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup")
|
||||||
|
.WithMany("Loadouts")
|
||||||
|
.HasForeignKey("ProfileLoadoutGroupId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group~");
|
||||||
|
|
||||||
|
b.Navigation("ProfileLoadoutGroup");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout")
|
||||||
|
.WithMany("Groups")
|
||||||
|
.HasForeignKey("ProfileRoleLoadoutId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loa~");
|
||||||
|
|
||||||
|
b.Navigation("ProfileRoleLoadout");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Loadouts")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_role_loadout_profile_profile_id");
|
||||||
|
|
||||||
|
b.Navigation("Profile");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Content.Server.Database.Server", "Server")
|
b.HasOne("Content.Server.Database.Server", "Server")
|
||||||
@@ -1731,9 +1835,21 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
|
|
||||||
b.Navigation("Jobs");
|
b.Navigation("Jobs");
|
||||||
|
|
||||||
|
b.Navigation("Loadouts");
|
||||||
|
|
||||||
b.Navigation("Traits");
|
b.Navigation("Traits");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Loadouts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Groups");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("AdminLogs");
|
b.Navigation("AdminLogs");
|
||||||
|
|||||||
1765
Content.Server.Database/Migrations/Sqlite/20240301130602_ClothingRemoval.Designer.cs
generated
Normal file
1765
Content.Server.Database/Migrations/Sqlite/20240301130602_ClothingRemoval.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ClothingRemoval : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "backpack",
|
||||||
|
table: "profile");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "clothing",
|
||||||
|
table: "profile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "backpack",
|
||||||
|
table: "profile",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "clothing",
|
||||||
|
table: "profile",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1809
Content.Server.Database/Migrations/Sqlite/20240403072258_Loadouts.Designer.cs
generated
Normal file
1809
Content.Server.Database/Migrations/Sqlite/20240403072258_Loadouts.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Loadouts : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_role_loadout",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_role_loadout_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
profile_id = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
role_name = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_role_loadout", x => x.profile_role_loadout_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_role_loadout_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_loadout_group",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_loadout_group_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
profile_role_loadout_id = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
group_name = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_loadout_group", x => x.profile_loadout_group_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_loadout_group_profile_role_loadout_profile_role_loadout_id",
|
||||||
|
column: x => x.profile_role_loadout_id,
|
||||||
|
principalTable: "profile_role_loadout",
|
||||||
|
principalColumn: "profile_role_loadout_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile_loadout",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_loadout_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
profile_loadout_group_id = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
loadout_name = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile_loadout", x => x.profile_loadout_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_loadout_profile_loadout_group_profile_loadout_group_id",
|
||||||
|
column: x => x.profile_loadout_group_id,
|
||||||
|
principalTable: "profile_loadout_group",
|
||||||
|
principalColumn: "profile_loadout_group_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_loadout_profile_loadout_group_id",
|
||||||
|
table: "profile_loadout",
|
||||||
|
column: "profile_loadout_group_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_loadout_group_profile_role_loadout_id",
|
||||||
|
table: "profile_loadout_group",
|
||||||
|
column: "profile_role_loadout_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_role_loadout_profile_id",
|
||||||
|
table: "profile_role_loadout",
|
||||||
|
column: "profile_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_loadout");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_loadout_group");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile_role_loadout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -688,21 +688,11 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
.HasColumnType("INTEGER")
|
.HasColumnType("INTEGER")
|
||||||
.HasColumnName("age");
|
.HasColumnName("age");
|
||||||
|
|
||||||
b.Property<string>("Backpack")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("backpack");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
b.Property<string>("CharacterName")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType("TEXT")
|
||||||
.HasColumnName("char_name");
|
.HasColumnName("char_name");
|
||||||
|
|
||||||
b.Property<string>("Clothing")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("clothing");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
b.Property<string>("EyeColor")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType("TEXT")
|
||||||
@@ -785,6 +775,78 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
b.ToTable("profile", (string)null);
|
b.ToTable("profile", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_loadout_id");
|
||||||
|
|
||||||
|
b.Property<string>("LoadoutName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("loadout_name");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileLoadoutGroupId")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_loadout_group_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_loadout");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileLoadoutGroupId");
|
||||||
|
|
||||||
|
b.ToTable("profile_loadout", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_loadout_group_id");
|
||||||
|
|
||||||
|
b.Property<string>("GroupName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("group_name");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileRoleLoadoutId")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_role_loadout_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_loadout_group");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileRoleLoadoutId");
|
||||||
|
|
||||||
|
b.ToTable("profile_loadout_group", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_role_loadout_id");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("profile_id");
|
||||||
|
|
||||||
|
b.Property<string>("RoleName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("role_name");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("PK_profile_role_loadout");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("profile_role_loadout", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1450,6 +1512,42 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
b.Navigation("Preference");
|
b.Navigation("Preference");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup")
|
||||||
|
.WithMany("Loadouts")
|
||||||
|
.HasForeignKey("ProfileLoadoutGroupId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group_id");
|
||||||
|
|
||||||
|
b.Navigation("ProfileLoadoutGroup");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout")
|
||||||
|
.WithMany("Groups")
|
||||||
|
.HasForeignKey("ProfileRoleLoadoutId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loadout_id");
|
||||||
|
|
||||||
|
b.Navigation("ProfileRoleLoadout");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Loadouts")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("FK_profile_role_loadout_profile_profile_id");
|
||||||
|
|
||||||
|
b.Navigation("Profile");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Content.Server.Database.Server", "Server")
|
b.HasOne("Content.Server.Database.Server", "Server")
|
||||||
@@ -1662,9 +1760,21 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
|
|
||||||
b.Navigation("Jobs");
|
b.Navigation("Jobs");
|
||||||
|
|
||||||
|
b.Navigation("Loadouts");
|
||||||
|
|
||||||
b.Navigation("Traits");
|
b.Navigation("Traits");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Loadouts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Groups");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("AdminLogs");
|
b.Navigation("AdminLogs");
|
||||||
|
|||||||
@@ -59,6 +59,24 @@ namespace Content.Server.Database
|
|||||||
.HasIndex(p => new {HumanoidProfileId = p.ProfileId, p.TraitName})
|
.HasIndex(p => new {HumanoidProfileId = p.ProfileId, p.TraitName})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<ProfileRoleLoadout>()
|
||||||
|
.HasOne(e => e.Profile)
|
||||||
|
.WithMany(e => e.Loadouts)
|
||||||
|
.HasForeignKey(e => e.ProfileId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
modelBuilder.Entity<ProfileLoadoutGroup>()
|
||||||
|
.HasOne(e => e.ProfileRoleLoadout)
|
||||||
|
.WithMany(e => e.Groups)
|
||||||
|
.HasForeignKey(e => e.ProfileRoleLoadoutId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
modelBuilder.Entity<ProfileLoadout>()
|
||||||
|
.HasOne(e => e.ProfileLoadoutGroup)
|
||||||
|
.WithMany(e => e.Loadouts)
|
||||||
|
.HasForeignKey(e => e.ProfileLoadoutGroupId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
modelBuilder.Entity<Job>()
|
modelBuilder.Entity<Job>()
|
||||||
.HasIndex(j => j.ProfileId);
|
.HasIndex(j => j.ProfileId);
|
||||||
|
|
||||||
@@ -337,13 +355,13 @@ namespace Content.Server.Database
|
|||||||
public string FacialHairColor { get; set; } = null!;
|
public string FacialHairColor { get; set; } = null!;
|
||||||
public string EyeColor { get; set; } = null!;
|
public string EyeColor { get; set; } = null!;
|
||||||
public string SkinColor { get; set; } = null!;
|
public string SkinColor { get; set; } = null!;
|
||||||
public string Clothing { get; set; } = null!;
|
|
||||||
public string Backpack { get; set; } = null!;
|
|
||||||
public int SpawnPriority { get; set; } = 0;
|
public int SpawnPriority { get; set; } = 0;
|
||||||
public List<Job> Jobs { get; } = new();
|
public List<Job> Jobs { get; } = new();
|
||||||
public List<Antag> Antags { get; } = new();
|
public List<Antag> Antags { get; } = new();
|
||||||
public List<Trait> Traits { get; } = new();
|
public List<Trait> Traits { get; } = new();
|
||||||
|
|
||||||
|
public List<ProfileRoleLoadout> Loadouts { get; } = new();
|
||||||
|
|
||||||
[Column("pref_unavailable")] public DbPreferenceUnavailableMode PreferenceUnavailable { get; set; }
|
[Column("pref_unavailable")] public DbPreferenceUnavailableMode PreferenceUnavailable { get; set; }
|
||||||
|
|
||||||
public int PreferenceId { get; set; }
|
public int PreferenceId { get; set; }
|
||||||
@@ -387,6 +405,79 @@ namespace Content.Server.Database
|
|||||||
public string TraitName { get; set; } = null!;
|
public string TraitName { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Loadouts
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to a single role's loadout inside the DB.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileRoleLoadout
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int ProfileId { get; set; }
|
||||||
|
|
||||||
|
public Profile Profile { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The corresponding role prototype on the profile.
|
||||||
|
/// </summary>
|
||||||
|
public string RoleName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Store the saved loadout groups. These may get validated and removed when loaded at runtime.
|
||||||
|
/// </summary>
|
||||||
|
public List<ProfileLoadoutGroup> Groups { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to a loadout group prototype with the specified loadouts attached.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileLoadoutGroup
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int ProfileRoleLoadoutId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The corresponding RoleLoadout that owns this.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileRoleLoadout ProfileRoleLoadout { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The corresponding group prototype.
|
||||||
|
/// </summary>
|
||||||
|
public string GroupName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selected loadout prototype. Null if none is set.
|
||||||
|
/// May get validated at runtime and updated to to the default.
|
||||||
|
/// </summary>
|
||||||
|
public List<ProfileLoadout> Loadouts { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to a selected loadout.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileLoadout
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int ProfileLoadoutGroupId { get; set; }
|
||||||
|
|
||||||
|
public ProfileLoadoutGroup ProfileLoadoutGroup { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponding loadout prototype.
|
||||||
|
/// </summary>
|
||||||
|
public string LoadoutName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert extra data here like custom descriptions or colors or whatever.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public enum DbPreferenceUnavailableMode
|
public enum DbPreferenceUnavailableMode
|
||||||
{
|
{
|
||||||
// These enum values HAVE to match the ones in PreferenceUnavailableMode in Shared.
|
// These enum values HAVE to match the ones in PreferenceUnavailableMode in Shared.
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ namespace Content.Server.Administration.Commands
|
|||||||
foreach (var slot in slots)
|
foreach (var slot in slots)
|
||||||
{
|
{
|
||||||
invSystem.TryUnequip(target, slot.Name, true, true, false, inventoryComponent);
|
invSystem.TryUnequip(target, slot.Name, true, true, false, inventoryComponent);
|
||||||
var gearStr = startingGear.GetGear(slot.Name, profile);
|
var gearStr = startingGear.GetGear(slot.Name);
|
||||||
if (gearStr == string.Empty)
|
if (gearStr == string.Empty)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Humanoid.Markings;
|
using Content.Shared.Humanoid.Markings;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
@@ -40,6 +42,10 @@ namespace Content.Server.Database
|
|||||||
.Include(p => p.Profiles).ThenInclude(h => h.Jobs)
|
.Include(p => p.Profiles).ThenInclude(h => h.Jobs)
|
||||||
.Include(p => p.Profiles).ThenInclude(h => h.Antags)
|
.Include(p => p.Profiles).ThenInclude(h => h.Antags)
|
||||||
.Include(p => p.Profiles).ThenInclude(h => h.Traits)
|
.Include(p => p.Profiles).ThenInclude(h => h.Traits)
|
||||||
|
.Include(p => p.Profiles)
|
||||||
|
.ThenInclude(h => h.Loadouts)
|
||||||
|
.ThenInclude(l => l.Groups)
|
||||||
|
.ThenInclude(group => group.Loadouts)
|
||||||
.AsSingleQuery()
|
.AsSingleQuery()
|
||||||
.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
|
.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
|
||||||
|
|
||||||
@@ -88,6 +94,9 @@ namespace Content.Server.Database
|
|||||||
.Include(p => p.Jobs)
|
.Include(p => p.Jobs)
|
||||||
.Include(p => p.Antags)
|
.Include(p => p.Antags)
|
||||||
.Include(p => p.Traits)
|
.Include(p => p.Traits)
|
||||||
|
.Include(p => p.Loadouts)
|
||||||
|
.ThenInclude(l => l.Groups)
|
||||||
|
.ThenInclude(group => group.Loadouts)
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
.SingleOrDefault(h => h.Slot == slot);
|
.SingleOrDefault(h => h.Slot == slot);
|
||||||
|
|
||||||
@@ -179,14 +188,6 @@ namespace Content.Server.Database
|
|||||||
if (Enum.TryParse<Sex>(profile.Sex, true, out var sexVal))
|
if (Enum.TryParse<Sex>(profile.Sex, true, out var sexVal))
|
||||||
sex = sexVal;
|
sex = sexVal;
|
||||||
|
|
||||||
var clothing = ClothingPreference.Jumpsuit;
|
|
||||||
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 spawnPriority = (SpawnPriorityPreference) profile.SpawnPriority;
|
var spawnPriority = (SpawnPriorityPreference) profile.SpawnPriority;
|
||||||
|
|
||||||
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
|
var gender = sex == Sex.Male ? Gender.Male : Gender.Female;
|
||||||
@@ -209,6 +210,27 @@ namespace Content.Server.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var loadouts = new Dictionary<string, RoleLoadout>();
|
||||||
|
|
||||||
|
foreach (var role in profile.Loadouts)
|
||||||
|
{
|
||||||
|
var loadout = new RoleLoadout(role.RoleName);
|
||||||
|
|
||||||
|
foreach (var group in role.Groups)
|
||||||
|
{
|
||||||
|
var groupLoadouts = loadout.SelectedLoadouts.GetOrNew(group.GroupName);
|
||||||
|
foreach (var profLoadout in group.Loadouts)
|
||||||
|
{
|
||||||
|
groupLoadouts.Add(new Loadout()
|
||||||
|
{
|
||||||
|
Prototype = profLoadout.LoadoutName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadouts[role.RoleName] = loadout;
|
||||||
|
}
|
||||||
|
|
||||||
return new HumanoidCharacterProfile(
|
return new HumanoidCharacterProfile(
|
||||||
profile.CharacterName,
|
profile.CharacterName,
|
||||||
profile.FlavorText,
|
profile.FlavorText,
|
||||||
@@ -226,13 +248,12 @@ namespace Content.Server.Database
|
|||||||
Color.FromHex(profile.SkinColor),
|
Color.FromHex(profile.SkinColor),
|
||||||
markings
|
markings
|
||||||
),
|
),
|
||||||
clothing,
|
|
||||||
backpack,
|
|
||||||
spawnPriority,
|
spawnPriority,
|
||||||
jobs,
|
jobs,
|
||||||
(PreferenceUnavailableMode) profile.PreferenceUnavailable,
|
(PreferenceUnavailableMode) profile.PreferenceUnavailable,
|
||||||
antags.ToList(),
|
antags.ToList(),
|
||||||
traits.ToList()
|
traits.ToList(),
|
||||||
|
loadouts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,8 +280,6 @@ namespace Content.Server.Database
|
|||||||
profile.FacialHairColor = appearance.FacialHairColor.ToHex();
|
profile.FacialHairColor = appearance.FacialHairColor.ToHex();
|
||||||
profile.EyeColor = appearance.EyeColor.ToHex();
|
profile.EyeColor = appearance.EyeColor.ToHex();
|
||||||
profile.SkinColor = appearance.SkinColor.ToHex();
|
profile.SkinColor = appearance.SkinColor.ToHex();
|
||||||
profile.Clothing = humanoid.Clothing.ToString();
|
|
||||||
profile.Backpack = humanoid.Backpack.ToString();
|
|
||||||
profile.SpawnPriority = (int) humanoid.SpawnPriority;
|
profile.SpawnPriority = (int) humanoid.SpawnPriority;
|
||||||
profile.Markings = markings;
|
profile.Markings = markings;
|
||||||
profile.Slot = slot;
|
profile.Slot = slot;
|
||||||
@@ -285,6 +304,36 @@ namespace Content.Server.Database
|
|||||||
.Select(t => new Trait {TraitName = t})
|
.Select(t => new Trait {TraitName = t})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
profile.Loadouts.Clear();
|
||||||
|
|
||||||
|
foreach (var (role, loadouts) in humanoid.Loadouts)
|
||||||
|
{
|
||||||
|
var dz = new ProfileRoleLoadout()
|
||||||
|
{
|
||||||
|
RoleName = role,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (group, groupLoadouts) in loadouts.SelectedLoadouts)
|
||||||
|
{
|
||||||
|
var profileGroup = new ProfileLoadoutGroup()
|
||||||
|
{
|
||||||
|
GroupName = group,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var loadout in groupLoadouts)
|
||||||
|
{
|
||||||
|
profileGroup.Loadouts.Add(new ProfileLoadout()
|
||||||
|
{
|
||||||
|
LoadoutName = loadout.Prototype,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dz.Groups.Add(profileGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.Loadouts.Add(dz);
|
||||||
|
}
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -709,7 +709,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
_humanoid.LoadProfile(mob, profile);
|
_humanoid.LoadProfile(mob, profile);
|
||||||
|
|
||||||
var gear = _prototypeManager.Index(spawnDetails.GearProto);
|
var gear = _prototypeManager.Index(spawnDetails.GearProto);
|
||||||
_stationSpawning.EquipStartingGear(mob, gear, profile);
|
_stationSpawning.EquipStartingGear(mob, gear);
|
||||||
|
|
||||||
_npcFaction.RemoveFaction(mob, "NanoTrasen", false);
|
_npcFaction.RemoveFaction(mob, "NanoTrasen", false);
|
||||||
_npcFaction.AddFaction(mob, "Syndicate");
|
_npcFaction.AddFaction(mob, "Syndicate");
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
|||||||
|
|
||||||
_mindSystem.TransferTo(newMind, mob);
|
_mindSystem.TransferTo(newMind, mob);
|
||||||
var profile = _prefs.GetPreferences(session.UserId).SelectedCharacter as HumanoidCharacterProfile;
|
var profile = _prefs.GetPreferences(session.UserId).SelectedCharacter as HumanoidCharacterProfile;
|
||||||
_stationSpawningSystem.EquipStartingGear(mob, pirateGear, profile);
|
_stationSpawningSystem.EquipStartingGear(mob, pirateGear);
|
||||||
|
|
||||||
_npcFaction.RemoveFaction(mob, EnemyFactionId, false);
|
_npcFaction.RemoveFaction(mob, EnemyFactionId, false);
|
||||||
_npcFaction.AddFaction(mob, PirateFactionId);
|
_npcFaction.AddFaction(mob, PirateFactionId);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using Content.Server.Worldgen.Tools;
|
|||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Administration.Managers;
|
using Content.Shared.Administration.Managers;
|
||||||
using Content.Shared.Kitchen;
|
using Content.Shared.Kitchen;
|
||||||
|
using Content.Shared.Players.PlayTimeTracking;
|
||||||
|
|
||||||
namespace Content.Server.IoC
|
namespace Content.Server.IoC
|
||||||
{
|
{
|
||||||
@@ -58,6 +59,7 @@ namespace Content.Server.IoC
|
|||||||
IoCManager.Register<PoissonDiskSampler>();
|
IoCManager.Register<PoissonDiskSampler>();
|
||||||
IoCManager.Register<DiscordWebhook>();
|
IoCManager.Register<DiscordWebhook>();
|
||||||
IoCManager.Register<ServerDbEntryManager>();
|
IoCManager.Register<ServerDbEntryManager>();
|
||||||
|
IoCManager.Register<ISharedPlaytimeManager, PlayTimeTrackingManager>();
|
||||||
IoCManager.Register<ServerApi>();
|
IoCManager.Register<ServerApi>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public delegate void CalcPlayTimeTrackersCallback(ICommonSession player, HashSet
|
|||||||
/// Operations like refreshing and sending play time info to clients are deferred until the next frame (note: not tick).
|
/// Operations like refreshing and sending play time info to clients are deferred until the next frame (note: not tick).
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public sealed class PlayTimeTrackingManager
|
public sealed class PlayTimeTrackingManager : ISharedPlaytimeManager
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IServerDbManager _db = default!;
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
[Dependency] private readonly IServerNetManager _net = default!;
|
[Dependency] private readonly IServerNetManager _net = default!;
|
||||||
@@ -201,6 +201,11 @@ public sealed class PlayTimeTrackingManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, TimeSpan> GetPlayTimes(ICommonSession session)
|
||||||
|
{
|
||||||
|
return GetTrackerTimes(session);
|
||||||
|
}
|
||||||
|
|
||||||
private void SendPlayTimes(ICommonSession pSession)
|
private void SendPlayTimes(ICommonSession pSession)
|
||||||
{
|
{
|
||||||
var roles = GetTrackerTimes(pSession);
|
var roles = GetTrackerTimes(pSession);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Shared.CCVar;
|
|||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -25,6 +26,7 @@ namespace Content.Server.Preferences.Managers
|
|||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IServerDbManager _db = default!;
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _protos = default!;
|
[Dependency] private readonly IPrototypeManager _protos = default!;
|
||||||
|
|
||||||
// Cache player prefs on the server so we don't need as much async hell related to them.
|
// Cache player prefs on the server so we don't need as much async hell related to them.
|
||||||
@@ -98,8 +100,10 @@ namespace Content.Server.Preferences.Managers
|
|||||||
}
|
}
|
||||||
|
|
||||||
var curPrefs = prefsData.Prefs!;
|
var curPrefs = prefsData.Prefs!;
|
||||||
|
var session = _playerManager.GetSessionById(userId);
|
||||||
|
var collection = IoCManager.Instance!;
|
||||||
|
|
||||||
profile.EnsureValid(_cfg, _protos);
|
profile.EnsureValid(session, collection);
|
||||||
|
|
||||||
var profiles = new Dictionary<int, ICharacterProfile>(curPrefs.Characters)
|
var profiles = new Dictionary<int, ICharacterProfile>(curPrefs.Characters)
|
||||||
{
|
{
|
||||||
@@ -260,17 +264,20 @@ namespace Content.Server.Preferences.Managers
|
|||||||
return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random());
|
return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random());
|
||||||
}
|
}
|
||||||
|
|
||||||
return SanitizePreferences(prefs);
|
var session = _playerManager.GetSessionById(userId);
|
||||||
|
var collection = IoCManager.Instance!;
|
||||||
|
|
||||||
|
return SanitizePreferences(session, prefs, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerPreferences SanitizePreferences(PlayerPreferences prefs)
|
private PlayerPreferences SanitizePreferences(ICommonSession session, PlayerPreferences prefs, IDependencyCollection collection)
|
||||||
{
|
{
|
||||||
// Clean up preferences in case of changes to the game,
|
// Clean up preferences in case of changes to the game,
|
||||||
// such as removed jobs still being selected.
|
// such as removed jobs still being selected.
|
||||||
|
|
||||||
return new PlayerPreferences(prefs.Characters.Select(p =>
|
return new PlayerPreferences(prefs.Characters.Select(p =>
|
||||||
{
|
{
|
||||||
return new KeyValuePair<int, ICharacterProfile>(p.Key, p.Value.Validated(_cfg, _protos));
|
return new KeyValuePair<int, ICharacterProfile>(p.Key, p.Value.Validated(session, collection));
|
||||||
}), prefs.SelectedCharacterIndex, prefs.AdminOOCColor);
|
}), prefs.SelectedCharacterIndex, prefs.AdminOOCColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public sealed class SpawnPointSystem : EntitySystem
|
|||||||
// TODO: Refactor gameticker spawning code so we don't have to do this!
|
// TODO: Refactor gameticker spawning code so we don't have to do this!
|
||||||
var points2 = EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
|
var points2 = EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
|
||||||
|
|
||||||
if (points2.MoveNext(out var uid, out var spawnPoint, out var xform))
|
if (points2.MoveNext(out var spawnPoint, out var xform))
|
||||||
{
|
{
|
||||||
possiblePositions.Add(xform.Coordinates);
|
possiblePositions.Add(xform.Coordinates);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Server.Access.Systems;
|
using Content.Server.Access.Systems;
|
||||||
using Content.Server.DetailExaminable;
|
using Content.Server.DetailExaminable;
|
||||||
using Content.Server.Humanoid;
|
using Content.Server.Humanoid;
|
||||||
@@ -10,10 +11,12 @@ using Content.Server.Station.Components;
|
|||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
using Content.Shared.Random;
|
using Content.Shared.Random;
|
||||||
using Content.Shared.Random.Helpers;
|
using Content.Shared.Random.Helpers;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
@@ -86,7 +89,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||||||
|
|
||||||
if (station != null && profile != null)
|
if (station != null && profile != null)
|
||||||
{
|
{
|
||||||
/// Try to call the character's preferred spawner first.
|
// Try to call the character's preferred spawner first.
|
||||||
if (_spawnerCallbacks.TryGetValue(profile.SpawnPriority, out var preferredSpawner))
|
if (_spawnerCallbacks.TryGetValue(profile.SpawnPriority, out var preferredSpawner))
|
||||||
{
|
{
|
||||||
preferredSpawner(ev);
|
preferredSpawner(ev);
|
||||||
@@ -101,11 +104,13 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/// Call all of them in the typical order.
|
// Call all of them in the typical order.
|
||||||
foreach (var typicalSpawner in _spawnerCallbacks.Values)
|
foreach (var typicalSpawner in _spawnerCallbacks.Values)
|
||||||
|
{
|
||||||
typicalSpawner(ev);
|
typicalSpawner(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RaiseLocalEvent(ev);
|
RaiseLocalEvent(ev);
|
||||||
|
|
||||||
@@ -134,7 +139,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||||||
EntityUid? station,
|
EntityUid? station,
|
||||||
EntityUid? entity = null)
|
EntityUid? entity = null)
|
||||||
{
|
{
|
||||||
_prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out JobPrototype? prototype);
|
_prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out var prototype);
|
||||||
|
|
||||||
// If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
|
// If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
|
||||||
if (prototype?.JobEntity != null)
|
if (prototype?.JobEntity != null)
|
||||||
@@ -176,11 +181,38 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||||||
if (prototype?.StartingGear != null)
|
if (prototype?.StartingGear != null)
|
||||||
{
|
{
|
||||||
var startingGear = _prototypeManager.Index<StartingGearPrototype>(prototype.StartingGear);
|
var startingGear = _prototypeManager.Index<StartingGearPrototype>(prototype.StartingGear);
|
||||||
EquipStartingGear(entity.Value, startingGear, profile);
|
EquipStartingGear(entity.Value, startingGear);
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
EquipIdCard(entity.Value, profile.Name, prototype, station);
|
EquipIdCard(entity.Value, profile.Name, prototype, station);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run loadouts after so stuff like storage loadouts can get
|
||||||
|
var jobLoadout = LoadoutSystem.GetJobPrototype(prototype?.ID);
|
||||||
|
|
||||||
|
if (_prototypeManager.TryIndex(jobLoadout, out RoleLoadoutPrototype? loadoutProto))
|
||||||
|
{
|
||||||
|
RoleLoadout? loadout = null;
|
||||||
|
profile?.Loadouts.TryGetValue(jobLoadout, out loadout);
|
||||||
|
|
||||||
|
// Set to default if not present
|
||||||
|
if (loadout == null)
|
||||||
|
{
|
||||||
|
loadout = new RoleLoadout(jobLoadout);
|
||||||
|
loadout.SetDefault(_prototypeManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order loadout selections by the order they appear on the prototype.
|
||||||
|
foreach (var group in loadout.SelectedLoadouts.OrderBy(x => loadoutProto.Groups.FindIndex(e => e == x.Key)))
|
||||||
|
{
|
||||||
|
foreach (var items in group.Value)
|
||||||
|
{
|
||||||
|
// Handle any extra data here.
|
||||||
|
var startingGear = _prototypeManager.Index<StartingGearPrototype>(items.Prototype);
|
||||||
|
EquipStartingGear(entity.Value, startingGear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
{
|
{
|
||||||
_humanoidSystem.LoadProfile(entity.Value, profile);
|
_humanoidSystem.LoadProfile(entity.Value, profile);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Shared.Clothing.Components;
|
using Content.Shared.Clothing.Components;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Station;
|
using Content.Shared.Station;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -24,12 +26,94 @@ public sealed class LoadoutSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<LoadoutComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<LoadoutComponent, MapInitEvent>(OnMapInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetJobPrototype(string? loadout)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(loadout))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return "Job" + loadout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the first entity prototype for operations such as sprite drawing.
|
||||||
|
/// </summary>
|
||||||
|
public EntProtoId? GetFirstOrNull(LoadoutPrototype loadout)
|
||||||
|
{
|
||||||
|
if (!_protoMan.TryIndex(loadout.Equipment, out var gear))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var count = gear.Equipment.Count + gear.Inhand.Count + gear.Storage.Values.Sum(x => x.Count);
|
||||||
|
|
||||||
|
if (count == 1)
|
||||||
|
{
|
||||||
|
if (gear.Equipment.Count == 1 && _protoMan.TryIndex<EntityPrototype>(gear.Equipment.Values.First(), out var proto))
|
||||||
|
{
|
||||||
|
return proto.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gear.Inhand.Count == 1 && _protoMan.TryIndex<EntityPrototype>(gear.Inhand[0], out proto))
|
||||||
|
{
|
||||||
|
return proto.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage moment
|
||||||
|
foreach (var ents in gear.Storage.Values)
|
||||||
|
{
|
||||||
|
foreach (var ent in ents)
|
||||||
|
{
|
||||||
|
return ent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the name of a loadout.
|
||||||
|
/// </summary>
|
||||||
|
public string GetName(LoadoutPrototype loadout)
|
||||||
|
{
|
||||||
|
if (!_protoMan.TryIndex(loadout.Equipment, out var gear))
|
||||||
|
return Loc.GetString("loadout-unknown");
|
||||||
|
|
||||||
|
var count = gear.Equipment.Count + gear.Storage.Values.Sum(o => o.Count) + gear.Inhand.Count;
|
||||||
|
|
||||||
|
if (count == 1)
|
||||||
|
{
|
||||||
|
if (gear.Equipment.Count == 1 && _protoMan.TryIndex<EntityPrototype>(gear.Equipment.Values.First(), out var proto))
|
||||||
|
{
|
||||||
|
return proto.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gear.Inhand.Count == 1 && _protoMan.TryIndex<EntityPrototype>(gear.Inhand[0], out proto))
|
||||||
|
{
|
||||||
|
return proto.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var values in gear.Storage.Values)
|
||||||
|
{
|
||||||
|
if (values.Count != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_protoMan.TryIndex<EntityPrototype>(values[0], out proto))
|
||||||
|
{
|
||||||
|
return proto.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Loc.GetString($"loadout-{loadout.ID}");
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
if (component.Prototypes == null)
|
if (component.Prototypes == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var proto = _protoMan.Index<StartingGearPrototype>(_random.Pick(component.Prototypes));
|
var proto = _protoMan.Index<StartingGearPrototype>(_random.Pick(component.Prototypes));
|
||||||
_station.EquipStartingGear(uid, proto, null);
|
_station.EquipStartingGear(uid, proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ public sealed partial class SpeciesPrototype : IPrototype
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Humanoid species variant used by this entity.
|
/// Humanoid species variant used by this entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[DataField(required: true)]
|
||||||
public string Prototype { get; private set; } = default!;
|
public EntProtoId Prototype { get; private set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prototype used by the species for the dress-up doll in various menus.
|
/// Prototype used by the species for the dress-up doll in various menus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[DataField(required: true)]
|
||||||
public string DollPrototype { get; private set; } = default!;
|
public EntProtoId DollPrototype { get; private set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method of skin coloration used by the species.
|
/// Method of skin coloration used by the species.
|
||||||
@@ -120,12 +120,6 @@ public sealed partial class SpeciesPrototype : IPrototype
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public int MaxAge = 120;
|
public int MaxAge = 120;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Style used for the guidebook info link in the character profile editor
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public string GuideBookIcon = "SpeciesInfoDefault";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SpeciesNaming : byte
|
public enum SpeciesNaming : byte
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Shared.Players.PlayTimeTracking;
|
||||||
|
|
||||||
|
public interface ISharedPlaytimeManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the playtimes for the session or an empty dictionary if none found.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyDictionary<string, TimeSpan> GetPlayTimes(ICommonSession session);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Content.Shared.Preferences
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The backpack preference for a profile. Stored in database!
|
|
||||||
/// </summary>
|
|
||||||
public enum BackpackPreference
|
|
||||||
{
|
|
||||||
Backpack,
|
|
||||||
Satchel,
|
|
||||||
Duffelbag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
namespace Content.Shared.Preferences
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The clothing preference for a profile. Stored in database!
|
|
||||||
/// </summary>
|
|
||||||
public enum ClothingPreference
|
|
||||||
{
|
|
||||||
Jumpsuit,
|
|
||||||
Jumpskirt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Humanoid.Prototypes;
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
using Content.Shared.Random.Helpers;
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Traits;
|
using Content.Shared.Traits;
|
||||||
|
using Robust.Shared.Collections;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
@@ -31,6 +33,11 @@ namespace Content.Shared.Preferences
|
|||||||
private readonly List<string> _antagPreferences;
|
private readonly List<string> _antagPreferences;
|
||||||
private readonly List<string> _traitPreferences;
|
private readonly List<string> _traitPreferences;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, RoleLoadout> Loadouts => _loadouts;
|
||||||
|
|
||||||
|
private Dictionary<string, RoleLoadout> _loadouts;
|
||||||
|
|
||||||
|
// What in the lord is happening here.
|
||||||
private HumanoidCharacterProfile(
|
private HumanoidCharacterProfile(
|
||||||
string name,
|
string name,
|
||||||
string flavortext,
|
string flavortext,
|
||||||
@@ -39,13 +46,12 @@ namespace Content.Shared.Preferences
|
|||||||
Sex sex,
|
Sex sex,
|
||||||
Gender gender,
|
Gender gender,
|
||||||
HumanoidCharacterAppearance appearance,
|
HumanoidCharacterAppearance appearance,
|
||||||
ClothingPreference clothing,
|
|
||||||
BackpackPreference backpack,
|
|
||||||
SpawnPriorityPreference spawnPriority,
|
SpawnPriorityPreference spawnPriority,
|
||||||
Dictionary<string, JobPriority> jobPriorities,
|
Dictionary<string, JobPriority> jobPriorities,
|
||||||
PreferenceUnavailableMode preferenceUnavailable,
|
PreferenceUnavailableMode preferenceUnavailable,
|
||||||
List<string> antagPreferences,
|
List<string> antagPreferences,
|
||||||
List<string> traitPreferences)
|
List<string> traitPreferences,
|
||||||
|
Dictionary<string, RoleLoadout> loadouts)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
FlavorText = flavortext;
|
FlavorText = flavortext;
|
||||||
@@ -54,13 +60,12 @@ namespace Content.Shared.Preferences
|
|||||||
Sex = sex;
|
Sex = sex;
|
||||||
Gender = gender;
|
Gender = gender;
|
||||||
Appearance = appearance;
|
Appearance = appearance;
|
||||||
Clothing = clothing;
|
|
||||||
Backpack = backpack;
|
|
||||||
SpawnPriority = spawnPriority;
|
SpawnPriority = spawnPriority;
|
||||||
_jobPriorities = jobPriorities;
|
_jobPriorities = jobPriorities;
|
||||||
PreferenceUnavailable = preferenceUnavailable;
|
PreferenceUnavailable = preferenceUnavailable;
|
||||||
_antagPreferences = antagPreferences;
|
_antagPreferences = antagPreferences;
|
||||||
_traitPreferences = traitPreferences;
|
_traitPreferences = traitPreferences;
|
||||||
|
_loadouts = loadouts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Copy constructor but with overridable references (to prevent useless copies)</summary>
|
/// <summary>Copy constructor but with overridable references (to prevent useless copies)</summary>
|
||||||
@@ -68,15 +73,16 @@ namespace Content.Shared.Preferences
|
|||||||
HumanoidCharacterProfile other,
|
HumanoidCharacterProfile other,
|
||||||
Dictionary<string, JobPriority> jobPriorities,
|
Dictionary<string, JobPriority> jobPriorities,
|
||||||
List<string> antagPreferences,
|
List<string> antagPreferences,
|
||||||
List<string> traitPreferences)
|
List<string> traitPreferences,
|
||||||
: this(other.Name, other.FlavorText, other.Species, other.Age, other.Sex, other.Gender, other.Appearance, other.Clothing, other.Backpack, other.SpawnPriority,
|
Dictionary<string, RoleLoadout> loadouts)
|
||||||
jobPriorities, other.PreferenceUnavailable, antagPreferences, traitPreferences)
|
: this(other.Name, other.FlavorText, other.Species, other.Age, other.Sex, other.Gender, other.Appearance, other.SpawnPriority,
|
||||||
|
jobPriorities, other.PreferenceUnavailable, antagPreferences, traitPreferences, loadouts)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Copy constructor</summary>
|
/// <summary>Copy constructor</summary>
|
||||||
private HumanoidCharacterProfile(HumanoidCharacterProfile other)
|
private HumanoidCharacterProfile(HumanoidCharacterProfile other)
|
||||||
: this(other, new Dictionary<string, JobPriority>(other.JobPriorities), new List<string>(other.AntagPreferences), new List<string>(other.TraitPreferences))
|
: this(other, new Dictionary<string, JobPriority>(other.JobPriorities), new List<string>(other.AntagPreferences), new List<string>(other.TraitPreferences), new Dictionary<string, RoleLoadout>(other.Loadouts))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +94,14 @@ namespace Content.Shared.Preferences
|
|||||||
Sex sex,
|
Sex sex,
|
||||||
Gender gender,
|
Gender gender,
|
||||||
HumanoidCharacterAppearance appearance,
|
HumanoidCharacterAppearance appearance,
|
||||||
ClothingPreference clothing,
|
|
||||||
BackpackPreference backpack,
|
|
||||||
SpawnPriorityPreference spawnPriority,
|
SpawnPriorityPreference spawnPriority,
|
||||||
IReadOnlyDictionary<string, JobPriority> jobPriorities,
|
IReadOnlyDictionary<string, JobPriority> jobPriorities,
|
||||||
PreferenceUnavailableMode preferenceUnavailable,
|
PreferenceUnavailableMode preferenceUnavailable,
|
||||||
IReadOnlyList<string> antagPreferences,
|
IReadOnlyList<string> antagPreferences,
|
||||||
IReadOnlyList<string> traitPreferences)
|
IReadOnlyList<string> traitPreferences,
|
||||||
: this(name, flavortext, species, age, sex, gender, appearance, clothing, backpack, spawnPriority, new Dictionary<string, JobPriority>(jobPriorities),
|
Dictionary<string, RoleLoadout> loadouts)
|
||||||
preferenceUnavailable, new List<string>(antagPreferences), new List<string>(traitPreferences))
|
: this(name, flavortext, species, age, sex, gender, appearance, spawnPriority, new Dictionary<string, JobPriority>(jobPriorities),
|
||||||
|
preferenceUnavailable, new List<string>(antagPreferences), new List<string>(traitPreferences), new Dictionary<string, RoleLoadout>(loadouts))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +118,6 @@ namespace Content.Shared.Preferences
|
|||||||
Sex.Male,
|
Sex.Male,
|
||||||
Gender.Male,
|
Gender.Male,
|
||||||
new HumanoidCharacterAppearance(),
|
new HumanoidCharacterAppearance(),
|
||||||
ClothingPreference.Jumpsuit,
|
|
||||||
BackpackPreference.Backpack,
|
|
||||||
SpawnPriorityPreference.None,
|
SpawnPriorityPreference.None,
|
||||||
new Dictionary<string, JobPriority>
|
new Dictionary<string, JobPriority>
|
||||||
{
|
{
|
||||||
@@ -122,7 +125,8 @@ namespace Content.Shared.Preferences
|
|||||||
},
|
},
|
||||||
PreferenceUnavailableMode.SpawnAsOverflow,
|
PreferenceUnavailableMode.SpawnAsOverflow,
|
||||||
new List<string>(),
|
new List<string>(),
|
||||||
new List<string>())
|
new List<string>(),
|
||||||
|
new Dictionary<string, RoleLoadout>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,8 +145,6 @@ namespace Content.Shared.Preferences
|
|||||||
Sex.Male,
|
Sex.Male,
|
||||||
Gender.Male,
|
Gender.Male,
|
||||||
HumanoidCharacterAppearance.DefaultWithSpecies(species),
|
HumanoidCharacterAppearance.DefaultWithSpecies(species),
|
||||||
ClothingPreference.Jumpsuit,
|
|
||||||
BackpackPreference.Backpack,
|
|
||||||
SpawnPriorityPreference.None,
|
SpawnPriorityPreference.None,
|
||||||
new Dictionary<string, JobPriority>
|
new Dictionary<string, JobPriority>
|
||||||
{
|
{
|
||||||
@@ -150,7 +152,8 @@ namespace Content.Shared.Preferences
|
|||||||
},
|
},
|
||||||
PreferenceUnavailableMode.SpawnAsOverflow,
|
PreferenceUnavailableMode.SpawnAsOverflow,
|
||||||
new List<string>(),
|
new List<string>(),
|
||||||
new List<string>());
|
new List<string>(),
|
||||||
|
new Dictionary<string, RoleLoadout>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This should eventually not be a visual change only.
|
// TODO: This should eventually not be a visual change only.
|
||||||
@@ -195,11 +198,11 @@ namespace Content.Shared.Preferences
|
|||||||
|
|
||||||
var name = GetName(species, gender);
|
var name = GetName(species, gender);
|
||||||
|
|
||||||
return new HumanoidCharacterProfile(name, "", species, age, sex, gender, HumanoidCharacterAppearance.Random(species, sex), ClothingPreference.Jumpsuit, BackpackPreference.Backpack, SpawnPriorityPreference.None,
|
return new HumanoidCharacterProfile(name, "", species, age, sex, gender, HumanoidCharacterAppearance.Random(species, sex), SpawnPriorityPreference.None,
|
||||||
new Dictionary<string, JobPriority>
|
new Dictionary<string, JobPriority>
|
||||||
{
|
{
|
||||||
{SharedGameTicker.FallbackOverflowJob, JobPriority.High},
|
{SharedGameTicker.FallbackOverflowJob, JobPriority.High},
|
||||||
}, PreferenceUnavailableMode.StayInLobby, new List<string>(), new List<string>());
|
}, PreferenceUnavailableMode.StayInLobby, new List<string>(), new List<string>(), new Dictionary<string, RoleLoadout>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
@@ -219,8 +222,6 @@ namespace Content.Shared.Preferences
|
|||||||
|
|
||||||
[DataField("appearance")]
|
[DataField("appearance")]
|
||||||
public HumanoidCharacterAppearance Appearance { get; private set; }
|
public HumanoidCharacterAppearance Appearance { get; private set; }
|
||||||
public ClothingPreference Clothing { get; private set; }
|
|
||||||
public BackpackPreference Backpack { get; private set; }
|
|
||||||
public SpawnPriorityPreference SpawnPriority { get; private set; }
|
public SpawnPriorityPreference SpawnPriority { get; private set; }
|
||||||
public IReadOnlyDictionary<string, JobPriority> JobPriorities => _jobPriorities;
|
public IReadOnlyDictionary<string, JobPriority> JobPriorities => _jobPriorities;
|
||||||
public IReadOnlyList<string> AntagPreferences => _antagPreferences;
|
public IReadOnlyList<string> AntagPreferences => _antagPreferences;
|
||||||
@@ -263,21 +264,14 @@ namespace Content.Shared.Preferences
|
|||||||
return new(this) { Appearance = appearance };
|
return new(this) { Appearance = appearance };
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithClothingPreference(ClothingPreference clothing)
|
|
||||||
{
|
|
||||||
return new(this) { Clothing = clothing };
|
|
||||||
}
|
|
||||||
public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack)
|
|
||||||
{
|
|
||||||
return new(this) { Backpack = backpack };
|
|
||||||
}
|
|
||||||
public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority)
|
public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority)
|
||||||
{
|
{
|
||||||
return new(this) { SpawnPriority = spawnPriority };
|
return new(this) { SpawnPriority = spawnPriority };
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities)
|
public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities)
|
||||||
{
|
{
|
||||||
return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences, _traitPreferences);
|
return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences, _traitPreferences, _loadouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithJobPriority(string jobId, JobPriority priority)
|
public HumanoidCharacterProfile WithJobPriority(string jobId, JobPriority priority)
|
||||||
@@ -291,7 +285,7 @@ namespace Content.Shared.Preferences
|
|||||||
{
|
{
|
||||||
dictionary[jobId] = priority;
|
dictionary[jobId] = priority;
|
||||||
}
|
}
|
||||||
return new(this, dictionary, _antagPreferences, _traitPreferences);
|
return new(this, dictionary, _antagPreferences, _traitPreferences, _loadouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithPreferenceUnavailable(PreferenceUnavailableMode mode)
|
public HumanoidCharacterProfile WithPreferenceUnavailable(PreferenceUnavailableMode mode)
|
||||||
@@ -301,7 +295,7 @@ namespace Content.Shared.Preferences
|
|||||||
|
|
||||||
public HumanoidCharacterProfile WithAntagPreferences(IEnumerable<string> antagPreferences)
|
public HumanoidCharacterProfile WithAntagPreferences(IEnumerable<string> antagPreferences)
|
||||||
{
|
{
|
||||||
return new(this, _jobPriorities, new List<string>(antagPreferences), _traitPreferences);
|
return new(this, _jobPriorities, new List<string>(antagPreferences), _traitPreferences, _loadouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithAntagPreference(string antagId, bool pref)
|
public HumanoidCharacterProfile WithAntagPreference(string antagId, bool pref)
|
||||||
@@ -321,7 +315,7 @@ namespace Content.Shared.Preferences
|
|||||||
list.Remove(antagId);
|
list.Remove(antagId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(this, _jobPriorities, list, _traitPreferences);
|
return new(this, _jobPriorities, list, _traitPreferences, _loadouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HumanoidCharacterProfile WithTraitPreference(string traitId, bool pref)
|
public HumanoidCharacterProfile WithTraitPreference(string traitId, bool pref)
|
||||||
@@ -343,7 +337,7 @@ namespace Content.Shared.Preferences
|
|||||||
list.Remove(traitId);
|
list.Remove(traitId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(this, _jobPriorities, _antagPreferences, list);
|
return new(this, _jobPriorities, _antagPreferences, list, _loadouts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Summary =>
|
public string Summary =>
|
||||||
@@ -362,17 +356,19 @@ namespace Content.Shared.Preferences
|
|||||||
if (Sex != other.Sex) return false;
|
if (Sex != other.Sex) return false;
|
||||||
if (Gender != other.Gender) return false;
|
if (Gender != other.Gender) return false;
|
||||||
if (PreferenceUnavailable != other.PreferenceUnavailable) return false;
|
if (PreferenceUnavailable != other.PreferenceUnavailable) return false;
|
||||||
if (Clothing != other.Clothing) return false;
|
|
||||||
if (Backpack != other.Backpack) return false;
|
|
||||||
if (SpawnPriority != other.SpawnPriority) return false;
|
if (SpawnPriority != other.SpawnPriority) return false;
|
||||||
if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false;
|
if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false;
|
||||||
if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false;
|
if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false;
|
||||||
if (!_traitPreferences.SequenceEqual(other._traitPreferences)) return false;
|
if (!_traitPreferences.SequenceEqual(other._traitPreferences)) return false;
|
||||||
|
if (!Loadouts.SequenceEqual(other.Loadouts)) return false;
|
||||||
return Appearance.MemberwiseEquals(other.Appearance);
|
return Appearance.MemberwiseEquals(other.Appearance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager)
|
public void EnsureValid(ICommonSession session, IDependencyCollection collection)
|
||||||
{
|
{
|
||||||
|
var configManager = collection.Resolve<IConfigurationManager>();
|
||||||
|
var prototypeManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
if (!prototypeManager.TryIndex<SpeciesPrototype>(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false)
|
if (!prototypeManager.TryIndex<SpeciesPrototype>(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false)
|
||||||
{
|
{
|
||||||
Species = SharedHumanoidAppearanceSystem.DefaultSpecies;
|
Species = SharedHumanoidAppearanceSystem.DefaultSpecies;
|
||||||
@@ -455,21 +451,6 @@ namespace Content.Shared.Preferences
|
|||||||
_ => PreferenceUnavailableMode.StayInLobby // Invalid enum values.
|
_ => PreferenceUnavailableMode.StayInLobby // Invalid enum values.
|
||||||
};
|
};
|
||||||
|
|
||||||
var clothing = Clothing switch
|
|
||||||
{
|
|
||||||
ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit,
|
|
||||||
ClothingPreference.Jumpskirt => ClothingPreference.Jumpskirt,
|
|
||||||
_ => ClothingPreference.Jumpsuit // Invalid enum values.
|
|
||||||
};
|
|
||||||
|
|
||||||
var backpack = Backpack switch
|
|
||||||
{
|
|
||||||
BackpackPreference.Backpack => BackpackPreference.Backpack,
|
|
||||||
BackpackPreference.Satchel => BackpackPreference.Satchel,
|
|
||||||
BackpackPreference.Duffelbag => BackpackPreference.Duffelbag,
|
|
||||||
_ => BackpackPreference.Backpack // Invalid enum values.
|
|
||||||
};
|
|
||||||
|
|
||||||
var spawnPriority = SpawnPriority switch
|
var spawnPriority = SpawnPriority switch
|
||||||
{
|
{
|
||||||
SpawnPriorityPreference.None => SpawnPriorityPreference.None,
|
SpawnPriorityPreference.None => SpawnPriorityPreference.None,
|
||||||
@@ -502,8 +483,6 @@ namespace Content.Shared.Preferences
|
|||||||
Sex = sex;
|
Sex = sex;
|
||||||
Gender = gender;
|
Gender = gender;
|
||||||
Appearance = appearance;
|
Appearance = appearance;
|
||||||
Clothing = clothing;
|
|
||||||
Backpack = backpack;
|
|
||||||
SpawnPriority = spawnPriority;
|
SpawnPriority = spawnPriority;
|
||||||
|
|
||||||
_jobPriorities.Clear();
|
_jobPriorities.Clear();
|
||||||
@@ -520,12 +499,31 @@ namespace Content.Shared.Preferences
|
|||||||
|
|
||||||
_traitPreferences.Clear();
|
_traitPreferences.Clear();
|
||||||
_traitPreferences.AddRange(traits);
|
_traitPreferences.AddRange(traits);
|
||||||
|
|
||||||
|
// Checks prototypes exist for all loadouts and dump / set to default if not.
|
||||||
|
var toRemove = new ValueList<string>();
|
||||||
|
|
||||||
|
foreach (var (roleName, loadouts) in _loadouts)
|
||||||
|
{
|
||||||
|
if (!prototypeManager.HasIndex<RoleLoadoutPrototype>(roleName))
|
||||||
|
{
|
||||||
|
toRemove.Add(roleName);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager)
|
loadouts.EnsureValid(session, collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var value in toRemove)
|
||||||
|
{
|
||||||
|
_loadouts.Remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICharacterProfile Validated(ICommonSession session, IDependencyCollection collection)
|
||||||
{
|
{
|
||||||
var profile = new HumanoidCharacterProfile(this);
|
var profile = new HumanoidCharacterProfile(this);
|
||||||
profile.EnsureValid(configManager, prototypeManager);
|
profile.EnsureValid(session, collection);
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,16 +549,32 @@ namespace Content.Shared.Preferences
|
|||||||
Age,
|
Age,
|
||||||
Sex,
|
Sex,
|
||||||
Gender,
|
Gender,
|
||||||
Appearance,
|
Appearance
|
||||||
Clothing,
|
|
||||||
Backpack
|
|
||||||
),
|
),
|
||||||
SpawnPriority,
|
SpawnPriority,
|
||||||
PreferenceUnavailable,
|
PreferenceUnavailable,
|
||||||
_jobPriorities,
|
_jobPriorities,
|
||||||
_antagPreferences,
|
_antagPreferences,
|
||||||
_traitPreferences
|
_traitPreferences,
|
||||||
|
_loadouts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetLoadout(RoleLoadout loadout)
|
||||||
|
{
|
||||||
|
_loadouts[loadout.Role.Id] = loadout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleLoadout GetLoadoutOrDefault(string id, IEntityManager entManager, IPrototypeManager protoManager)
|
||||||
|
{
|
||||||
|
if (!_loadouts.TryGetValue(id, out var loadout))
|
||||||
|
{
|
||||||
|
loadout = new RoleLoadout(id);
|
||||||
|
loadout.SetDefault(protoManager, force: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadout.SetDefault(protoManager);
|
||||||
|
return loadout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.Preferences
|
namespace Content.Shared.Preferences
|
||||||
@@ -15,11 +16,11 @@ namespace Content.Shared.Preferences
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Makes this profile valid so there's no bad data like negative ages.
|
/// Makes this profile valid so there's no bad data like negative ages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager);
|
void EnsureValid(ICommonSession session, IDependencyCollection collection);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a copy of this profile that has <see cref="EnsureValid"/> applied, i.e. no invalid data.
|
/// Gets a copy of this profile that has <see cref="EnsureValid"/> applied, i.e. no invalid data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager);
|
ICharacterProfile Validated(ICommonSession session, IDependencyCollection collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uses a <see cref="LoadoutEffectGroupPrototype"/> prototype as a singular effect that can be re-used.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class GroupLoadoutEffect : LoadoutEffect
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public ProtoId<LoadoutEffectGroupPrototype> Proto;
|
||||||
|
|
||||||
|
public override bool Validate(RoleLoadout loadout, ICommonSession session, IDependencyCollection collection, [NotNullWhen(false)] out FormattedMessage? reason)
|
||||||
|
{
|
||||||
|
var effectsProto = collection.Resolve<IPrototypeManager>().Index(Proto);
|
||||||
|
|
||||||
|
foreach (var effect in effectsProto.Effects)
|
||||||
|
{
|
||||||
|
if (!effect.Validate(loadout, session, collection, out reason))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
reason = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Shared.Players.PlayTimeTracking;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for a job requirement to be met such as playtime.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class JobRequirementLoadoutEffect : LoadoutEffect
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public JobRequirement Requirement = default!;
|
||||||
|
|
||||||
|
public override bool Validate(RoleLoadout loadout, ICommonSession session, IDependencyCollection collection, [NotNullWhen(false)] out FormattedMessage? reason)
|
||||||
|
{
|
||||||
|
var manager = collection.Resolve<ISharedPlaytimeManager>();
|
||||||
|
var playtimes = manager.GetPlayTimes(session);
|
||||||
|
return JobRequirements.TryRequirementMet(Requirement, playtimes, out reason,
|
||||||
|
collection.Resolve<IEntityManager>(),
|
||||||
|
collection.Resolve<IPrototypeManager>());
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Content.Shared/Preferences/Loadouts/Effects/LoadoutEffect.cs
Normal file
20
Content.Shared/Preferences/Loadouts/Effects/LoadoutEffect.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
|
||||||
|
[ImplicitDataDefinitionForInheritors]
|
||||||
|
public abstract partial class LoadoutEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to validate the effect.
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool Validate(
|
||||||
|
RoleLoadout loadout,
|
||||||
|
ICommonSession session,
|
||||||
|
IDependencyCollection collection,
|
||||||
|
[NotNullWhen(false)] out FormattedMessage? reason);
|
||||||
|
|
||||||
|
public virtual void Apply(RoleLoadout loadout) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores a group of loadout effects in a prototype for re-use.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
public sealed class LoadoutEffectGroupPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public List<LoadoutEffect> Effects = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
|
||||||
|
public sealed partial class PointsCostLoadoutEffect : LoadoutEffect
|
||||||
|
{
|
||||||
|
[DataField(required: true)]
|
||||||
|
public int Cost = 1;
|
||||||
|
|
||||||
|
public override bool Validate(
|
||||||
|
RoleLoadout loadout,
|
||||||
|
ICommonSession session,
|
||||||
|
IDependencyCollection collection,
|
||||||
|
[NotNullWhen(false)] out FormattedMessage? reason)
|
||||||
|
{
|
||||||
|
reason = null;
|
||||||
|
var protoManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(loadout.Role, out var roleProto) || roleProto.Points == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadout.Points <= Cost)
|
||||||
|
{
|
||||||
|
reason = FormattedMessage.FromUnformatted("loadout-group-points-insufficient");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Apply(RoleLoadout loadout)
|
||||||
|
{
|
||||||
|
loadout.Points -= Cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Content.Shared/Preferences/Loadouts/Loadout.cs
Normal file
13
Content.Shared/Preferences/Loadouts/Loadout.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the selected prototype and custom data for a loadout.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class Loadout
|
||||||
|
{
|
||||||
|
public ProtoId<LoadoutPrototype> Prototype;
|
||||||
|
}
|
||||||
34
Content.Shared/Preferences/Loadouts/LoadoutGroupPrototype.cs
Normal file
34
Content.Shared/Preferences/Loadouts/LoadoutGroupPrototype.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to a set of loadouts for a particular slot.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype("loadoutGroup")]
|
||||||
|
public sealed class LoadoutGroupPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User-friendly name for the group.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public LocId Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum number of loadouts that need to be specified for this category.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public int MinLimit = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum limit for the category.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public int MaxLimit = 1;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public List<ProtoId<LoadoutPrototype>> Loadouts = new();
|
||||||
|
}
|
||||||
25
Content.Shared/Preferences/Loadouts/LoadoutPrototype.cs
Normal file
25
Content.Shared/Preferences/Loadouts/LoadoutPrototype.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Content.Shared.Preferences.Loadouts.Effects;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Individual loadout item to be applied.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
public sealed class LoadoutPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
[DataField(required: true)]
|
||||||
|
public ProtoId<StartingGearPrototype> Equipment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effects to be applied when the loadout is applied.
|
||||||
|
/// These can also return true or false for validation purposes.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public List<LoadoutEffect> Effects = new();
|
||||||
|
}
|
||||||
248
Content.Shared/Preferences/Loadouts/RoleLoadout.cs
Normal file
248
Content.Shared/Preferences/Loadouts/RoleLoadout.cs
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Shared.Random;
|
||||||
|
using Robust.Shared.Collections;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains all of the selected data for a role's loadout.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class RoleLoadout
|
||||||
|
{
|
||||||
|
public readonly ProtoId<RoleLoadoutPrototype> Role;
|
||||||
|
|
||||||
|
public Dictionary<ProtoId<LoadoutGroupPrototype>, List<Loadout>> SelectedLoadouts = new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loadout-specific data used for validation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int? Points;
|
||||||
|
|
||||||
|
public RoleLoadout(ProtoId<RoleLoadoutPrototype> role)
|
||||||
|
{
|
||||||
|
Role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures all prototypes exist and effects can be applied.
|
||||||
|
/// </summary>
|
||||||
|
public void EnsureValid(ICommonSession session, IDependencyCollection collection)
|
||||||
|
{
|
||||||
|
var groupRemove = new ValueList<string>();
|
||||||
|
var protoManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(Role, out var roleProto))
|
||||||
|
{
|
||||||
|
SelectedLoadouts.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset points to recalculate.
|
||||||
|
Points = roleProto.Points;
|
||||||
|
|
||||||
|
foreach (var (group, groupLoadouts) in SelectedLoadouts)
|
||||||
|
{
|
||||||
|
// Dump if Group doesn't exist
|
||||||
|
if (!protoManager.TryIndex(group, out var groupProto))
|
||||||
|
{
|
||||||
|
groupRemove.Add(group);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadouts = groupLoadouts[..Math.Min(groupLoadouts.Count, groupProto.MaxLimit)];
|
||||||
|
|
||||||
|
// Validate first
|
||||||
|
for (var i = loadouts.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var loadout = loadouts[i];
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(loadout.Prototype, out var loadoutProto))
|
||||||
|
{
|
||||||
|
loadouts.RemoveAt(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the loadout can be applied (e.g. points).
|
||||||
|
if (!IsValid(session, loadout.Prototype, collection, out _))
|
||||||
|
{
|
||||||
|
loadouts.RemoveAt(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Apply(loadoutProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply defaults if required
|
||||||
|
// Technically it's possible for someone to game themselves into loadouts they shouldn't have
|
||||||
|
// If you put invalid ones first but that's your fault for not using sensible defaults
|
||||||
|
if (loadouts.Count < groupProto.MinLimit)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Math.Min(groupProto.MinLimit, groupProto.Loadouts.Count); i++)
|
||||||
|
{
|
||||||
|
if (!protoManager.TryIndex(groupProto.Loadouts[i], out var loadoutProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var defaultLoadout = new Loadout()
|
||||||
|
{
|
||||||
|
Prototype = loadoutProto.ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loadouts.Contains(defaultLoadout))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Still need to apply the effects even if validation is ignored.
|
||||||
|
loadouts.Add(defaultLoadout);
|
||||||
|
Apply(loadoutProto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedLoadouts[group] = loadouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var value in groupRemove)
|
||||||
|
{
|
||||||
|
SelectedLoadouts.Remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Apply(LoadoutPrototype loadoutProto)
|
||||||
|
{
|
||||||
|
foreach (var effect in loadoutProto.Effects)
|
||||||
|
{
|
||||||
|
effect.Apply(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the selected loadouts to default if no data is present.
|
||||||
|
/// </summary>
|
||||||
|
public void SetDefault(IPrototypeManager protoManager, bool force = false)
|
||||||
|
{
|
||||||
|
if (force)
|
||||||
|
SelectedLoadouts.Clear();
|
||||||
|
|
||||||
|
var roleProto = protoManager.Index(Role);
|
||||||
|
|
||||||
|
for (var i = roleProto.Groups.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var group = roleProto.Groups[i];
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(group, out var groupProto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SelectedLoadouts.ContainsKey(group))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SelectedLoadouts[group] = new List<Loadout>();
|
||||||
|
|
||||||
|
if (groupProto.MinLimit > 0)
|
||||||
|
{
|
||||||
|
// Apply any loadouts we can.
|
||||||
|
for (var j = 0; j < Math.Min(groupProto.MinLimit, groupProto.Loadouts.Count); j++)
|
||||||
|
{
|
||||||
|
AddLoadout(group, groupProto.Loadouts[j], protoManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether a loadout is valid or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid(ICommonSession session, ProtoId<LoadoutPrototype> loadout, IDependencyCollection collection, [NotNullWhen(false)] out FormattedMessage? reason)
|
||||||
|
{
|
||||||
|
reason = null;
|
||||||
|
|
||||||
|
var protoManager = collection.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(loadout, out var loadoutProto))
|
||||||
|
{
|
||||||
|
// Uhh
|
||||||
|
reason = FormattedMessage.FromMarkup("");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!protoManager.TryIndex(Role, out var roleProto))
|
||||||
|
{
|
||||||
|
reason = FormattedMessage.FromUnformatted("loadouts-prototype-missing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var valid = true;
|
||||||
|
|
||||||
|
foreach (var effect in loadoutProto.Effects)
|
||||||
|
{
|
||||||
|
valid = valid && effect.Validate(this, session, collection, out reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the specified loadout to this group.
|
||||||
|
/// </summary>
|
||||||
|
public bool AddLoadout(ProtoId<LoadoutGroupPrototype> selectedGroup, ProtoId<LoadoutPrototype> selectedLoadout, IPrototypeManager protoManager)
|
||||||
|
{
|
||||||
|
var groupLoadouts = SelectedLoadouts[selectedGroup];
|
||||||
|
|
||||||
|
// Need to unselect existing ones if we're at or above limit
|
||||||
|
var limit = Math.Max(0, groupLoadouts.Count + 1 - protoManager.Index(selectedGroup).MaxLimit);
|
||||||
|
|
||||||
|
for (var i = 0; i < groupLoadouts.Count; i++)
|
||||||
|
{
|
||||||
|
var loadout = groupLoadouts[i];
|
||||||
|
|
||||||
|
if (loadout.Prototype != selectedLoadout)
|
||||||
|
{
|
||||||
|
// Remove any other loadouts that might push it above the limit.
|
||||||
|
if (limit > 0)
|
||||||
|
{
|
||||||
|
limit--;
|
||||||
|
groupLoadouts.RemoveAt(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugTools.Assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupLoadouts.Add(new Loadout()
|
||||||
|
{
|
||||||
|
Prototype = selectedLoadout,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removed the specified loadout from this group.
|
||||||
|
/// </summary>
|
||||||
|
public bool RemoveLoadout(ProtoId<LoadoutGroupPrototype> selectedGroup, ProtoId<LoadoutPrototype> selectedLoadout, IPrototypeManager protoManager)
|
||||||
|
{
|
||||||
|
// Although this may bring us below minimum we'll let EnsureValid handle it.
|
||||||
|
|
||||||
|
var groupLoadouts = SelectedLoadouts[selectedGroup];
|
||||||
|
|
||||||
|
for (var i = 0; i < groupLoadouts.Count; i++)
|
||||||
|
{
|
||||||
|
var loadout = groupLoadouts[i];
|
||||||
|
|
||||||
|
if (loadout.Prototype != selectedLoadout)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
groupLoadouts.RemoveAt(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Content.Shared/Preferences/Loadouts/RoleLoadoutPrototype.cs
Normal file
29
Content.Shared/Preferences/Loadouts/RoleLoadoutPrototype.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Preferences.Loadouts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to a Job / Antag prototype and specifies loadouts
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
public sealed class RoleLoadoutPrototype : IPrototype
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Separate to JobPrototype / AntagPrototype as they are turning into messy god classes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Groups that comprise this role loadout.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public List<ProtoId<LoadoutGroupPrototype>> Groups = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many points are allotted for this role loadout prototype.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public int? Points;
|
||||||
|
}
|
||||||
@@ -96,7 +96,7 @@ namespace Content.Shared.Roles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool TryRequirementMet(
|
public static bool TryRequirementMet(
|
||||||
JobRequirement requirement,
|
JobRequirement requirement,
|
||||||
Dictionary<string, TimeSpan> playTimes,
|
IReadOnlyDictionary<string, TimeSpan> playTimes,
|
||||||
[NotNullWhen(false)] out FormattedMessage? reason,
|
[NotNullWhen(false)] out FormattedMessage? reason,
|
||||||
IEntityManager entManager,
|
IEntityManager entManager,
|
||||||
IPrototypeManager prototypes)
|
IPrototypeManager prototypes)
|
||||||
|
|||||||
@@ -9,37 +9,21 @@ namespace Content.Shared.Roles
|
|||||||
[DataField]
|
[DataField]
|
||||||
public Dictionary<string, EntProtoId> Equipment = new();
|
public Dictionary<string, EntProtoId> Equipment = new();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// if empty, there is no skirt override - instead the uniform provided in equipment is added.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public EntProtoId? InnerClothingSkirt;
|
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public EntProtoId? Satchel;
|
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public EntProtoId? Duffelbag;
|
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public List<EntProtoId> Inhand = new(0);
|
public List<EntProtoId> Inhand = new(0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts entities into the specified slot's storage (if it does have storage).
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public Dictionary<string, List<EntProtoId>> Storage = new();
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
[IdDataField]
|
[IdDataField]
|
||||||
public string ID { get; private set; } = string.Empty;
|
public string ID { get; private set; } = string.Empty;
|
||||||
|
|
||||||
public string GetGear(string slot, HumanoidCharacterProfile? profile)
|
public string GetGear(string slot)
|
||||||
{
|
{
|
||||||
if (profile != null)
|
|
||||||
{
|
|
||||||
if (slot == "jumpsuit" && profile.Clothing == ClothingPreference.Jumpskirt && !string.IsNullOrEmpty(InnerClothingSkirt))
|
|
||||||
return InnerClothingSkirt;
|
|
||||||
if (slot == "back" && profile.Backpack == BackpackPreference.Satchel && !string.IsNullOrEmpty(Satchel))
|
|
||||||
return Satchel;
|
|
||||||
if (slot == "back" && profile.Backpack == BackpackPreference.Duffelbag && !string.IsNullOrEmpty(Duffelbag))
|
|
||||||
return Duffelbag;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Equipment.TryGetValue(slot, out var equipment) ? equipment : string.Empty;
|
return Equipment.TryGetValue(slot, out var equipment) ? equipment : string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ using Content.Shared.Hands.EntitySystems;
|
|||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.Storage;
|
||||||
|
using Content.Shared.Storage.EntitySystems;
|
||||||
|
using Robust.Shared.Collections;
|
||||||
|
|
||||||
namespace Content.Shared.Station;
|
namespace Content.Shared.Station;
|
||||||
|
|
||||||
@@ -10,31 +13,31 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] protected readonly InventorySystem InventorySystem = default!;
|
[Dependency] protected readonly InventorySystem InventorySystem = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedStorageSystem _storage = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Equips starting gear onto the given entity.
|
/// Equips starting gear onto the given entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entity">Entity to load out.</param>
|
/// <param name="entity">Entity to load out.</param>
|
||||||
/// <param name="startingGear">Starting gear to use.</param>
|
/// <param name="startingGear">Starting gear to use.</param>
|
||||||
/// <param name="profile">Character profile to use, if any.</param>
|
public void EquipStartingGear(EntityUid entity, StartingGearPrototype startingGear)
|
||||||
public void EquipStartingGear(EntityUid entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile)
|
|
||||||
{
|
{
|
||||||
if (InventorySystem.TryGetSlots(entity, out var slotDefinitions))
|
if (InventorySystem.TryGetSlots(entity, out var slotDefinitions))
|
||||||
{
|
{
|
||||||
foreach (var slot in slotDefinitions)
|
foreach (var slot in slotDefinitions)
|
||||||
{
|
{
|
||||||
var equipmentStr = startingGear.GetGear(slot.Name, profile);
|
var equipmentStr = startingGear.GetGear(slot.Name);
|
||||||
if (!string.IsNullOrEmpty(equipmentStr))
|
if (!string.IsNullOrEmpty(equipmentStr))
|
||||||
{
|
{
|
||||||
var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, EntityManager.GetComponent<TransformComponent>(entity).Coordinates);
|
var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, EntityManager.GetComponent<TransformComponent>(entity).Coordinates);
|
||||||
InventorySystem.TryEquip(entity, equipmentEntity, slot.Name, true, force:true);
|
InventorySystem.TryEquip(entity, equipmentEntity, slot.Name, silent: true, force:true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryComp(entity, out HandsComponent? handsComponent))
|
if (TryComp(entity, out HandsComponent? handsComponent))
|
||||||
return;
|
{
|
||||||
|
|
||||||
var inhand = startingGear.Inhand;
|
var inhand = startingGear.Inhand;
|
||||||
var coords = EntityManager.GetComponent<TransformComponent>(entity).Coordinates;
|
var coords = EntityManager.GetComponent<TransformComponent>(entity).Coordinates;
|
||||||
foreach (var prototype in inhand)
|
foreach (var prototype in inhand)
|
||||||
@@ -47,4 +50,33 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (startingGear.Storage.Count > 0)
|
||||||
|
{
|
||||||
|
var coords = _xformSystem.GetMapCoordinates(entity);
|
||||||
|
var ents = new ValueList<EntityUid>();
|
||||||
|
TryComp(entity, out InventoryComponent? inventoryComp);
|
||||||
|
|
||||||
|
foreach (var (slot, entProtos) in startingGear.Storage)
|
||||||
|
{
|
||||||
|
if (entProtos.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var ent in entProtos)
|
||||||
|
{
|
||||||
|
ents.Add(Spawn(ent, coords));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventoryComp != null &&
|
||||||
|
InventorySystem.TryGetSlotEntity(entity, slot, out var slotEnt, inventoryComponent: inventoryComp) &&
|
||||||
|
TryComp(slotEnt, out StorageComponent? storage))
|
||||||
|
{
|
||||||
|
foreach (var ent in ents)
|
||||||
|
{
|
||||||
|
_storage.Insert(slotEnt.Value, ent, out _, storageComp: storage, playSound: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
Resources/Locale/en-US/job/loadouts.ftl
Normal file
2
Resources/Locale/en-US/job/loadouts.ftl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
loadout-window = Loadout
|
||||||
|
loadout-none = None
|
||||||
159
Resources/Locale/en-US/preferences/loadout-groups.ftl
Normal file
159
Resources/Locale/en-US/preferences/loadout-groups.ftl
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
loadout-group-trinkets = Trinkets
|
||||||
|
|
||||||
|
# Command
|
||||||
|
loadout-group-captain-head = Captain head
|
||||||
|
loadout-group-captain-jumpsuit = Captain jumpsuit
|
||||||
|
loadout-group-captain-neck = Captain neck
|
||||||
|
loadout-group-captain-backpack = Captain backpack
|
||||||
|
|
||||||
|
loadout-group-hop-head = Head of Personnel head
|
||||||
|
loadout-group-hop-jumpsuit = Head of Personnel jumpsuit
|
||||||
|
loadout-group-hop-neck = Head of Personnel neck
|
||||||
|
loadout-group-hop-backpack = Head of Personnel backpack
|
||||||
|
|
||||||
|
|
||||||
|
# Civilian
|
||||||
|
loadout-group-passenger-jumpsuit = Passenger jumpsuit
|
||||||
|
loadout-group-passenger-mask = Passenger mask
|
||||||
|
loadout-group-passenger-gloves = Passenger gloves
|
||||||
|
loadout-group-passenger-backpack = Passenger backpack
|
||||||
|
|
||||||
|
loadout-group-bartender-head = Bartender head
|
||||||
|
loadout-group-bartender-jumpsuit = Bartender jumpsuit
|
||||||
|
loadout-group-bartender-outerclothing = Bartender outer clothing
|
||||||
|
|
||||||
|
loadout-group-chef-head = Chef head
|
||||||
|
loadout-group-chef-mask = Chef mask
|
||||||
|
loadout-group-chef-jumpsuit = Chef jumpsuit
|
||||||
|
loadout-group-chef-outerclothing = Chef outer clothing
|
||||||
|
|
||||||
|
loadout-group-librarian-jumpsuit = Librarian jumpsuit
|
||||||
|
|
||||||
|
loadout-group-lawyer-jumpsuit = Lawyer jumpsuit
|
||||||
|
loadout-group-lawyer-neck = Lawyer neck
|
||||||
|
|
||||||
|
loadout-group-chaplain-head = Chaplain head
|
||||||
|
loadout-group-chaplain-mask = Chaplain mask
|
||||||
|
loadout-group-chaplain-jumpsuit = Chaplain jumpsuit
|
||||||
|
loadout-group-chaplain-backpack = Chaplain backpack
|
||||||
|
loadout-group-chaplain-outerclothing = Chaplain outer clothing
|
||||||
|
loadout-group-chaplain-neck = Chaplain neck
|
||||||
|
|
||||||
|
loadout-group-janitor-head = Janitor head
|
||||||
|
loadout-group-janitor-jumpsuit = Janitor jumpsuit
|
||||||
|
|
||||||
|
loadout-group-botanist-head = Botanist head
|
||||||
|
loadout-group-botanist-jumpsuit = Botanist jumpsuit
|
||||||
|
loadout-group-botanist-backpack = Botanist backpack
|
||||||
|
loadout-group-botanist-outerclothing = Botanist outer clothing
|
||||||
|
|
||||||
|
loadout-group-clown-head = Clown head
|
||||||
|
loadout-group-clown-jumpsuit = Clown jumpsuit
|
||||||
|
loadout-group-clown-backpack = Clown backpack
|
||||||
|
loadout-group-clown-shoes = Clown shoes
|
||||||
|
|
||||||
|
loadout-group-mime-head = Mime head
|
||||||
|
loadout-group-mime-mask = Mime mask
|
||||||
|
loadout-group-mime-jumpsuit = Mime jumpsuit
|
||||||
|
loadout-group-mime-backpack = Mime backpack
|
||||||
|
|
||||||
|
loadout-group-musician-backpack = Musician backpack
|
||||||
|
|
||||||
|
# Cargo
|
||||||
|
loadout-group-quartermaster-head = Quartermaster head
|
||||||
|
loadout-group-quartermaster-jumpsuit = Quartermaster jumpsuit
|
||||||
|
loadout-group-quartermaster-backpack = Quartermaster backpack
|
||||||
|
loadout-group-quartermaster-neck = Quartermaster neck
|
||||||
|
|
||||||
|
loadout-group-cargo-technician-head = Technician head
|
||||||
|
loadout-group-cargo-technician-jumpsuit = Technician jumpsuit
|
||||||
|
loadout-group-cargo-technician-backpack = Technician backpack
|
||||||
|
|
||||||
|
loadout-group-salvage-specialist-backpack = Salvage Specialist backpack
|
||||||
|
|
||||||
|
# Engineering
|
||||||
|
loadout-group-chief-engineer-head = Chief Engineer head
|
||||||
|
loadout-group-chief-engineer-jumpsuit = Chief Engineer jumpsuit
|
||||||
|
loadout-group-chief-engineer-backpack = Chief Engineer backpack
|
||||||
|
loadout-group-chief-engineer-neck = Chief Engineer neck
|
||||||
|
|
||||||
|
loadout-group-technical-assistant-jumpsuit = Technical Assistant jumpsuit
|
||||||
|
|
||||||
|
loadout-group-station-engineer-head = Station Engineer head
|
||||||
|
loadout-group-station-engineer-jumpsuit = Station Engineer jumpsuit
|
||||||
|
loadout-group-station-engineer-backpack = Station Engineer backpack
|
||||||
|
loadout-group-station-engineer-outerclothing = Station Engineer outer clothing
|
||||||
|
loadout-group-station-engineer-id = Station Engineer ID
|
||||||
|
|
||||||
|
loadout-group-atmospheric-technician-jumpsuit = Atmospheric Technician jumpsuit
|
||||||
|
loadout-group-atmospheric-technician-backpack = Atmospheric Technician backpack
|
||||||
|
|
||||||
|
# Science
|
||||||
|
loadout-group-research-director-head = Research Director head
|
||||||
|
loadout-group-research-director-neck = Research Director neck
|
||||||
|
loadout-group-research-director-jumpsuit = Research Director jumpsuit
|
||||||
|
loadout-group-research-director-backpack = Research Director backpack
|
||||||
|
loadout-group-research-director-outerclothing = Research Director outer clothing
|
||||||
|
|
||||||
|
loadout-group-scientist-head = Scientist head
|
||||||
|
loadout-group-scientist-neck = Scientist neck
|
||||||
|
loadout-group-scientist-jumpsuit = Scientist jumpsuit
|
||||||
|
loadout-group-scientist-backpack = Scientist backpack
|
||||||
|
loadout-group-scientist-outerclothing = Scientist outer clothing
|
||||||
|
loadout-group-scientist-id = Scientist ID
|
||||||
|
|
||||||
|
loadout-group-research-assistant-jumpsuit = Research Assistant jumpsuit
|
||||||
|
|
||||||
|
# Security
|
||||||
|
loadout-group-head-of-security-head = Head of Security head
|
||||||
|
loadout-group-head-of-security-jumpsuit = Head of Security jumpsuit
|
||||||
|
loadout-group-head-of-security-neck = Head of Security neck
|
||||||
|
loadout-group-head-of-security-outerclothing = Head of Security outer clothing
|
||||||
|
|
||||||
|
loadout-group-warden-head = Warden head
|
||||||
|
loadout-group-warden-jumpsuit = Warden jumpsuit
|
||||||
|
loadout-group-warden-outerclothing = Warden outer clothing
|
||||||
|
|
||||||
|
loadout-group-security-head = Security head
|
||||||
|
loadout-group-security-jumpsuit = Security jumpsuit
|
||||||
|
loadout-group-security-backpack = Security backpack
|
||||||
|
loadout-group-security-id = Security ID
|
||||||
|
|
||||||
|
loadout-group-detective-head = Detective head
|
||||||
|
loadout-group-detective-neck = Detective neck
|
||||||
|
loadout-group-detective-jumpsuit = Detective jumpsuit
|
||||||
|
loadout-group-detective-backpack = Detective backpack
|
||||||
|
loadout-group-detective-outerclothing = Detective outer clothing
|
||||||
|
|
||||||
|
loadout-group-security-cadet-jumpsuit = Security cadet jumpsuit
|
||||||
|
|
||||||
|
# Medical
|
||||||
|
loadout-group-chief-medical-officer-head = Chief Medical Officer head
|
||||||
|
loadout-group-chief-medical-officer-jumpsuit = Chief Medical Officer jumpsuit
|
||||||
|
loadout-group-chief-medical-officer-outerclothing = Chief Medical Officer outer clothing
|
||||||
|
loadout-group-chief-medical-officer-backpack = Chief Medical Officer backpack
|
||||||
|
loadout-group-chief-medical-officer-neck = Chief Medical Officer neck
|
||||||
|
|
||||||
|
loadout-group-medical-doctor-head = Medical Doctor head
|
||||||
|
loadout-group-medical-doctor-jumpsuit = Medical Doctor jumpsuit
|
||||||
|
loadout-group-medical-doctor-outerclothing = Medical Doctor outer clothing
|
||||||
|
loadout-group-medical-doctor-backpack = Medical Doctor backpack
|
||||||
|
loadout-group-medical-doctor-id = Medical Doctor ID
|
||||||
|
|
||||||
|
loadout-group-medical-intern-jumpsuit = Medical intern jumpsuit
|
||||||
|
|
||||||
|
loadout-group-chemist-jumpsuit = Chemist jumpsuit
|
||||||
|
loadout-group-chemist-outerclothing = Chemist outer clothing
|
||||||
|
loadout-group-chemist-backpack = Chemist backpack
|
||||||
|
|
||||||
|
loadout-group-paramedic-head = Paramedic head
|
||||||
|
loadout-group-paramedic-jumpsuit = Paramedic jumpsuit
|
||||||
|
loadout-group-paramedic-outerclothing = Paramedic outer clothing
|
||||||
|
loadout-group-paramedic-backpack = Paramedic backpack
|
||||||
|
|
||||||
|
# Wildcards
|
||||||
|
loadout-group-reporter-jumpsuit = Reporter jumpsuit
|
||||||
|
|
||||||
|
loadout-group-boxer-jumpsuit = Boxer jumpsuit
|
||||||
|
loadout-group-boxer-gloves = Boxer gloves
|
||||||
7
Resources/Locale/en-US/preferences/loadouts.ftl
Normal file
7
Resources/Locale/en-US/preferences/loadouts.ftl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Restrictions
|
||||||
|
loadout-restrictions = Restrictions
|
||||||
|
loadouts-min-limit = Min count: {$count}
|
||||||
|
loadouts-max-limit = Max count: {$count}
|
||||||
|
loadouts-points-limit = Points: {$count} / {$max}
|
||||||
|
|
||||||
|
loadouts-points-restriction = Insufficient points
|
||||||
@@ -19,8 +19,6 @@ humanoid-profile-editor-pronouns-neuter-text = It / It
|
|||||||
humanoid-profile-editor-import-button = Import
|
humanoid-profile-editor-import-button = Import
|
||||||
humanoid-profile-editor-export-button = Export
|
humanoid-profile-editor-export-button = Export
|
||||||
humanoid-profile-editor-save-button = Save
|
humanoid-profile-editor-save-button = Save
|
||||||
humanoid-profile-editor-clothing-label = Clothing:
|
|
||||||
humanoid-profile-editor-backpack-label = Backpack:
|
|
||||||
humanoid-profile-editor-spawn-priority-label = Spawn priority:
|
humanoid-profile-editor-spawn-priority-label = Spawn priority:
|
||||||
humanoid-profile-editor-eyes-label = Eye color:
|
humanoid-profile-editor-eyes-label = Eye color:
|
||||||
humanoid-profile-editor-jobs-tab = Jobs
|
humanoid-profile-editor-jobs-tab = Jobs
|
||||||
|
|||||||
@@ -104,6 +104,17 @@
|
|||||||
- id: Flash
|
- id: Flash
|
||||||
#- id: TelescopicBaton
|
#- id: TelescopicBaton
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: ClothingBackpackIan
|
||||||
|
id: ClothingBackpackHOPIanFilled
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: BoxSurvival
|
||||||
|
- id: Flash
|
||||||
|
#- id: TelescopicBaton
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
noSpawn: true
|
noSpawn: true
|
||||||
parent: ClothingBackpackMedical
|
parent: ClothingBackpackMedical
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianHead
|
||||||
|
equipment: CargoTechnicianHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatCargosoft
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianJumpsuit
|
||||||
|
equipment: CargoTechnicianJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitCargo
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianJumpskirt
|
||||||
|
equipment: CargoTechnicianJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtCargo
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianBackpack
|
||||||
|
equipment: CargoTechnicianBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackCargoFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianSatchel
|
||||||
|
equipment: CargoTechnicianSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelCargoFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CargoTechnicianDuffel
|
||||||
|
equipment: CargoTechnicianDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CargoTechnicianDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelCargoFilled
|
||||||
111
Resources/Prototypes/Loadouts/Jobs/Cargo/quartermaster.yml
Normal file
111
Resources/Prototypes/Loadouts/Jobs/Cargo/quartermaster.yml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterJumpsuit
|
||||||
|
equipment: QuartermasterJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitQM
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterJumpskirt
|
||||||
|
equipment: QuartermasterJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtQM
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterTurtleneck
|
||||||
|
equipment: QuartermasterTurtleneck
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterTurtleneck
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitQMTurtleneck
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterTurtleneckSkirt
|
||||||
|
equipment: QuartermasterTurtleneckSkirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterTurtleneckSkirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtQMTurtleneck
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterFormalSuit
|
||||||
|
equipment: QuartermasterFormalSuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterFormalSuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitQMFormal
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterHead
|
||||||
|
equipment: QuartermasterHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatQMsoft
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterBeret
|
||||||
|
equipment: QuartermasterBeret
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretQM
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterCloak
|
||||||
|
equipment: QuartermasterCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakQm
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterMantle
|
||||||
|
equipment: QuartermasterMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleQM
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterBackpack
|
||||||
|
equipment: QuartermasterBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackQuartermasterFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterSatchel
|
||||||
|
equipment: QuartermasterSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelQuartermasterFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: QuartermasterDuffel
|
||||||
|
equipment: QuartermasterDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: QuartermasterDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelQuartermasterFilled
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: SalvageSpecialistBackpack
|
||||||
|
equipment: SalvageSpecialistBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SalvageSpecialistBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSalvageFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SalvageSpecialistSatchel
|
||||||
|
equipment: SalvageSpecialistSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SalvageSpecialistSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelSalvageFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SalvageSpecialistDuffel
|
||||||
|
equipment: SalvageSpecialistDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SalvageSpecialistDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelSalvageFilled
|
||||||
65
Resources/Prototypes/Loadouts/Jobs/Civilian/bartender.yml
Normal file
65
Resources/Prototypes/Loadouts/Jobs/Civilian/bartender.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderHead
|
||||||
|
equipment: BartenderHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatTophat
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderBowler
|
||||||
|
equipment: BartenderBowler
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderBowler
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBowlerHat
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderJumpsuit
|
||||||
|
equipment: BartenderJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitBartender
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderJumpskirt
|
||||||
|
equipment: BartenderJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtBartender
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderJumpsuitPurple
|
||||||
|
equipment: BartenderJumpsuitPurple
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderJumpsuitPurple
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitBartenderPurple
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderApron
|
||||||
|
equipment: BartenderApron
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderApron
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterApronBar
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BartenderVest
|
||||||
|
equipment: BartenderVest
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BartenderVest
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterVest
|
||||||
84
Resources/Prototypes/Loadouts/Jobs/Civilian/botanist.yml
Normal file
84
Resources/Prototypes/Loadouts/Jobs/Civilian/botanist.yml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistHead
|
||||||
|
equipment: BotanistHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatTrucker
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistBandana
|
||||||
|
equipment: BotanistBandana
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistBandana
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadBandBotany
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistJumpsuit
|
||||||
|
equipment: BotanistJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitHydroponics
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistJumpskirt
|
||||||
|
equipment: BotanistJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtHydroponics
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistOveralls
|
||||||
|
equipment: BotanistOveralls
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistOveralls
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformOveralls
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistBackpack
|
||||||
|
equipment: BotanistBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackHydroponicsFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistSatchel
|
||||||
|
equipment: BotanistSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelHydroponicsFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistDuffel
|
||||||
|
equipment: BotanistDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelHydroponicsFilled
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: BotanistApron
|
||||||
|
equipment: BotanistApron
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BotanistApron
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterApronBotanist
|
||||||
158
Resources/Prototypes/Loadouts/Jobs/Civilian/chaplain.yml
Normal file
158
Resources/Prototypes/Loadouts/Jobs/Civilian/chaplain.yml
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainHead
|
||||||
|
equipment: ChaplainHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatFez
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainPlagueHat
|
||||||
|
equipment: ChaplainPlagueHat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainPlagueHat
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatPlaguedoctor
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainWitchHat
|
||||||
|
equipment: ChaplainWitchHat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainWitchHat
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatWitch
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainWitchHatAlt
|
||||||
|
equipment: ChaplainWitchHatAlt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainWitchHatAlt
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatWitch1
|
||||||
|
|
||||||
|
# Mask
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainMask
|
||||||
|
equipment: ChaplainMask
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainMask
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskPlague
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainJumpsuit
|
||||||
|
equipment: ChaplainJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitChaplain
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainJumpskirt
|
||||||
|
equipment: ChaplainJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtChaplain
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainRobesDark
|
||||||
|
equipment: ChaplainRobesDark
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainRobesDark
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitMonasticRobeDark
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainRobesLight
|
||||||
|
equipment: ChaplainRobesLight
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainRobesLight
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitMonasticRobeLight
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainBackpack
|
||||||
|
equipment: ChaplainBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackChaplainFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainSatchel
|
||||||
|
equipment: ChaplainSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelChaplainFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainDuffel
|
||||||
|
equipment: ChaplainDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelChaplainFilled
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainNeck
|
||||||
|
equipment: ChaplainNeck
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainNeck
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckStoleChaplain
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainPlagueSuit
|
||||||
|
equipment: ChaplainPlagueSuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainPlagueSuit
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterPlagueSuit
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainNunRobe
|
||||||
|
equipment: ChaplainNunRobe
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainNunRobe
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterNunRobe
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainBlackHoodie
|
||||||
|
equipment: ChaplainBlackHoodie
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainBlackHoodie
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterHoodieBlack
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChaplainHoodie
|
||||||
|
equipment: ChaplainHoodie
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChaplainHoodie
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterHoodieChaplain
|
||||||
57
Resources/Prototypes/Loadouts/Jobs/Civilian/chef.yml
Normal file
57
Resources/Prototypes/Loadouts/Jobs/Civilian/chef.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: ChefHead
|
||||||
|
equipment: ChefHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatChef
|
||||||
|
|
||||||
|
# Mask
|
||||||
|
- type: loadout
|
||||||
|
id: ChefMask
|
||||||
|
equipment: ChefMask
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefMask
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskItalianMoustache
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ChefJumpsuit
|
||||||
|
equipment: ChefJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitChef
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChefJumpskirt
|
||||||
|
equipment: ChefJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtChef
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: ChefApron
|
||||||
|
equipment: ChefApron
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefApron
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterApronChef
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChefJacket
|
||||||
|
equipment: ChefJacket
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChefJacket
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterJacketChef
|
||||||
75
Resources/Prototypes/Loadouts/Jobs/Civilian/clown.yml
Normal file
75
Resources/Prototypes/Loadouts/Jobs/Civilian/clown.yml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: JesterHat
|
||||||
|
equipment: JesterHat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JesterHat
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatJesterAlt
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ClownSuit
|
||||||
|
equipment: ClownSuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ClownSuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitClown
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: JesterSuit
|
||||||
|
equipment: JesterSuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JesterSuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitJesterAlt
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ClownBackpack
|
||||||
|
equipment: ClownBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ClownBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackClownFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ClownSatchel
|
||||||
|
equipment: ClownSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ClownSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelClownFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ClownDuffel
|
||||||
|
equipment: ClownDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ClownDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelClownFilled
|
||||||
|
|
||||||
|
# Shoes
|
||||||
|
- type: loadout
|
||||||
|
id: ClownShoes
|
||||||
|
equipment: ClownShoes
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ClownShoes
|
||||||
|
equipment:
|
||||||
|
shoes: ClothingShoesClown
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: JesterShoes
|
||||||
|
equipment: JesterShoes
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JesterShoes
|
||||||
|
equipment:
|
||||||
|
shoes: ClothingShoesJester
|
||||||
28
Resources/Prototypes/Loadouts/Jobs/Civilian/janitor.yml
Normal file
28
Resources/Prototypes/Loadouts/Jobs/Civilian/janitor.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: JanitorHead
|
||||||
|
equipment: JanitorHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JanitorHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatPurplesoft
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: JanitorJumpsuit
|
||||||
|
equipment: JanitorJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JanitorJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitJanitor
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: JanitorJumpskirt
|
||||||
|
equipment: JanitorJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: JanitorJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtJanitor
|
||||||
100
Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml
Normal file
100
Resources/Prototypes/Loadouts/Jobs/Civilian/lawyer.yml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpsuit
|
||||||
|
equipment: LawyerJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLawyerBlack
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpskirt
|
||||||
|
equipment: LawyerJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLawyerBlack
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpsuitBlue
|
||||||
|
equipment: LawyerJumpsuitBlue
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpsuitBlue
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLawyerBlue
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpskirtBlue
|
||||||
|
equipment: LawyerJumpskirtBlue
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpskirtBlue
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLawyerBlue
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpsuitPurple
|
||||||
|
equipment: LawyerJumpsuitPurple
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpsuitPurple
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLawyerPurple
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpskirtPurple
|
||||||
|
equipment: LawyerJumpskirtPurple
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpskirtPurple
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLawyerPurple
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpsuitRed
|
||||||
|
equipment: LawyerJumpsuitRed
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpsuitRed
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLawyerRed
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpskirtRed
|
||||||
|
equipment: LawyerJumpskirtRed
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpskirtRed
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLawyerRed
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpsuitGood
|
||||||
|
equipment: LawyerJumpsuitGood
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpsuitGood
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLawyerGood
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerJumpskirtGood
|
||||||
|
equipment: LawyerJumpskirtGood
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerJumpskirtGood
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLawyerGood
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: LawyerNeck
|
||||||
|
equipment: LawyerNeck
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LawyerNeck
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckLawyerbadge
|
||||||
36
Resources/Prototypes/Loadouts/Jobs/Civilian/librarian.yml
Normal file
36
Resources/Prototypes/Loadouts/Jobs/Civilian/librarian.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: LibrarianJumpsuit
|
||||||
|
equipment: LibrarianJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LibrarianJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitLibrarian
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: LibrarianJumpskirt
|
||||||
|
equipment: LibrarianJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: LibrarianJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtLibrarian
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CuratorJumpsuit
|
||||||
|
equipment: CuratorJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CuratorJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitCurator
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CuratorJumpskirt
|
||||||
|
equipment: CuratorJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CuratorJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtCurator
|
||||||
102
Resources/Prototypes/Loadouts/Jobs/Civilian/mime.yml
Normal file
102
Resources/Prototypes/Loadouts/Jobs/Civilian/mime.yml
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: MimeHead
|
||||||
|
equipment: MimeHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeret
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeFrenchBeret
|
||||||
|
equipment: MimeFrenchBeret
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeFrenchBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretFrench
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeCap
|
||||||
|
equipment: MimeCap
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeCap
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatMimesoft
|
||||||
|
|
||||||
|
# Mask
|
||||||
|
- type: loadout
|
||||||
|
id: MimeMask
|
||||||
|
equipment: MimeMask
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeMask
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskMime
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeMaskSad
|
||||||
|
equipment: MimeMaskSad
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeMaskSad
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskSadMime
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeMaskScared
|
||||||
|
equipment: MimeMaskScared
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeMaskScared
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskScaredMime
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: MimeJumpsuit
|
||||||
|
equipment: MimeJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitMime
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeJumpskirt
|
||||||
|
equipment: MimeJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtMime
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: MimeBackpack
|
||||||
|
equipment: MimeBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackMimeFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeSatchel
|
||||||
|
equipment: MimeSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelMimeFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MimeDuffel
|
||||||
|
equipment: MimeDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MimeDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelMimeFilled
|
||||||
27
Resources/Prototypes/Loadouts/Jobs/Civilian/musician.yml
Normal file
27
Resources/Prototypes/Loadouts/Jobs/Civilian/musician.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: MusicianBackpack
|
||||||
|
equipment: MusicianBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MusicianBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackMusicianFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MusicianSatchel
|
||||||
|
equipment: MusicianSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MusicianSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelMusicianFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MusicianDuffel
|
||||||
|
equipment: MusicianDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MusicianDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelMusicianFilled
|
||||||
82
Resources/Prototypes/Loadouts/Jobs/Civilian/passenger.yml
Normal file
82
Resources/Prototypes/Loadouts/Jobs/Civilian/passenger.yml
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Greytide Time
|
||||||
|
- type: loadoutEffectGroup
|
||||||
|
id: GreyTider
|
||||||
|
effects:
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobPassenger
|
||||||
|
time: 36000 #10 hrs, silly reward for people who play passenger a lot
|
||||||
|
|
||||||
|
# Face
|
||||||
|
- type: loadout
|
||||||
|
id: PassengerFace
|
||||||
|
equipment: GasMask
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: GreyTider
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: GasMask
|
||||||
|
equipment:
|
||||||
|
mask: ClothingMaskGas
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: GreyJumpsuit
|
||||||
|
equipment: GreyJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: GreyJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitColorGrey
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: GreyJumpskirt
|
||||||
|
equipment: GreyJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: GreyJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtColorGrey
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: CommonBackpack
|
||||||
|
equipment: CommonBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CommonBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CommonSatchel
|
||||||
|
equipment: CommonSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CommonSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CommonDuffel
|
||||||
|
equipment: CommonDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CommonDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelFilled
|
||||||
|
|
||||||
|
# Gloves
|
||||||
|
- type: loadout
|
||||||
|
id: PassengerGloves
|
||||||
|
equipment: FingerlessInsulatedGloves
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: GreyTider
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: FingerlessInsulatedGloves
|
||||||
|
equipment:
|
||||||
|
gloves: ClothingHandsGlovesFingerlessInsulated
|
||||||
111
Resources/Prototypes/Loadouts/Jobs/Command/captain.yml
Normal file
111
Resources/Prototypes/Loadouts/Jobs/Command/captain.yml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainJumpsuit
|
||||||
|
equipment: CaptainJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitCaptain
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainJumpskirt
|
||||||
|
equipment: CaptainJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtCaptain
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainFormalSuit
|
||||||
|
equipment: CaptainFormalSuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainFormalSuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitCapFormal
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainFormalSkirt
|
||||||
|
equipment: CaptainFormalSkirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainFormalSkirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtCapFormalDress
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainHead
|
||||||
|
equipment: CaptainHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatCaptain
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainCap
|
||||||
|
equipment: CaptainCap
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainCap
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatCapcap
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainCloak
|
||||||
|
equipment: CaptainCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakCap
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainCloakFormal
|
||||||
|
equipment: CaptainCloakFormal
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainCloakFormal
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakCapFormal
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainMantle
|
||||||
|
equipment: CaptainMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleCap
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainBackpack
|
||||||
|
equipment: CaptainBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackCaptainFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainSatchel
|
||||||
|
equipment: CaptainSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelCaptainFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: CaptainDuffel
|
||||||
|
equipment: CaptainDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: CaptainDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelCaptainFilled
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Professional HoP Time
|
||||||
|
- type: loadoutEffectGroup
|
||||||
|
id: ProfessionalHoP
|
||||||
|
effects:
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobHeadOfPersonnel
|
||||||
|
time: 54000 #15 hrs, special reward for HoP mains
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: HoPJumpsuit
|
||||||
|
equipment: HoPJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitHoP
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: HoPJumpskirt
|
||||||
|
equipment: HoPJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtHoP
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: HoPHead
|
||||||
|
equipment: HoPHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatHopcap
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: HoPCloak
|
||||||
|
equipment: HoPCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakHop
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: HoPMantle
|
||||||
|
equipment: HoPMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleHOP
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: HoPBackpack
|
||||||
|
equipment: HoPBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackHOPFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: HoPSatchel
|
||||||
|
equipment: HoPSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelHOPFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: HoPDuffel
|
||||||
|
equipment: HoPDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelHOPFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: HoPBackpackIan
|
||||||
|
equipment: HoPBackpackIan
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: ProfessionalHoP
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: HoPBackpackIan
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackHOPIanFilled
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianJumpsuit
|
||||||
|
equipment: AtmosphericTechnicianJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitAtmos
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianJumpskirt
|
||||||
|
equipment: AtmosphericTechnicianJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtAtmos
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianJumpsuitCasual
|
||||||
|
equipment: AtmosphericTechnicianJumpsuitCasual
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianJumpsuitCasual
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitAtmosCasual
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianBackpack
|
||||||
|
equipment: AtmosphericTechnicianBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackAtmosphericsFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianSatchel
|
||||||
|
equipment: AtmosphericTechnicianSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: AtmosphericTechnicianDuffel
|
||||||
|
equipment: AtmosphericTechnicianDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: AtmosphericTechnicianDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelAtmosphericsFilled
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerJumpsuit
|
||||||
|
equipment: ChiefEngineerJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitChiefEngineer
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerJumpskirt
|
||||||
|
equipment: ChiefEngineerJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtChiefEngineer
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerTurtleneck
|
||||||
|
equipment: ChiefEngineerTurtleneck
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerTurtleneck
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitChiefEngineerTurtle
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerTurtleneckSkirt
|
||||||
|
equipment: ChiefEngineerTurtleneckSkirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerTurtleneckSkirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtChiefEngineerTurtle
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerHead
|
||||||
|
equipment: ChiefEngineerHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatHardhatWhite
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerBeret
|
||||||
|
equipment: EngineeringBeret
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerCloak
|
||||||
|
equipment: ChiefEngineerCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakCe
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerMantle
|
||||||
|
equipment: ChiefEngineerMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleCE
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerBackpack
|
||||||
|
equipment: ChiefEngineerBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackChiefEngineerFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerSatchel
|
||||||
|
equipment: ChiefEngineerSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelChiefEngineerFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefEngineerDuffel
|
||||||
|
equipment: ChiefEngineerDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefEngineerDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelChiefEngineerFilled
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
# Senior times
|
||||||
|
- type: loadoutEffectGroup
|
||||||
|
id: SeniorEngineering
|
||||||
|
effects:
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobAtmosphericTechnician
|
||||||
|
time: 21600 #6 hrs
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobStationEngineer
|
||||||
|
time: 21600 #6 hrs
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:DepartmentTimeRequirement
|
||||||
|
department: Engineering
|
||||||
|
time: 216000 # 60 hrs
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerHead
|
||||||
|
equipment: StationEngineerHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatHardhatYellow
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerBeret
|
||||||
|
equipment: EngineeringBeret
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: EngineeringBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretEngineering
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerJumpsuit
|
||||||
|
equipment: StationEngineerJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitEngineering
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerJumpskirt
|
||||||
|
equipment: StationEngineerJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtEngineering
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerHazardsuit
|
||||||
|
equipment: StationEngineerHazardsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerHazardsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitEngineeringHazard
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerJumpsuit
|
||||||
|
equipment: SeniorEngineerJumpsuit
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitSeniorEngineer
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerJumpskirt
|
||||||
|
equipment: SeniorEngineerJumpskirt
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtSeniorEngineer
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerBackpack
|
||||||
|
equipment: StationEngineerBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerSatchel
|
||||||
|
equipment: StationEngineerSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerDuffel
|
||||||
|
equipment: StationEngineerDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerBackpack
|
||||||
|
equipment: SeniorEngineerBackpack
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerSatchel
|
||||||
|
equipment: SeniorEngineerSatchel
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelEngineeringFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerDuffel
|
||||||
|
equipment: SeniorEngineerDuffel
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelEngineeringFilled
|
||||||
|
|
||||||
|
# OuterClothing
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerOuterVest
|
||||||
|
equipment: StationEngineerOuterVest
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerOuterVest
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterVestHazard
|
||||||
|
|
||||||
|
# ID
|
||||||
|
- type: loadout
|
||||||
|
id: StationEngineerPDA
|
||||||
|
equipment: StationEngineerPDA
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: StationEngineerPDA
|
||||||
|
equipment:
|
||||||
|
id: EngineerPDA
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorEngineerPDA
|
||||||
|
equipment: SeniorEngineerPDA
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorEngineering
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorEngineerPDA
|
||||||
|
equipment:
|
||||||
|
id: SeniorEngineerPDA
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: YellowJumpsuit
|
||||||
|
equipment: YellowJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: YellowJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitColorYellow
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: YellowJumpskirt
|
||||||
|
equipment: YellowJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: YellowJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtColorYellow
|
||||||
56
Resources/Prototypes/Loadouts/Jobs/Medical/chemist.yml
Normal file
56
Resources/Prototypes/Loadouts/Jobs/Medical/chemist.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistJumpsuit
|
||||||
|
equipment: ChemistJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitChemistry
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistJumpskirt
|
||||||
|
equipment: ChemistJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtChemistry
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistBackpack
|
||||||
|
equipment: ChemistBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackChemistryFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistSatchel
|
||||||
|
equipment: ChemistSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelChemistryFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistDuffel
|
||||||
|
equipment: ChemistDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelChemistryFilled
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: ChemistLabCoat
|
||||||
|
equipment: ChemistLabCoat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChemistLabCoat
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterCoatLabChem
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerJumpsuit
|
||||||
|
equipment: ChiefMedicalOfficerJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitCMO
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerJumpskirt
|
||||||
|
equipment: ChiefMedicalOfficerJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtCMO
|
||||||
|
|
||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerBeret
|
||||||
|
equipment: ChiefMedicalOfficerBeret
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretCmo
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerCloak
|
||||||
|
equipment: ChiefMedicalOfficerCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingCloakCmo
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerMantle
|
||||||
|
equipment: ChiefMedicalOfficerMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleCMO
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerBackpack
|
||||||
|
equipment: ChiefMedicalOfficerBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackCMOFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerSatchel
|
||||||
|
equipment: ChiefMedicalOfficerSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelCMOFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerDuffel
|
||||||
|
equipment: ChiefMedicalOfficerDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelCMOFilled
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: ChiefMedicalOfficerLabCoat
|
||||||
|
equipment: ChiefMedicalOfficerLabCoat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ChiefMedicalOfficerLabCoat
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterCoatLabCmo
|
||||||
239
Resources/Prototypes/Loadouts/Jobs/Medical/medical_doctor.yml
Normal file
239
Resources/Prototypes/Loadouts/Jobs/Medical/medical_doctor.yml
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
# Senior Time
|
||||||
|
- type: loadoutEffectGroup
|
||||||
|
id: SeniorPhysician
|
||||||
|
effects:
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobChemist
|
||||||
|
time: 21600 #6 hrs
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:RoleTimeRequirement
|
||||||
|
role: JobMedicalDoctor
|
||||||
|
time: 21600 #6 hrs
|
||||||
|
- !type:JobRequirementLoadoutEffect
|
||||||
|
requirement:
|
||||||
|
!type:DepartmentTimeRequirement
|
||||||
|
department: Medical
|
||||||
|
time: 216000 # 60 hrs
|
||||||
|
|
||||||
|
# Head
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianBeret
|
||||||
|
equipment: SeniorPhysicianBeret
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretSeniorPhysician
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalBeret
|
||||||
|
equipment: MedicalBeret
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalBeret
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatBeretMedic
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: BlueSurgeryCap
|
||||||
|
equipment: BlueSurgeryCap
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: BlueSurgeryCap
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatSurgcapBlue
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: GreenSurgeryCap
|
||||||
|
equipment: GreenSurgeryCap
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: GreenSurgeryCap
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatSurgcapGreen
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: PurpleSurgeryCap
|
||||||
|
equipment: PurpleSurgeryCap
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: PurpleSurgeryCap
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatSurgcapPurple
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorJumpsuit
|
||||||
|
equipment: MedicalDoctorJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitMedicalDoctor
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorJumpskirt
|
||||||
|
equipment: MedicalDoctorJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtMedicalDoctor
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianJumpsuit
|
||||||
|
equipment: SeniorPhysicianJumpsuit
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitSeniorPhysician
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianJumpskirt
|
||||||
|
equipment: SeniorPhysicianJumpskirt
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtSeniorPhysician
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalBlueScrubs
|
||||||
|
equipment: MedicalBlueScrubs
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalBlueScrubs
|
||||||
|
equipment:
|
||||||
|
jumpsuit: UniformScrubsColorBlue
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalGreenScrubs
|
||||||
|
equipment: MedicalGreenScrubs
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalGreenScrubs
|
||||||
|
equipment:
|
||||||
|
jumpsuit: UniformScrubsColorGreen
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalPurpleScrubs
|
||||||
|
equipment: MedicalPurpleScrubs
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalPurpleScrubs
|
||||||
|
equipment:
|
||||||
|
jumpsuit: UniformScrubsColorPurple
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorBackpack
|
||||||
|
equipment: MedicalDoctorBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackMedicalFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorSatchel
|
||||||
|
equipment: MedicalDoctorSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelMedicalFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorDuffel
|
||||||
|
equipment: MedicalDoctorDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelMedicalFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianBackpack
|
||||||
|
equipment: SeniorPhysicianBackpack
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelMedicalFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianSatchel
|
||||||
|
equipment: SeniorPhysicianSatchel
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelMedicalFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianDuffel
|
||||||
|
equipment: SeniorPhysicianDuffel
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelMedicalFilled
|
||||||
|
|
||||||
|
# OuterClothing
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianLabCoat
|
||||||
|
equipment: SeniorPhysicianLabCoat
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianLabCoat
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterCoatLabSeniorPhysician
|
||||||
|
|
||||||
|
# ID
|
||||||
|
- type: loadout
|
||||||
|
id: MedicalDoctorPDA
|
||||||
|
equipment: MedicalDoctorPDA
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: MedicalDoctorPDA
|
||||||
|
equipment:
|
||||||
|
id: MedicalPDA
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: SeniorPhysicianPDA
|
||||||
|
equipment: SeniorPhysicianPDA
|
||||||
|
effects:
|
||||||
|
- !type:GroupLoadoutEffect
|
||||||
|
proto: SeniorPhysician
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: SeniorPhysicianPDA
|
||||||
|
equipment:
|
||||||
|
id: SeniorPhysicianPDA
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: WhiteJumpsuit
|
||||||
|
equipment: WhiteJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: WhiteJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitColorWhite
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: WhiteJumpskirt
|
||||||
|
equipment: WhiteJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: WhiteJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtColorWhite
|
||||||
66
Resources/Prototypes/Loadouts/Jobs/Medical/paramedic.yml
Normal file
66
Resources/Prototypes/Loadouts/Jobs/Medical/paramedic.yml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Head
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicHead
|
||||||
|
equipment: ParamedicHead
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicHead
|
||||||
|
equipment:
|
||||||
|
head: ClothingHeadHatParamedicsoft
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicJumpsuit
|
||||||
|
equipment: ParamedicJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitParamedic
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicJumpskirt
|
||||||
|
equipment: ParamedicJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtParamedic
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicBackpack
|
||||||
|
equipment: ParamedicBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackParamedicFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicSatchel
|
||||||
|
equipment: ParamedicSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelParamedicFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicDuffel
|
||||||
|
equipment: ParamedicDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelParamedicFilled
|
||||||
|
|
||||||
|
# Outer clothing
|
||||||
|
- type: loadout
|
||||||
|
id: ParamedicWindbreaker
|
||||||
|
equipment: ParamedicWindbreaker
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ParamedicWindbreaker
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterCoatParamedicWB
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# Head
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorBeret
|
||||||
|
equipment: ScientificBeret
|
||||||
|
|
||||||
|
# Neck
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorMantle
|
||||||
|
equipment: ResearchDirectorMantle
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorMantle
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckMantleRD
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorCloak
|
||||||
|
equipment: ResearchDirectorCloak
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorCloak
|
||||||
|
equipment:
|
||||||
|
neck: ClothingNeckCloakRd
|
||||||
|
|
||||||
|
# Jumpsuit
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorJumpsuit
|
||||||
|
equipment: ResearchDirectorJumpsuit
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorJumpsuit
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitResearchDirector
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorJumpskirt
|
||||||
|
equipment: ResearchDirectorJumpskirt
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorJumpskirt
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpskirtResearchDirector
|
||||||
|
|
||||||
|
# Back
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorBackpack
|
||||||
|
equipment: ResearchDirectorBackpack
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorBackpack
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackResearchDirectorFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorSatchel
|
||||||
|
equipment: ResearchDirectorSatchel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorSatchel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackSatchelResearchDirectorFilled
|
||||||
|
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorDuffel
|
||||||
|
equipment: ResearchDirectorDuffel
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorDuffel
|
||||||
|
equipment:
|
||||||
|
back: ClothingBackpackDuffelResearchDirectorFilled
|
||||||
|
|
||||||
|
# OuterClothing
|
||||||
|
- type: loadout
|
||||||
|
id: ResearchDirectorLabCoat
|
||||||
|
equipment: ResearchDirectorLabCoat
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: ResearchDirectorLabCoat
|
||||||
|
equipment:
|
||||||
|
outerClothing: ClothingOuterCoatRD
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user