Skip to content

Commit

Permalink
EE Merge (#200)
Browse files Browse the repository at this point in the history
this adds everything

:cl: EE Contributors
- add: Added Tajara and related content
- add: Add Batonbot
- add: Add Disablerbot
- add: Modsuits have been ported from Goobstation!
- add: A new ChemMaster experience has been granted to the people of
Einstein Engines. Includes a pill buffer!
- add: Added a new species, the Chitinid.
- tweak: Kill random person objective has been replaced by teaching them
a lesson, removing the need to RR a random person.
- add: Added playing cards. You may get one in the Games Vendor or as an
item
in your loadout.
- add: Engineering Hardsuits, Maxim Hardsuit, and Cybersun's Elite
Tacsuit now all make the wearer immune to atmos fires. Have fun walking
directly into the supermatter engine. Play out your heroic engineer
fantasy by dragging the supermatter crystal to space in order to save
the station.
- add: The Plasmaman species has arrived! They need to breathe plasma to
live, and a special jumpsuit to prevent oxygen from igniting them. In
exchange, they deal formidable unarmed Heat damage, are never hungry nor
thirsty, and are immune to cold and radiation damage. Read more about
Plasmamen in their Guidebook entry.
- tweak: Internals are no longer toggled off if you take your helmet off
but still have a gas mask on and vice versa.
- tweak: Paradox Anomalies will now spawn with the original person's
Loadout items.
- fix: Fixed prisoners not being able to have custom Loadout names and
descriptions, and heirlooms if they didn't have a backpack when joining.
- add: New hairstyles have arrived, including all Goob LRP-original
hairstyles, Pulato, new facial hair and more!
- add: Added epic IPC wings and Plasmaman wings. 
- add: Added the Iron Jaw face marking.
- tweak: Increased the maximum number of Reptilian chest markings to 3.
- tweak: Vox is now playable again.
- fix: Harpy, Arachne and Lamia can no longer pick the "No Ears" marking
which had no effect as they had no default ear markings.
- add: Ported Goob mechs
- fix: Fixed Diona not respecting previous character profile.
  • Loading branch information
sleepyyapril authored Jan 26, 2025
2 parents 1169029 + d8f00c5 commit b0a336d
Show file tree
Hide file tree
Showing 1,399 changed files with 27,675 additions and 797 deletions.
6 changes: 1 addition & 5 deletions Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ protected override void Open()
// Setup static button actions.
_window.InputEjectButton.OnPressed += _ => SendMessage(
new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName));
_window.OutputEjectButton.OnPressed += _ => SendMessage(
new ItemSlotButtonPressedEvent(SharedChemMaster.OutputSlotName));
_window.BufferTransferButton.OnPressed += _ => SendMessage(
new ChemMasterSetModeMessage(ChemMasterMode.Transfer));
_window.BufferDiscardButton.OnPressed += _ => SendMessage(
Expand All @@ -49,11 +47,9 @@ protected override void Open()
_window.PillTypeButtons[i].OnPressed += _ => SendMessage(new ChemMasterSetPillTypeMessage(pillType));
}

_window.OnReagentButtonPressed += (_, button, amount) => SendMessage(new ChemMasterReagentAmountButtonMessage(button.Id, amount, button.IsBuffer));
_window.OnReagentButtonPressed += (_, button, amount, isOutput) => SendMessage(new ChemMasterReagentAmountButtonMessage(button.Id, amount, button.IsBuffer, isOutput));
_window.OnSortMethodChanged += sortMethod => SendMessage(new ChemMasterSortMethodUpdated(sortMethod));
_window.OnTransferAmountChanged += amount => SendMessage(new ChemMasterTransferringAmountUpdated(amount));


}

/// <summary>
Expand Down
237 changes: 124 additions & 113 deletions Content.Client/Chemistry/UI/ChemMasterWindow.xaml

Large diffs are not rendered by default.

