Client LuaCsForBarotrauma
CharacterTalent.cs
2 using System;
3 using System.Collections.Generic;
4 
5 namespace Barotrauma
6 {
8  {
9  public Character Character { get; }
10  public string DebugIdentifier { get; }
11 
12  public readonly TalentPrefab Prefab;
13 
14  public bool AddedThisRound = true;
15 
16  private readonly Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>> characterAbilityGroupEffectDictionary = new Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>>();
17 
18  private readonly List<CharacterAbilityGroupInterval> characterAbilityGroupIntervals = new List<CharacterAbilityGroupInterval>();
19 
20  // works functionally but a missing recipe is not represented on GUI side. this might be better placed in the character class itself, though it might be fine here as well
21  public List<Identifier> UnlockedRecipes { get; } = new List<Identifier>();
22  public List<Identifier> UnlockedStoreItems { get; } = new List<Identifier>();
23 
24  public CharacterTalent(TalentPrefab talentPrefab, Character character)
25  {
26  Character = character ?? throw new ArgumentNullException(nameof(character));
27  Prefab = talentPrefab ?? throw new ArgumentNullException(nameof(talentPrefab));
28  var element = talentPrefab.ConfigElement;
29  DebugIdentifier = talentPrefab.OriginalName;
30 
31  foreach (var subElement in element.Elements())
32  {
33  switch (subElement.Name.ToString().ToLowerInvariant())
34  {
35  case "abilitygroupeffect":
36  LoadAbilityGroupEffect(subElement);
37  break;
38  case "abilitygroupinterval":
39  LoadAbilityGroupInterval(subElement);
40  break;
41  case "addedrecipe":
42  if (subElement.GetAttributeIdentifier("itemidentifier", Identifier.Empty) is { IsEmpty: false } recipeIdentifier)
43  {
44  UnlockedRecipes.Add(recipeIdentifier);
45  }
46  else
47  {
48  DebugConsole.ThrowError($"No recipe identifier defined for talent {DebugIdentifier}",
49  contentPackage: element.ContentPackage);
50  }
51  break;
52  case "addedstoreitem":
53  if (subElement.GetAttributeIdentifier("itemtag", Identifier.Empty) is { IsEmpty: false } storeItemTag)
54  {
55  UnlockedStoreItems.Add(storeItemTag);
56  }
57  else
58  {
59  DebugConsole.ThrowError($"No store item identifier defined for talent {DebugIdentifier}",
60  contentPackage: element.ContentPackage);
61  }
62  break;
63  }
64  }
65  }
66 
67  public virtual void UpdateTalent(float deltaTime)
68  {
69  foreach (var characterAbilityGroupInterval in characterAbilityGroupIntervals)
70  {
71  characterAbilityGroupInterval.UpdateAbilityGroup(deltaTime);
72  }
73  }
74 
75  private static readonly HashSet<Identifier> checkedNonStackableTalents = new();
76 
80  public static void CheckTalentsForCrew(IEnumerable<Character> crew, AbilityEffectType type, AbilityObject abilityObject)
81  {
82  checkedNonStackableTalents.Clear();
83  foreach (Character character in crew)
84  {
85  foreach (CharacterTalent characterTalent in character.CharacterTalents)
86  {
87  if (!characterTalent.Prefab.AbilityEffectsStackWithSameTalent)
88  {
89  if (checkedNonStackableTalents.Contains(characterTalent.Prefab.Identifier)) { continue; }
90  checkedNonStackableTalents.Add(characterTalent.Prefab.Identifier);
91  }
92 
93  characterTalent.CheckTalent(type, abilityObject);
94  }
95  }
96  }
97 
98  public void CheckTalent(AbilityEffectType abilityEffectType, AbilityObject abilityObject)
99  {
100  if (characterAbilityGroupEffectDictionary.TryGetValue(abilityEffectType, out var characterAbilityGroups))
101  {
102  foreach (var characterAbilityGroup in characterAbilityGroups)
103  {
104  characterAbilityGroup.CheckAbilityGroup(abilityObject);
105  }
106  }
107  }
108 
109  public void ActivateTalent(bool addingFirstTime)
110  {
111  foreach (var characterAbilityGroups in characterAbilityGroupEffectDictionary.Values)
112  {
113  foreach (var characterAbilityGroup in characterAbilityGroups)
114  {
115  characterAbilityGroup.ActivateAbilityGroup(addingFirstTime);
116  }
117  }
118  }
119 
120  // XML logic
121  private void LoadAbilityGroupInterval(ContentXElement abilityGroup)
122  {
123  characterAbilityGroupIntervals.Add(new CharacterAbilityGroupInterval(AbilityEffectType.Undefined, this, abilityGroup));
124  }
125 
126  private void LoadAbilityGroupEffect(ContentXElement abilityGroup)
127  {
128  AbilityEffectType abilityEffectType = ParseAbilityEffectType(this, abilityGroup.GetAttributeString("abilityeffecttype", "none"));
129  AddAbilityGroupEffect(new CharacterAbilityGroupEffect(abilityEffectType, this, abilityGroup), abilityEffectType);
130  }
131 
132  public void AddAbilityGroupEffect(CharacterAbilityGroupEffect characterAbilityGroup, AbilityEffectType abilityEffectType = AbilityEffectType.None)
133  {
134  if (characterAbilityGroupEffectDictionary.TryGetValue(abilityEffectType, out var characterAbilityList))
135  {
136  characterAbilityList.Add(characterAbilityGroup);
137  }
138  else
139  {
140  List<CharacterAbilityGroupEffect> characterAbilityGroups = new List<CharacterAbilityGroupEffect>();
141  characterAbilityGroups.Add(characterAbilityGroup);
142  characterAbilityGroupEffectDictionary.Add(abilityEffectType, characterAbilityGroups);
143  }
144  }
145 
146  public static AbilityEffectType ParseAbilityEffectType(CharacterTalent characterTalent, string abilityEffectTypeString)
147  {
148  if (!Enum.TryParse(abilityEffectTypeString, true, out AbilityEffectType abilityEffectType))
149  {
150  DebugConsole.ThrowError("Invalid ability effect type \"" + abilityEffectTypeString + "\" in CharacterTalent (" + characterTalent.DebugIdentifier + ")",
151  contentPackage: characterTalent?.Prefab?.ContentPackage);
152  }
153  if (abilityEffectType == AbilityEffectType.Undefined)
154  {
155  DebugConsole.ThrowError("Ability effect type not defined in CharacterTalent (" + characterTalent.DebugIdentifier + ")",
156  contentPackage: characterTalent?.Prefab?.ContentPackage);
157  }
158 
159  return abilityEffectType;
160  }
161  }
162 }
IReadOnlyCollection< CharacterTalent > CharacterTalents
readonly TalentPrefab Prefab
List< Identifier > UnlockedRecipes
CharacterTalent(TalentPrefab talentPrefab, Character character)
void AddAbilityGroupEffect(CharacterAbilityGroupEffect characterAbilityGroup, AbilityEffectType abilityEffectType=AbilityEffectType.None)
static AbilityEffectType ParseAbilityEffectType(CharacterTalent characterTalent, string abilityEffectTypeString)
List< Identifier > UnlockedStoreItems
void ActivateTalent(bool addingFirstTime)
static void CheckTalentsForCrew(IEnumerable< Character > crew, AbilityEffectType type, AbilityObject abilityObject)
Checks talents for a given AbilityObject taking into account non-stackable talents.
void CheckTalent(AbilityEffectType abilityEffectType, AbilityObject abilityObject)
virtual void UpdateTalent(float deltaTime)
ContentPackage? ContentPackage
Definition: Prefab.cs:37
readonly Identifier Identifier
Definition: Prefab.cs:34
bool AbilityEffectsStackWithSameTalent
When set to false the AbilityEffects of multiple of the same talent will not be checked and only the ...
Definition: TalentPrefab.cs:21
ContentXElement ConfigElement
Definition: TalentPrefab.cs:40
AbilityEffectType
Definition: Enums.cs:125