Add group for loadouts (#36951)
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
This commit is contained in:
@@ -20,6 +20,12 @@ public sealed partial class LoadoutContainer : BoxContainer
|
||||
|
||||
public Button Select => SelectButton;
|
||||
|
||||
public string? Text
|
||||
{
|
||||
get => SelectButton.Text;
|
||||
set => SelectButton.Text = value;
|
||||
}
|
||||
|
||||
public LoadoutContainer(ProtoId<LoadoutPrototype> proto, bool disabled, FormattedMessage? reason)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -54,22 +60,9 @@ public sealed partial class LoadoutContainer : BoxContainer
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<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 StyleClasses="AngleRect" HorizontalExpand="True" Margin="5">
|
||||
<BoxContainer Name="LoadoutsContainer" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True"/>
|
||||
</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"/>
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True" Margin="5">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Text="{Loc 'loadout-restrictions'}"/>
|
||||
<BoxContainer Name="RestrictionsContainer" Orientation="Vertical" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
@@ -7,12 +6,21 @@ using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Client.Lobby.UI.Loadouts;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||
{
|
||||
private const string ClosedGroupMark = "▶";
|
||||
private const string OpenedGroupMark = "▼";
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary that stores open groups
|
||||
/// </summary>
|
||||
private Dictionary<string, bool> _openedGroups = new();
|
||||
|
||||
private readonly LoadoutGroupPrototype _groupProto;
|
||||
|
||||
public event Action<ProtoId<LoadoutPrototype>>? OnLoadoutPressed;
|
||||
@@ -21,6 +29,7 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||
public LoadoutGroupContainer(HumanoidCharacterProfile profile, RoleLoadout loadout, LoadoutGroupPrototype groupProto, ICommonSession session, IDependencyCollection collection)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_groupProto = groupProto;
|
||||
|
||||
RefreshLoadouts(profile, loadout, session, collection);
|
||||
@@ -63,32 +72,165 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||
}
|
||||
|
||||
LoadoutsContainer.DisposeAllChildren();
|
||||
// Didn't use options because this is more robust in future.
|
||||
|
||||
var selected = loadout.SelectedLoadouts[_groupProto.ID];
|
||||
// Get all loadout prototypes for this group.
|
||||
var validProtos = _groupProto.Loadouts.Select(id => protoMan.Index(id));
|
||||
|
||||
foreach (var loadoutProto in _groupProto.Loadouts)
|
||||
/*
|
||||
* Group the prototypes based on their GroupBy field.
|
||||
* - If GroupBy is null or empty, fallback to grouping by the prototype ID itself.
|
||||
* - The result is a dictionary where:
|
||||
* - The key is either GroupBy or ID (if GroupBy is not set).
|
||||
* - The value is the list of prototypes that belong to that group.
|
||||
*
|
||||
* This allows grouping loadouts into sub-categories within the group.
|
||||
*/
|
||||
var groups = validProtos
|
||||
.GroupBy(p => string.IsNullOrEmpty(p.GroupBy)
|
||||
? p.ID
|
||||
: p.GroupBy)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
|
||||
foreach (var kvp in groups)
|
||||
{
|
||||
if (!protoMan.TryIndex(loadoutProto, out var loadProto))
|
||||
continue;
|
||||
var protos = kvp.Value;
|
||||
|
||||
var matchingLoadout = selected.FirstOrDefault(e => e.Prototype == loadoutProto);
|
||||
var pressed = matchingLoadout != null;
|
||||
|
||||
var enabled = loadout.IsValid(profile, 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 (protos.Count > 1)
|
||||
{
|
||||
if (args.Button.Pressed)
|
||||
OnLoadoutPressed?.Invoke(loadoutProto);
|
||||
/*
|
||||
* Build the list of UI elements for each loadout prototype:
|
||||
* - For each prototype, create its corresponding LoadoutContainer UI element.
|
||||
* - Set HorizontalExpand to true so elements properly stretch in layout.
|
||||
* - Collect all UI elements into a list for further processing.
|
||||
*/
|
||||
var uiElements = protos
|
||||
.Select(proto =>
|
||||
{
|
||||
var elem = CreateLoadoutUI(proto, profile, loadout, session, collection, loadoutSystem);
|
||||
elem.HorizontalExpand = true;
|
||||
return elem;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
/*
|
||||
* Determine which element should be displayed first:
|
||||
* - If any element is currently selected (its button is pressed), use it.
|
||||
* - Otherwise, fallback to the first element in the list.
|
||||
*
|
||||
* This moves the selected item outside of the sublist for better usability,
|
||||
* making it easier for players to quickly toggle loadout options (e.g. clothing, accessories)
|
||||
* without having to search inside expanded subgroups.
|
||||
*/
|
||||
var firstElement = uiElements.FirstOrDefault(e => e.Select.Pressed) ?? uiElements[0];
|
||||
|
||||
/*
|
||||
* Get all remaining elements except the first one:
|
||||
* - Use ReferenceEquals to ensure we exclude the exact instance used as firstElement.
|
||||
*/
|
||||
var otherElements = uiElements.Where(e => !ReferenceEquals(e, firstElement)).ToList();
|
||||
|
||||
firstElement.HorizontalExpand = true;
|
||||
var subContainer = new SubLoadoutContainer()
|
||||
{
|
||||
Visible = _openedGroups.GetValueOrDefault(kvp.Key, false)
|
||||
};
|
||||
var toggle = CreateToggleButton(kvp, firstElement, subContainer);
|
||||
|
||||
LoadoutsContainer.AddChild(firstElement);
|
||||
LoadoutsContainer.AddChild(subContainer);
|
||||
|
||||
var subList = subContainer.Grid;
|
||||
foreach (var proto in otherElements)
|
||||
{
|
||||
subList.AddChild(proto);
|
||||
}
|
||||
|
||||
UpdateToggleColor(toggle, subList);
|
||||
}
|
||||
else
|
||||
OnLoadoutUnpressed?.Invoke(loadoutProto);
|
||||
{
|
||||
LoadoutsContainer.AddChild(
|
||||
CreateLoadoutUI(protos[0], profile, loadout, session, collection, loadoutSystem)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ToggleLoadoutButton CreateToggleButton(KeyValuePair<string, List<LoadoutPrototype>> kvp, LoadoutContainer firstElement, SubLoadoutContainer subContainer)
|
||||
{
|
||||
var toggle = new ToggleLoadoutButton
|
||||
{
|
||||
Text = ClosedGroupMark
|
||||
};
|
||||
|
||||
LoadoutsContainer.AddChild(loadoutContainer);
|
||||
toggle.Text = subContainer.Visible ? OpenedGroupMark : ClosedGroupMark;
|
||||
|
||||
toggle.OnPressed += _ =>
|
||||
{
|
||||
var willOpen = !subContainer.Visible;
|
||||
subContainer.Visible = willOpen;
|
||||
toggle.Text = willOpen ? OpenedGroupMark : ClosedGroupMark;
|
||||
_openedGroups[kvp.Key] = willOpen;
|
||||
};
|
||||
|
||||
firstElement.AddChild(toggle);
|
||||
toggle.SetPositionFirst();
|
||||
return toggle;
|
||||
}
|
||||
|
||||
private void UpdateToggleColor(Button toggle, BoxContainer subList)
|
||||
{
|
||||
var anyActive = subList.Children
|
||||
.OfType<LoadoutContainer>()
|
||||
.Any(c => c.Select.Pressed);
|
||||
|
||||
toggle.Modulate = anyActive
|
||||
? Color.Green
|
||||
: Color.White;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a UI container for a single Loadout item.
|
||||
///
|
||||
/// This method was extracted from RefreshLoadouts because the logic for creating
|
||||
/// individual loadout items is used multiple times inside that method, and duplicating
|
||||
/// the code made it harder to maintain.
|
||||
///
|
||||
/// Logic:
|
||||
/// - Checks if the item is currently selected in the loadout.
|
||||
/// - Checks if the item is valid for selection (IsValid).
|
||||
/// - Creates a LoadoutContainer with the appropriate status (disabled / active).
|
||||
/// - Subscribes to button press events to handle selection and deselection.
|
||||
/// </summary>
|
||||
/// <param name="proto">The loadout item prototype.</param>
|
||||
/// <param name="profile">The humanoid character profile.</param>
|
||||
/// <param name="loadout">The current role loadout for the user.</param>
|
||||
/// <param name="session">The user's session.</param>
|
||||
/// <param name="collection">The dependency injection container.</param>
|
||||
/// <param name="loadoutSystem">The loadout system instance.</param>
|
||||
/// <returns>A fully initialized LoadoutContainer for UI display.</returns>
|
||||
private LoadoutContainer CreateLoadoutUI(LoadoutPrototype proto, HumanoidCharacterProfile profile, RoleLoadout loadout, ICommonSession session, IDependencyCollection collection, LoadoutSystem loadoutSystem)
|
||||
{
|
||||
var selected = loadout.SelectedLoadouts[_groupProto.ID];
|
||||
|
||||
var pressed = selected.Any(e => e.Prototype == proto.ID);
|
||||
|
||||
var enabled = loadout.IsValid(profile, session, proto.ID, collection, out var reason);
|
||||
|
||||
var cont = new LoadoutContainer(proto, !enabled, reason);
|
||||
|
||||
cont.Text = loadoutSystem.GetName(proto);
|
||||
|
||||
cont.Select.Pressed = pressed;
|
||||
|
||||
cont.Select.OnPressed += args =>
|
||||
{
|
||||
if (args.Button.Pressed)
|
||||
OnLoadoutPressed?.Invoke(proto.ID);
|
||||
else
|
||||
OnLoadoutUnpressed?.Invoke(proto.ID);
|
||||
};
|
||||
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<PanelContainer Name="SubContainer"
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<BoxContainer Name="SubGridContainer"
|
||||
Orientation="Vertical"
|
||||
HorizontalExpand="true"/>
|
||||
|
||||
</PanelContainer>
|
||||
21
Content.Client/Lobby/UI/Loadouts/SubLoadoutContainer.xaml.cs
Normal file
21
Content.Client/Lobby/UI/Loadouts/SubLoadoutContainer.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.Lobby.UI.Loadouts;
|
||||
|
||||
/// <summary>
|
||||
/// A simple container used to group additional loadout UI elements
|
||||
/// that are part of the same GroupBy subgroup.
|
||||
///
|
||||
/// - Used when a loadout group contains multiple prototypes.
|
||||
/// - The first prototype is shown directly; the remaining ones are placed inside this container.
|
||||
/// - Allows toggling visibility of the subgroup via expandable UI (collapsible behavior).
|
||||
///
|
||||
/// Internally inherits from PanelContainer to allow for border/background styling if needed.
|
||||
/// Exposes its internal BoxContainer (SubGridContainer) via the <see cref="Grid"/> property for adding children.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SubLoadoutContainer : PanelContainer
|
||||
{
|
||||
public BoxContainer Grid => SubGridContainer;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Button Name="ToggleButton"
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
VerticalExpand="False"
|
||||
HorizontalExpand="False"
|
||||
SetSize="64 64"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 5 0"/>
|
||||
10
Content.Client/Lobby/UI/Loadouts/ToggleLoadoutButton.xaml.cs
Normal file
10
Content.Client/Lobby/UI/Loadouts/ToggleLoadoutButton.xaml.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.Lobby.UI.Loadouts;
|
||||
|
||||
/// <summary>
|
||||
/// A button that toggles the loadout groups. Needs for override default styles.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ToggleLoadoutButton : Button;
|
||||
@@ -13,6 +13,11 @@ public sealed partial class LoadoutPrototype : IPrototype, IEquipmentLoadout
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// A text identifier used to group loadouts.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string? GroupBy;
|
||||
/*
|
||||
* You can either use an existing StartingGearPrototype or specify it inline to avoid bloating yaml.
|
||||
*/
|
||||
|
||||
@@ -13,31 +13,37 @@
|
||||
id: HeadofSecurityJumpsuit
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpsuitHoS
|
||||
groupBy: "jumpsuit"
|
||||
|
||||
- type: loadout
|
||||
id: HeadofSecurityJumpskirt
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpskirtHoS
|
||||
groupBy: "jumpskirt"
|
||||
|
||||
- type: loadout
|
||||
id: HeadofSecurityTurtleneck
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpsuitHoSAlt
|
||||
groupBy: "jumpsuit"
|
||||
|
||||
- type: loadout
|
||||
id: HeadofSecurityTurtleneckSkirt
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpskirtHoSAlt
|
||||
groupBy: "jumpskirt"
|
||||
|
||||
- type: loadout
|
||||
id: HeadofSecurityFormalSuit
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpsuitHosFormal
|
||||
groupBy: "jumpsuit"
|
||||
|
||||
- type: loadout
|
||||
id: HeadofSecurityFormalSkirt
|
||||
equipment:
|
||||
jumpsuit: ClothingUniformJumpskirtHosFormal
|
||||
groupBy: "jumpskirt"
|
||||
|
||||
# Head
|
||||
- type: loadout
|
||||
|
||||
@@ -56,30 +56,35 @@
|
||||
storage:
|
||||
back:
|
||||
- Lighter
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigPackGreen
|
||||
storage:
|
||||
back:
|
||||
- CigPackGreen
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigPackRed
|
||||
storage:
|
||||
back:
|
||||
- CigPackRed
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigPackBlue
|
||||
storage:
|
||||
back:
|
||||
- CigPackBlue
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigPackBlack
|
||||
storage:
|
||||
back:
|
||||
- CigPackBlack
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigarCase
|
||||
@@ -89,6 +94,7 @@
|
||||
storage:
|
||||
back:
|
||||
- CigarCase
|
||||
groupBy: "smokeables"
|
||||
|
||||
- type: loadout
|
||||
id: CigarGold
|
||||
@@ -98,6 +104,7 @@
|
||||
storage:
|
||||
back:
|
||||
- CigarGold
|
||||
groupBy: "smokeables"
|
||||
|
||||
# Pins
|
||||
- type: loadout
|
||||
@@ -105,108 +112,126 @@
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckLGBTPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAllyPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAllyPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAromanticPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAromanticPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAsexualPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAsexualPin
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAroacePin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAroacePin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckBisexualPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckBisexualPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckGayPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckGayPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckIntersexPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckIntersexPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckLesbianPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckLesbianPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckNonBinaryPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckNonBinaryPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckPansexualPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckPansexualPin
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckPluralPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckPluralPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckOmnisexualPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckOmnisexualPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckGenderqueerPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckGenderqueerPin
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckGenderfluidPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckGenderfluidPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckTransPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckTransPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAutismPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAutismPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckGoldAutismPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckGoldAutismPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckAroacePin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckAroacePin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckPluralPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckPluralPin
|
||||
groupBy: "pin"
|
||||
|
||||
- type: loadout
|
||||
id: ClothingNeckGenderfluidPin
|
||||
storage:
|
||||
back:
|
||||
- ClothingNeckGenderfluidPin
|
||||
groupBy: "pin"
|
||||
|
||||
# Towels
|
||||
- type: loadout
|
||||
@@ -219,6 +244,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorWhite
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorSilver
|
||||
@@ -230,6 +256,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorSilver
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorGold
|
||||
@@ -241,6 +268,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorGold
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorLightBrown
|
||||
@@ -253,6 +281,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorLightBrown
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorGreen
|
||||
@@ -265,6 +294,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorGreen
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorDarkBlue
|
||||
@@ -277,6 +307,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorDarkBlue
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorOrange
|
||||
@@ -289,6 +320,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorOrange
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorLightBlue
|
||||
@@ -301,6 +333,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorLightBlue
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorPurple
|
||||
@@ -313,6 +346,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorPurple
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorRed
|
||||
@@ -325,6 +359,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorRed
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorGray
|
||||
@@ -337,6 +372,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorGray
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorBlack
|
||||
@@ -349,6 +385,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorBlack
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorDarkGreen
|
||||
@@ -361,6 +398,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorDarkGreen
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorMaroon
|
||||
@@ -373,6 +411,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorMaroon
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorYellow
|
||||
@@ -385,6 +424,7 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorYellow
|
||||
groupBy: "towels"
|
||||
|
||||
- type: loadout
|
||||
id: TowelColorMime
|
||||
@@ -397,3 +437,4 @@
|
||||
storage:
|
||||
back:
|
||||
- TowelColorMime
|
||||
groupBy: "towels"
|
||||
|
||||
Reference in New Issue
Block a user