229 changes: 173 additions & 56 deletions Content.Client/Chemistry/UI/ChemMasterWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ namespace Content.Client.Chemistry.UI
public sealed partial class ChemMasterWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public event Action<BaseButton.ButtonEventArgs, ReagentButton, int>? OnReagentButtonPressed;
public event Action<BaseButton.ButtonEventArgs, ReagentButton, int, bool>? OnReagentButtonPressed;
public event Action<int>? OnAmountButtonPressed;
public event Action<int>? OnSortMethodChanged;
public event Action<int>? OnTransferAmountChanged;
public readonly Button[] PillTypeButtons;

private Dictionary<string, ReagentCached> _reagents;
private const string TransferringAmountColor = "#ffa500";
private const string TransferringAmountColor = "#ffffff";
private ReagentSortMethod _currentSortMethod = ReagentSortMethod.Alphabetical;
private ChemMasterBoundUserInterfaceState? _lastState;
private string _lastAmountText = "50";
private int _transferAmount = 50;

private bool _isOutput = false;

private const string PillsRsiPath = "/Textures/Objects/Specific/Chemistry/pills.rsi";

Expand All @@ -50,12 +50,9 @@ public ChemMasterWindow()
IoCManager.InjectDependencies(this);

_reagents = new();

InputAmountLineEdit.OnTextEntered += SetAmount;
InputAmountLineEdit.OnFocusExit += SetAmount;

OutputAmountLineEdit.OnTextEntered += SetAmount;
OutputAmountLineEdit.OnFocusExit += SetAmount;
AmountLabel.HorizontalAlignment = HAlignment.Center;
AmountLineEdit.OnTextEntered += SetAmount;
AmountLineEdit.OnFocusExit += SetAmount;

// Pill type selection buttons, in total there are 20 pills.
// Pill rsi file should have states named as pill1, pill2, and so on.
Expand Down Expand Up @@ -110,12 +107,63 @@ public ChemMasterWindow()
SortMethod.AddItem(
Loc.GetString("chem-master-window-sort-method-Alphabetical-text"),
(int) ReagentSortMethod.Alphabetical);
SortMethod.AddItem(Loc.GetString("chem-master-window-sort-method-Amount-text"), (int) ReagentSortMethod.Amount);
SortMethod.AddItem(Loc.GetString("chem-master-window-sort-method-Time-text"), (int) ReagentSortMethod.Time);

SortMethod.AddItem(
Loc.GetString("chem-master-window-sort-method-Amount-text"),
(int) ReagentSortMethod.Amount);

SortMethod.AddItem(
Loc.GetString("chem-master-window-sort-method-Time-text"),
(int) ReagentSortMethod.Time);

SortMethod.OnItemSelected += HandleChildPressed;

PillSortMethod.AddItem(
Loc.GetString(
"chem-master-window-sort-method-Alphabetical-text"),
(int) ReagentSortMethod.Alphabetical);
PillSortMethod.AddItem(Loc.GetString(
"chem-master-window-sort-method-Amount-text"),
(int) ReagentSortMethod.Amount);
PillSortMethod.AddItem(
Loc.GetString("chem-master-window-sort-method-Time-text"),
(int) ReagentSortMethod.Time);

PillSortMethod.OnItemSelected += HandleChildPressed;

BufferTransferButton.OnPressed += HandleDiscardTransferPress;
BufferDiscardButton.OnPressed += HandleDiscardTransferPress;

var amounts = new List<int>()
{
1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 125, 150, 175, 200, 225, 250, 275, 300, 500
};

for (int i = 0; i < amounts.Count; i++)
{
var styleClass = StyleBase.ButtonOpenBoth;
var amount = amounts[i];
var columns = AmountButtons.Columns;

if (i == 0 || i % columns == 0)
styleClass = StyleBase.ButtonOpenRight;

if ((i + 1) % columns == 0)
styleClass = StyleBase.ButtonOpenLeft;

var button = new Button()
{
Text = amount.ToString(),
MinSize = new(10, 10),
StyleClasses = { styleClass },
HorizontalExpand = true
};

button.OnPressed += _ => OnAmountButtonPressed?.Invoke(amount);
AmountButtons.AddChild(button);
}

OnAmountButtonPressed += amount => SetAmountText(amount.ToString());
}

private void HandleDiscardTransferPress(BaseButton.ButtonEventArgs args)
Expand All @@ -137,6 +185,8 @@ private void HandleSortMethodChange(int newSortMethod)

