Skip to content

Commit

Permalink
Merge remote-tracking branch 'wizard/master' into upstream-sync
Browse files Browse the repository at this point in the history
  • Loading branch information
Rxup committed Sep 21, 2023
2 parents fe54567 + d888d9a commit daca9fe
Show file tree
Hide file tree
Showing 47 changed files with 693 additions and 295 deletions.
23 changes: 14 additions & 9 deletions Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,31 +110,36 @@ public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessag
}

var player = _playerManager.LocalPlayer?.Session;

if (player == null)
return true;

var reasonBuilder = new StringBuilder();
return CheckRoleTime(job.Requirements, out reason);
}

public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(false)] out FormattedMessage? reason)
{
reason = null;

if (requirements == null)
return true;

foreach (var requirement in job.Requirements)
var reasons = new List<string>();
foreach (var requirement in requirements)
{
if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes))
continue;

reasonBuilder.AppendLine(jobReason.ToMarkup());
reasons.Add(jobReason.ToMarkup());
}

//start-backmen: whitelist
if (job.WhitelistRequired && _cfg.GetCVar(Shared.Backmen.CCVar.CCVars.WhitelistRolesEnabled) && !_whitelisted)
{
if (reasonBuilder.Length > 0)
reasonBuilder.Append('\n');

reasonBuilder.AppendLine(Loc.GetString("playtime-deny-reason-not-whitelisted"));
reasons.Add(Loc.GetString("playtime-deny-reason-not-whitelisted"));
}
//end-backmen: whitelist

reason = reasonBuilder.Length == 0 ? null : FormattedMessage.FromMarkup(reasonBuilder.ToString().Trim());
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons));
return reason == null;
}
}
207 changes: 108 additions & 99 deletions Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,13 +403,16 @@ public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IProt
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 =>
{
Expand Down Expand Up @@ -597,19 +600,15 @@ private void UpdateRoleRequirements()
foreach (var jobSelector in _jobPriorities)
{
// Sync other selectors with the same job in case of multiple department jobs
if (jobSelector.Job == selector.Job)
if (jobSelector.Proto == selector.Proto)
{
jobSelector.Priority = priority;
}

// Lower any other high priorities to medium.
if (priority == JobPriority.High)
else if (priority == JobPriority.High && jobSelector.Priority == JobPriority.High)
{
if (jobSelector.Job != selector.Job && jobSelector.Priority == JobPriority.High)
{
jobSelector.Priority = JobPriority.Medium;
Profile = Profile?.WithJobPriority(jobSelector.Job.ID, JobPriority.Medium);
}
// Lower any other high priorities to medium.
jobSelector.Priority = JobPriority.Medium;
Profile = Profile?.WithJobPriority(jobSelector.Proto.ID, JobPriority.Medium);
}
}
};
Expand Down Expand Up @@ -1151,63 +1150,37 @@ private void UpdateJobPriorities()
{
foreach (var prioritySelector in _jobPriorities)
{
var jobId = prioritySelector.Job.ID;
var jobId = prioritySelector.Proto.ID;

var priority = Profile?.JobPriorities.GetValueOrDefault(jobId, JobPriority.Never) ?? JobPriority.Never;

prioritySelector.Priority = priority;
}
}

private sealed class JobPrioritySelector : Control
private abstract class RequirementsSelector<T> : Control
{
public JobPrototype Job { get; }
private readonly RadioOptions<int> _optionButton;

public JobPriority Priority
{
get => (JobPriority) _optionButton.SelectedValue;
set => _optionButton.SelectByValue((int) value);
}

public event Action<JobPriority>? PriorityChanged;
public T Proto { get; }
public bool Disabled => _lockStripe.Visible;

protected readonly RadioOptions<int> Options;
private StripeBack _lockStripe;
private Label _requirementsLabel;
private Label _jobTitle;

public JobPrioritySelector(JobPrototype job, IPrototypeManager prototypeManager)
protected RequirementsSelector(T proto)
{
Job = job;
Proto = proto;

_optionButton = new RadioOptions<int>(RadioOptionsLayout.Horizontal)
Options = new RadioOptions<int>(RadioOptionsLayout.Horizontal)
{
FirstButtonStyle = StyleBase.ButtonOpenRight,
ButtonStyle = StyleBase.ButtonOpenBoth,
LastButtonStyle = StyleBase.ButtonOpenLeft
};
//Override default radio option button width
_optionButton.GenerateItem = GenerateButton;
// Text, Value
_optionButton.AddItem(Loc.GetString("humanoid-profile-editor-job-priority-high-button"), (int) JobPriority.High);
_optionButton.AddItem(Loc.GetString("humanoid-profile-editor-job-priority-medium-button"), (int) JobPriority.Medium);
_optionButton.AddItem(Loc.GetString("humanoid-profile-editor-job-priority-low-button"), (int) JobPriority.Low);
_optionButton.AddItem(Loc.GetString("humanoid-profile-editor-job-priority-never-button"), (int) JobPriority.Never);

_optionButton.OnItemSelected += args =>
{
_optionButton.Select(args.Id);
PriorityChanged?.Invoke(Priority);
};

var icon = new TextureRect
{
TextureScale = new Vector2(2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
};
Options.GenerateItem = GenerateButton;

var jobIcon = prototypeManager.Index<StatusIconPrototype>(job.Icon);
icon.Texture = jobIcon.Icon.Frame0();
Options.OnItemSelected += args => Options.Select(args.Id);

_requirementsLabel = new Label()
{
Expand All @@ -1228,30 +1201,40 @@ public JobPrioritySelector(JobPrototype job, IPrototypeManager prototypeManager)
}
};

_jobTitle = new Label()
{
Margin = new Thickness(5f,0,5f,0),
Text = job.LocalizedName,
MinSize = new Vector2(200, 0),
MouseFilter = MouseFilterMode.Stop
};
// Setup must be called after
}

if (job.LocalizedDescription != null)
/// <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)
{
_jobTitle.ToolTip = job.LocalizedDescription;
Options.AddItem(Loc.GetString(text), value);
}

AddChild(new BoxContainer
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,
Children =
{
icon,
_jobTitle,
_optionButton,
_lockStripe,
}
});
};

