return;
}
- //Setup model
- Dictionary<string, List<string>> model = new();
+ // Setup model
+ Dictionary<string, List<string>> traitGroups = new();
List<string> defaultTraits = new();
- model.Add("default", defaultTraits);
+ traitGroups.Add(TraitCategoryPrototype.Default, defaultTraits);
foreach (var trait in traits)
{
continue;
}
- if (!model.ContainsKey(trait.Category))
- {
- model.Add(trait.Category, new());
- }
- model[trait.Category].Add(trait.ID);
+ if (!_prototypeManager.HasIndex(trait.Category))
+ continue;
+
+ var group = traitGroups.GetOrNew(trait.Category);
+ group.Add(trait.ID);
}
- //Create UI view from model
- foreach (var (categoryId, traitId) in model)
+ // Create UI view from model
+ foreach (var (categoryId, categoryTraits) in traitGroups)
{
TraitCategoryPrototype? category = null;
- if (categoryId != "default")
+
+ if (categoryId != TraitCategoryPrototype.Default)
{
category = _prototypeManager.Index<TraitCategoryPrototype>(categoryId);
// Label
List<TraitPreferenceSelector?> selectors = new();
var selectionCount = 0;
- foreach (var traitProto in traitId)
+ foreach (var traitProto in categoryTraits)
{
var trait = _prototypeManager.Index<TraitPrototype>(traitProto);
var selector = new TraitPreferenceSelector(trait);
selector.PreferenceChanged += preference =>
{
- Profile = Profile?.WithTraitPreference(trait.ID, categoryId, preference);
+ if (preference)
+ {
+ Profile = Profile?.WithTraitPreference(trait.ID, _prototypeManager);
+ }
+ else
+ {
+ Profile = Profile?.WithoutTraitPreference(trait.ID, _prototypeManager);
+ }
+
SetDirty();
RefreshTraits(); // If too many traits are selected, they will be reset to the real value.
};
};
}
- public HumanoidCharacterProfile WithTraitPreference(ProtoId<TraitPrototype> traitId, string? categoryId, bool pref)
+ public HumanoidCharacterProfile WithTraitPreference(ProtoId<TraitPrototype> traitId, IPrototypeManager protoManager)
{
- var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
- var traitProto = prototypeManager.Index(traitId);
+ // null category is assumed to be default.
+ if (!protoManager.TryIndex(traitId, out var traitProto))
+ return new(this);
- TraitCategoryPrototype? categoryProto = null;
- if (categoryId != null && categoryId != "default")
- categoryProto = prototypeManager.Index<TraitCategoryPrototype>(categoryId);
+ var category = traitProto.Category;
- var list = new HashSet<ProtoId<TraitPrototype>>(_traitPreferences);
+ // Category not found so dump it.
+ TraitCategoryPrototype? traitCategory = null;
- if (pref)
- {
- list.Add(traitId);
+ if (category != null && !protoManager.TryIndex(category, out traitCategory))
+ return new(this);
- if (categoryProto == null || categoryProto.MaxTraitPoints < 0)
- {
- return new(this)
- {
- _traitPreferences = list,
- };
- }
+ var list = new HashSet<ProtoId<TraitPrototype>>(_traitPreferences) { traitId };
- var count = 0;
- foreach (var trait in list)
+ if (traitCategory == null || traitCategory.MaxTraitPoints < 0)
+ {
+ return new(this)
{
- var traitProtoTemp = prototypeManager.Index(trait);
- count += traitProtoTemp.Cost;
- }
+ _traitPreferences = list,
+ };
+ }
- if (count > categoryProto.MaxTraitPoints && traitProto.Cost != 0)
+ var count = 0;
+ foreach (var trait in list)
+ {
+ // If trait not found or another category don't count its points.
+ if (!protoManager.TryIndex<TraitPrototype>(trait, out var otherProto) ||
+ otherProto.Category != traitCategory)
{
- return new(this)
- {
- _traitPreferences = _traitPreferences,
- };
+ continue;
}
+
+ count += otherProto.Cost;
}
- else
+
+ if (count > traitCategory.MaxTraitPoints && traitProto.Cost != 0)
{
- list.Remove(traitId);
+ return new(this);
}
return new(this)
};
}
+ public HumanoidCharacterProfile WithoutTraitPreference(ProtoId<TraitPrototype> traitId, IPrototypeManager protoManager)
+ {
+ var list = new HashSet<ProtoId<TraitPrototype>>(_traitPreferences);
+ list.Remove(traitId);
+
+ return new(this)
+ {
+ _traitPreferences = list,
+ };
+ }
+
public string Summary =>
Loc.GetString(
"humanoid-character-profile-summary",
_antagPreferences.UnionWith(antags);
_traitPreferences.Clear();
- _traitPreferences.UnionWith(traits);
+ _traitPreferences.UnionWith(GetValidTraits(traits, prototypeManager));
// Checks prototypes exist for all loadouts and dump / set to default if not.
var toRemove = new ValueList<string>();
}
}
+ /// <summary>
+ /// Takes in an IEnumerable of traits and returns a List of the valid traits.
+ /// </summary>
+ public List<ProtoId<TraitPrototype>> GetValidTraits(IEnumerable<ProtoId<TraitPrototype>> traits, IPrototypeManager protoManager)
+ {
+ // Track points count for each group.
+ var groups = new Dictionary<string, int>();
+ var result = new List<ProtoId<TraitPrototype>>();
+
+ foreach (var trait in traits)
+ {
+ if (!protoManager.TryIndex(trait, out var traitProto))
+ continue;
+
+ // Always valid.
+ if (traitProto.Category == null)
+ {
+ result.Add(trait);
+ continue;
+ }
+
+ // No category so dump it.
+ if (!protoManager.TryIndex(traitProto.Category, out var category))
+ continue;
+
+ var existing = groups.GetOrNew(category.ID);
+ existing += traitProto.Cost;
+
+ // Too expensive.
+ if (existing > category.MaxTraitPoints)
+ continue;
+
+ groups[category.ID] = existing;
+ result.Add(trait);
+ }
+
+ return result;
+ }
+
public ICharacterProfile Validated(ICommonSession session, IDependencyCollection collection)
{
var profile = new HumanoidCharacterProfile(this);