_currentSortMethod = (ReagentSortMethod) newSortMethod;
SortMethod.SelectId(newSortMethod);
PillSortMethod.SelectId(newSortMethod);

SortUpdated();
}

Expand All @@ -158,12 +208,10 @@ private bool ValidateAmount(string newText)
{
if (string.IsNullOrWhiteSpace(newText) || !int.TryParse(newText, out int amount))
{
InputAmountLineEdit.SetText(string.Empty);
OutputAmountLineEdit.SetText(string.Empty);
AmountLineEdit.SetText(string.Empty);
return false;
}

_lastAmountText = newText;
_transferAmount = amount;
OnTransferAmountChanged?.Invoke(amount);
return true;
Expand All @@ -174,29 +222,23 @@ private void SetAmount(LineEdit.LineEditEventArgs args) =>

private void SetAmountText(string newText)
{
if (newText == _lastAmountText)
return;

if (!ValidateAmount(newText))
if (newText == _transferAmount.ToString() || !ValidateAmount(newText))
return;

var localizedAmount = Loc.GetString(
"chem-master-window-transferring-label",
("quantity", newText),
("color", TransferringAmountColor));

InputAmountLabel.Text = localizedAmount;
OutputAmountLabel.Text = localizedAmount;

InputAmountLineEdit.SetText(string.Empty);
OutputAmountLineEdit.SetText(string.Empty);
AmountLabel.Text = localizedAmount;
AmountLineEdit.SetText(string.Empty);
}

private ReagentButton MakeReagentButton(string text, ReagentId id, bool isBuffer)
{
var reagentTransferButton = new ReagentButton(text, id, isBuffer);
reagentTransferButton.OnPressed += args
=> OnReagentButtonPressed?.Invoke(args, reagentTransferButton, _transferAmount);
=> OnReagentButtonPressed?.Invoke(args, reagentTransferButton, _transferAmount, Tabs.CurrentTab == 1);
return reagentTransferButton;
}
/// <summary>
Expand Down Expand Up @@ -237,60 +279,49 @@ public void UpdateState(BoundUserInterfaceState state)
HandleSortMethodChange(castState.SortMethod);
SetAmountText(castState.TransferringAmount.ToString());

BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
BufferCurrentVolume.Text = $" {castState.PillBufferCurrentVolume?.Int() ?? 0}u";

InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null;
CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null;
InputEjectButton.Disabled = castState.ContainerInfo is null;
CreateBottleButton.Disabled = castState.PillBufferReagents.Count == 0;
CreatePillButton.Disabled = castState.PillBufferReagents.Count == 0;

UpdateDosageFields(castState);
}

private FixedPoint2 CurrentStateBufferVolume(ChemMasterBoundUserInterfaceState state) =>
(Tabs.CurrentTab == 0 ? state.BufferCurrentVolume : state.PillBufferCurrentVolume) ?? 0;

//assign default values for pill and bottle fields.
private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState)
{
var output = castState.OutputContainerInfo;
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
var holdsReagents = output?.Reagents != null;
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;

PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
var bufferVolume = castState.PillBufferCurrentVolume?.Int() ?? 0;
PillDosage.Value = (int) Math.Min(bufferVolume, castState.PillDosageLimit);

PillTypeButtons[castState.SelectedPillType].Pressed = true;
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
PillNumber.IsValid = x => x >= 0;
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
BottleDosage.IsValid = x => x >= 0 && x <= bottleAmountMax;

if (PillNumber.Value > pillNumberMax)
PillNumber.Value = pillNumberMax;
if (BottleDosage.Value > bottleAmountMax)
BottleDosage.Value = bottleAmountMax;
BottleDosage.IsValid = x => x >= 0;

// Avoid division by zero
if (PillDosage.Value > 0)
{
PillNumber.Value = Math.Min(bufferVolume / PillDosage.Value, pillNumberMax);
}
PillNumber.Value = bufferVolume / PillDosage.Value;
else
{
PillNumber.Value = 0;
}

BottleDosage.Value = Math.Min(bottleAmountMax, bufferVolume);
BottleDosage.Value = bufferVolume;
}
/// <summary>
/// Generate a product label based on reagents in the buffer.
/// </summary>
/// <param name="state">State data sent by the server.</param>
private string GenerateLabel(ChemMasterBoundUserInterfaceState state)
{
if (state.BufferCurrentVolume == 0)
if (CurrentStateBufferVolume(state) == 0)
return "";

var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First().Reagent;
var buffer = Tabs.CurrentTab == 0 ? state.BufferReagents : state.PillBufferReagents;
var reagent = buffer.OrderBy(r => r.Quantity).First().Reagent;

_prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
return proto?.LocalizedName ?? "";
}
Expand All @@ -304,15 +335,21 @@ private void UpdatePanelInfo(ChemMasterBoundUserInterfaceState state)
BufferTransferButton.Pressed = state.Mode == ChemMasterMode.Transfer;
BufferDiscardButton.Pressed = state.Mode == ChemMasterMode.Discard;