if (icon != null)
container.AddChild(icon);
container.AddChild(titleLabel);
container.AddChild(Options);
container.AddChild(_lockStripe);

AddChild(container);
}

public void LockRequirements(FormattedMessage requirements)
Expand All @@ -1260,35 +1243,67 @@ public void LockRequirements(FormattedMessage requirements)
tooltip.SetMessage(requirements);
_lockStripe.TooltipSupplier = _ => tooltip;
_lockStripe.Visible = true;
_optionButton.Visible = false;
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()
{
_requirementsLabel.Visible = false;
_lockStripe.Visible = false;
_optionButton.Visible = true;
Options.Visible = true;
}

private Button GenerateButton(string text, int value)
{
var btn = new Button
return new Button
{
Text = text,
MinWidth = 90
};
return btn;
}
}

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),
Stretch = TextureRect.StretchMode.KeepCentered
};
var jobIcon = protoMan.Index<StatusIconPrototype>(proto.Icon);
icon.Texture = jobIcon.Icon.Frame0();

Setup(items, proto.LocalizedName, 200, proto.LocalizedDescription, icon);
}
}

private void UpdateAntagPreferences()
{
foreach (var preferenceSelector in _antagPreferences)
{
var antagId = preferenceSelector.Antag.ID;
var antagId = preferenceSelector.Proto.ID;
var preference = Profile?.AntagPreferences.Contains(antagId) ?? false;

preferenceSelector.Preference = preference;
}
}
Expand All @@ -1304,44 +1319,38 @@ private void UpdateTraitPreferences()
}
}

private sealed class AntagPreferenceSelector : Control
private sealed class AntagPreferenceSelector : RequirementsSelector<AntagPrototype>
{
public AntagPrototype Antag { get; }
private readonly CheckBox _checkBox;

// 0 is yes and 1 is no
public bool Preference
{
get => _checkBox.Pressed;
set => _checkBox.Pressed = value;
get => Options.SelectedValue == 0;
set => Options.Select((value && !Disabled) ? 0 : 1);
}

public event Action<bool>? PreferenceChanged;

public AntagPreferenceSelector(AntagPrototype antag)
public AntagPreferenceSelector(AntagPrototype proto)
: base(proto)
{
Antag = antag;

_checkBox = new CheckBox {Text = Loc.GetString(antag.Name)};
_checkBox.OnToggled += OnCheckBoxToggled;
Options.OnItemSelected += args => PreferenceChanged?.Invoke(Preference);

if (antag.Description != null)
var items = new[]
{
_checkBox.ToolTip = Loc.GetString(antag.Description);
}

AddChild(new BoxContainer
("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))
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
_checkBox
}
});
}

private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
{
PreferenceChanged?.Invoke(Preference);
LockRequirements(reason);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
Access="Public"
Text="{Loc 'ghost-roles-window-request-role-button'}"
StyleClasses="OpenRight"
HorizontalAlignment="Left"/>
HorizontalAlignment="Left"
SetWidth="150"/>
<Button Name="FollowButton"
Access="Public"
Text="{Loc 'ghost-roles-window-follow-role-button'}"
StyleClasses="OpenLeft"
HorizontalAlignment="Right"/>
HorizontalAlignment="Right"
SetWidth="150"/>
</BoxContainer>
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'ghost-roles-window-title'}">
Title="{Loc 'ghost-roles-window-title'}"
MinSize="500 300"
SetSize="500 300">
<BoxContainer Orientation="Vertical"
HorizontalExpand="True">
<RichTextLabel Name="TopBanner" VerticalExpand="True"/>
Expand Down
Loading

0 comments on commit daca9fe

Please sign in to comment.