Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Content.Client/Content.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="_Goobstation\Power\" />
</ItemGroup>
<Folder Include="_Goobstation\Power\" />
</ItemGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
<Import Project="..\RobustToolbox\MSBuild\XamlIL.targets" />
</Project>
43 changes: 43 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Numerics;
using Content.Client.Humanoid;
using Content.Client.Lobby.UI.Loadouts;
using Content.Client._CD.Humanoid; // Allergies to work.
using Content.Client.Lobby.UI.Roles;
using Content.Client.Message;
using Content.Client.Players.PlayTimeTracking;
Expand Down Expand Up @@ -40,6 +41,9 @@
using Content.Shared._CD.Records;
// End CD - Character Records
using Content.Shared._DV.Traits; // DV - Traits
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent; // Allergies
using Content.Shared.FixedPoint; // Allergies

namespace Content.Client.Lobby.UI
{
Expand Down Expand Up @@ -118,6 +122,9 @@ public sealed partial class HumanoidProfileEditor : BoxContainer
private readonly RecordEditorGui _recordsTab;
// End CD - Station Records

// CD: Allergies Editor
private readonly AllergyPicker _allergiesTab;

[ValidatePrototypeId<GuideEntryPrototype>]
private static readonly ProtoId<GuideEntryPrototype> DefaultSpeciesGuidebook = "Species";

Expand Down Expand Up @@ -491,6 +498,13 @@ public HumanoidProfileEditor(
// Begin CD - Character Records
#region CosmaticRecords

// Begin CD - Allergies
_allergiesTab = new AllergyPicker(UpdateAllergies);
TabContainer.AddChild(_allergiesTab);
TabContainer.SetTabTitle(TabContainer.ChildCount - 1,
Loc.GetString("humanoid-profile-editor-cd-allergies-tab"));
// End CD - Allergies

_recordsTab = new RecordEditorGui(UpdateProfileRecords);
TabContainer.AddChild(_recordsTab);
TabContainer.SetTabTitle(TabContainer.ChildCount - 1, Loc.GetString("humanoid-profile-editor-cd-records-tab"));
Expand Down Expand Up @@ -908,6 +922,7 @@ public void SetProfile(HumanoidCharacterProfile? profile, int? slot)

// Begin CD - Character Records
UpdateHeightControls();
UpdateCDAllergies(); // CD Allergies
_recordsTab.Update(profile);
// End CD - Character Records

Expand Down Expand Up @@ -1222,6 +1237,15 @@ private void UpdateProfileRecords(PlayerProvidedCharacterRecords records)
}
// End CD - Character Records

// CD Allergies Editor
private void UpdateAllergies(Dictionary<ReagentPrototype, FixedPoint2> allergies)
{
Profile = Profile?.WithCDAllergies(allergies.Select(allergy => (allergy.Key.ID, allergy.Value))
.ToDictionary());
SetDirty();
}
// End CD Allergies

private void OnFlavorTextChange(string content)
{
if (Profile is null)
Expand Down Expand Up @@ -1586,6 +1610,25 @@ private void UpdateHeightControls()
}
// End CD - Character Records

// CD Allergies
private void UpdateCDAllergies()
{
if (Profile == null)
{
return;
}

var allergies = new Dictionary<ReagentPrototype, FixedPoint2>();
foreach (var entry in (Dictionary<string, FixedPoint2>) Profile.CDAllergies)
{
if (!_prototypeManager.TryIndex(entry.Key, out ReagentPrototype? reagent))
continue;
allergies.Add(reagent, entry.Value);
}
_allergiesTab.SetData(allergies);
}
// CD End

private void UpdateSpawnPriorityControls()
{
if (Profile == null)
Expand Down
29 changes: 29 additions & 0 deletions Content.Client/_CD/Humanoid/AllergyPicker.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<BoxContainer xmlns="https://spacestation14.io" Orientation="Vertical" HorizontalExpand="True" Margin="5">
<!-- Allergen lists -->
<BoxContainer Orientation="Horizontal" SeparationOverride="5" VerticalExpand="True">
<!-- Unused reagents -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<OptionButton Name="CReagentGroupButton" StyleClasses="OpenLeft" />
<LineEdit Name="CReagentSearch" PlaceHolder="{Loc 'cd-allergies-editor-search'}" />
<ItemList Name="CReagents" VerticalExpand="True" MinSize="275 250" />
</BoxContainer>

<BoxContainer Orientation="Vertical" Align="Center" MinSize="50 250">
<Button Name="CAllergyAdd" Text="+" />
<Button Name="CAllergyRemove" Text="-" />
</BoxContainer>

<!-- Current allergies -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<Label Text="{Loc 'cd-allergies-editor-allergies'}" />
<ItemList Name="CAllergies" VerticalExpand="True" MinSize="275 250" />
</BoxContainer>
</BoxContainer>

<!-- Allergy attributes -->
<BoxContainer Name="CAllergyAttributes" VerticalExpand="True">
<Label Text="{Loc 'cd-allergies-editor-intensity'}" />
<Control HorizontalExpand="True" />
<OptionButton Name="CIntensityButton" StyleClasses="OpenLeft" />
</BoxContainer>
</BoxContainer>
242 changes: 242 additions & 0 deletions Content.Client/_CD/Humanoid/AllergyPicker.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
using System.Collections.Immutable;
using System.Linq;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace Content.Client._CD.Humanoid;

[GenerateTypedNameReferences]
public sealed partial class AllergyPicker : BoxContainer
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;

private readonly Texture _textureWhite;

private readonly Action<Dictionary<ReagentPrototype, FixedPoint2>> _onUpdateAllergies;

private Dictionary<ReagentPrototype, FixedPoint2> _currentAllergies = new();

private ItemList.Item? _selectedAllergy;
private int _selectedReagentGroup;
private ItemList.Item? _selectedUnusedAllergy;

private readonly ImmutableList<(string, ImmutableList<ReagentPrototype>)> _reagentGroups;


// As hundredths
public enum Intensity
{
Mild = 0_50,
Moderate = 1_00,
Severe = 5_00,
Extreme = 100_00,
}

public AllergyPicker(Action<Dictionary<ReagentPrototype, FixedPoint2>> onUpdateAllergies)
{
_onUpdateAllergies = onUpdateAllergies;

RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);

var white = new Image<Rgba32>(32, 32);
for (var x = 0; x < 32; x++)
{
for (var y = 0; y < 32; y++)
{
white[x, y] = new Rgba32(255, 255, 255, 255);
}
}

_textureWhite = Texture.LoadFromImage(white);

_reagentGroups = _prototypeManager.EnumeratePrototypes<ReagentPrototype>()
.Select(reagent => reagent.Group)
.Distinct()
.Order()
.Select(group =>
{
var reagents = _prototypeManager.EnumeratePrototypes<ReagentPrototype>()
.Where(reagent => reagent.Group.Equals(group))
.OrderBy(reagent => reagent.LocalizedName)
.ToImmutableList();
return (group, reagents);
})
.Where(tuple => !tuple.reagents.IsEmpty)
.ToImmutableList();

PopulateIntensities();

CReagentGroupButton.OnItemSelected += OnGroupChange;
CReagentSearch.OnTextChanged += args => PopulateReagents(args.Text);

CReagents.OnItemSelected += item => _selectedUnusedAllergy = CReagents[item.ItemIndex];

CAllergyAdd.OnPressed += _ => AllergyAdd();
CAllergyRemove.OnPressed += _ => AllergyRemove();

CAllergies.OnItemSelected += OnAllergySelected;

CIntensityButton.OnItemSelected += args =>
{
if (CIntensityButton.IsItemDisabled(0))
CIntensityButton.RemoveItem(0);

CIntensityButton.SelectId(args.Id);
_currentAllergies[(ReagentPrototype)_selectedAllergy!.Metadata!] = FixedPoint2.FromCents(args.Id);
_onUpdateAllergies.Invoke(_currentAllergies);
};
}

private void PopulateIntensities(FixedPoint2? custom = null)
{
CIntensityButton.Clear();
if (custom is not null)
{
CIntensityButton.AddItem(custom.Value.ToString(), custom.Value.Value);
CIntensityButton.SetItemDisabled(0, true);
}
foreach (var level in Enum.GetValues<Intensity>())
{
CIntensityButton.AddItem(
Loc.GetString("cd-allergies-editor-intensity-" + Enum.GetName(level)!.ToLower()),
(int)level
);
}
}

private ItemList.Item GetReagentItem(ItemList list, ReagentPrototype reagent)
{
return new ItemList.Item(list)
{
Text = reagent.LocalizedName[0].ToString().ToUpper() + reagent.LocalizedName[1..],
Selectable = true,
Metadata = reagent,
Icon = _textureWhite,
IconModulate = reagent.SubstanceColor,
};
}

public void SetData(Dictionary<ReagentPrototype, FixedPoint2> newAllergies)
{
_currentAllergies = newAllergies;
PopulateReagents(CReagentSearch.Text);
PopulateAllergies();
}

private void SetupCategoryButtons()
{
CReagentGroupButton.Clear();

foreach (var (group, _) in _reagentGroups)
{
CReagentGroupButton.AddItem(group);
}

CReagentGroupButton.SelectId(_selectedReagentGroup);
}

private void PopulateReagents(string filter)
{
SetupCategoryButtons();

CReagents.Clear();
_selectedUnusedAllergy = null;

var sortedReagents = _reagentGroups[_selectedReagentGroup]
.Item2
.Where(m =>
m.ID.Contains(filter, StringComparison.CurrentCultureIgnoreCase) ||
m.LocalizedName.Contains(filter, StringComparison.CurrentCultureIgnoreCase)
);

foreach (var reagent in sortedReagents)
{
if (_currentAllergies.ContainsKey(reagent))
continue;

CReagents.Add(GetReagentItem(CReagents, reagent));
}
}

private void PopulateAllergies()
{
CAllergies.Clear();
CAllergyAttributes.Visible = false;
_selectedAllergy = null;

foreach (var reagent in _currentAllergies.Keys)
{
CAllergies.Add(GetReagentItem(CAllergies, reagent));
}
}

private void OnGroupChange(OptionButton.ItemSelectedEventArgs group)
{
CReagentGroupButton.SelectId(group.Id);
_selectedReagentGroup = group.Id;
PopulateReagents(CReagentSearch.Text);
PopulateAllergies();
}

private void OnAllergySelected(ItemList.ItemListSelectedEventArgs item)
{
_selectedAllergy = CAllergies[item.ItemIndex];
var intensity = _currentAllergies[(ReagentPrototype)_selectedAllergy.Metadata!];

if (CIntensityButton.IsItemDisabled(0))
CIntensityButton.RemoveItem(0);

if (!CIntensityButton.TrySelectId(intensity.Value))
{
PopulateIntensities(intensity);
CIntensityButton.SelectId(intensity.Value);
}

CAllergyAttributes.Visible = true;
}

private void AllergyAdd()
{
if (_selectedUnusedAllergy is null)
return;

var reagent = (ReagentPrototype)_selectedUnusedAllergy.Metadata!;
CReagents.Remove(_selectedUnusedAllergy);
_selectedUnusedAllergy = null;

_currentAllergies[reagent] = 1.0;
CAllergies.Add(GetReagentItem(CAllergies, reagent));

_onUpdateAllergies.Invoke(_currentAllergies);
}

private void AllergyRemove()
{
if (_selectedAllergy is null)
return;

var reagent = (ReagentPrototype)_selectedAllergy.Metadata!;

_currentAllergies.Remove(reagent);

CAllergies.Remove(_selectedAllergy);

if (reagent.Group == _reagentGroups[_selectedReagentGroup].Item1)
{
CReagents.Add(GetReagentItem(CReagents, reagent));
CReagents.SortItemsByText();
}

_selectedAllergy = null;
CAllergyAttributes.Visible = false;
_onUpdateAllergies.Invoke(_currentAllergies);
}
}
Empty file.
Loading
Loading