BuildContainerUI(InputContainerInfo, state.InputContainerInfo, true);
BuildContainerUI(OutputContainerInfo, state.OutputContainerInfo, false);
PillBufferTransferButton.Pressed = state.Mode == ChemMasterMode.Transfer;
PillBufferDiscardButton.Pressed = state.Mode == ChemMasterMode.Discard;

BuildContainerUI(ContainerInfoContainer, state.ContainerInfo, true);
BuildBufferInfo(state);
BuildPillBufferInfo(state);
}

private void BuildBufferInfo(ChemMasterBoundUserInterfaceState state)
{
BufferInfo.Children.Clear();

if (!state.BufferReagents.Any())
{
BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });

return;
}

Expand Down Expand Up @@ -386,6 +423,86 @@ private void UpdatePanelInfo(ChemMasterBoundUserInterfaceState state)
}
}

private void BuildPillBufferInfo(ChemMasterBoundUserInterfaceState state)
{
PillBufferInfo.Children.Clear();

if (!state.PillBufferReagents.Any())
{
PillBufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });
return;
}

var bufferHBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
PillBufferInfo.AddChild(bufferHBox);

var bufferLabel = new Label { Text = $"{Loc.GetString("chem-master-window-buffer-label")} " };
bufferHBox.AddChild(bufferLabel);
var bufferVol = new Label
{
Text = $"{state.PillBufferCurrentVolume}u",
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
};
bufferHBox.AddChild(bufferVol);

// initialises rowCount to allow for striped rows
var rowCount = 0;
var bufferReagents = state.PillBufferReagents.OrderBy(x => x.Reagent.Prototype);

if (_currentSortMethod == ReagentSortMethod.Amount)
bufferReagents = bufferReagents.OrderByDescending(x => x.Quantity);

if (_currentSortMethod == ReagentSortMethod.Time)
{
bufferReagents = bufferReagents.OrderByDescending(
x =>
{
var exists = _reagents.TryGetValue(x.Reagent.Prototype, out var reagent);
return exists && reagent != null ? reagent.TimeAdded : DateTimeOffset.UtcNow;
});
}

var bufferAsNames = bufferReagents.Select(r => r.Reagent.Prototype).ToHashSet();
var hashSetCachedReagents = _reagents.Keys.ToHashSet();
hashSetCachedReagents.ExceptWith(bufferAsNames);

foreach (var missing in hashSetCachedReagents)
_reagents.Remove(missing);

foreach (var (reagent, quantity) in bufferReagents)
{
var reagentId = reagent;
_prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color);
PillBufferInfo.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagentId, quantity, true, true));

var exists = _reagents.TryGetValue(reagent.Prototype, out var reagentCached);

if (!exists)
{
reagentCached = new()
{
Id = reagentId,
Quantity = quantity,
TimeAdded = reagentCached?.TimeAdded ?? DateTimeOffset.UtcNow
};

_reagents.Add(reagentId.Prototype, reagentCached);
}
else
{
reagentCached!.Quantity = quantity;
reagentCached!.Id = reagentId;

_reagents[reagentId.Prototype] = reagentCached;
}
}
}

private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
{
control.Children.Clear();
Expand Down
Loading

0 comments on commit b0a336d

Please sign in to comment.