Unstable 0.15.15.0 (and the one before it I forgor)
This commit is contained in:
+14
-2
@@ -16,10 +16,12 @@ namespace Barotrauma.Abilities
|
||||
private readonly string itemIdentifier;
|
||||
private readonly string[] tags;
|
||||
private readonly WeaponType weapontype;
|
||||
private bool ignoreNonHarmfulAttacks;
|
||||
public AbilityConditionAttackData(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
itemIdentifier = conditionElement.GetAttributeString("itemidentifier", "");
|
||||
tags = conditionElement.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true);
|
||||
ignoreNonHarmfulAttacks = conditionElement.GetAttributeBool("ignorenonharmfulattacks", false);
|
||||
switch (conditionElement.GetAttributeString("weapontype", ""))
|
||||
{
|
||||
case "melee":
|
||||
@@ -35,8 +37,15 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (abilityObject is AbilityAttackData attackData)
|
||||
{
|
||||
Item item = attackData?.SourceAttack?.SourceItem;
|
||||
if (ignoreNonHarmfulAttacks && attackData.SourceAttack != null)
|
||||
{
|
||||
if (attackData.SourceAttack.Stun <= 0.0f && (attackData.SourceAttack.Afflictions?.All(a => a.Key.Prefab.IsBuff) ?? true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Item item = attackData?.SourceAttack?.SourceItem;
|
||||
if (item == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Source Item was not found in {this} for talent {characterTalent.DebugIdentifier}!");
|
||||
@@ -61,10 +70,13 @@ namespace Barotrauma.Abilities
|
||||
|
||||
switch (weapontype)
|
||||
{
|
||||
// it is possible that an item that has both a melee and a projectile component will return true
|
||||
// even when not used as a melee/ranged weapon respectively
|
||||
// attackdata should contain data regarding whether the attack is melee or not
|
||||
case WeaponType.Melee:
|
||||
return item.GetComponent<MeleeWeapon>() != null;
|
||||
case WeaponType.Ranged:
|
||||
return item.GetComponent<RangedWeapon>() != null;
|
||||
return item.GetComponent<Projectile>() != null;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -18,13 +18,13 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected void LogAbilityConditionError(AbilityObject abilityObject, Type expectedData)
|
||||
{
|
||||
DebugConsole.ThrowError($"Used data-reliant ability condition when data is incompatible! Expected {expectedData}, but received {abilityObject}");
|
||||
DebugConsole.ThrowError($"Used data-reliant ability condition when data is incompatible! Expected {expectedData}, but received {abilityObject} in talent {characterTalent.DebugIdentifier}");
|
||||
}
|
||||
|
||||
protected abstract bool MatchesConditionSpecific(AbilityObject abilityObject);
|
||||
public override bool MatchesCondition()
|
||||
{
|
||||
DebugConsole.ThrowError("Used data-reliant ability condition in a state-based ability! This is not allowed.");
|
||||
DebugConsole.ThrowError($"Used data-reliant ability condition in a state-based ability in talent {characterTalent.DebugIdentifier}! This is not allowed.");
|
||||
return false;
|
||||
}
|
||||
public override bool MatchesCondition(AbilityObject abilityObject)
|
||||
|
||||
+3
-3
@@ -79,17 +79,17 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected virtual void ApplyEffect()
|
||||
{
|
||||
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not have a definition for ApplyEffect");
|
||||
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not have a definition for ApplyEffect in talent {CharacterTalent.DebugIdentifier}");
|
||||
}
|
||||
|
||||
protected virtual void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not take a parameter for ApplyEffect");
|
||||
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not take a parameter for ApplyEffect in talent {CharacterTalent.DebugIdentifier}");
|
||||
}
|
||||
|
||||
protected void LogabilityObjectMismatch()
|
||||
{
|
||||
DebugConsole.ThrowError($"Incompatible ability! Ability {this} is incompatitible with this type of ability effect type.");
|
||||
DebugConsole.ThrowError($"Incompatible ability! Ability {this} is incompatitible with this type of ability effect type in talent {CharacterTalent.DebugIdentifier}");
|
||||
}
|
||||
|
||||
// XML
|
||||
|
||||
+9
-1
@@ -10,8 +10,10 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected readonly List<StatusEffect> statusEffects;
|
||||
|
||||
private readonly bool applyToSelf;
|
||||
private readonly bool nearbyCharactersAppliesToSelf;
|
||||
private readonly bool nearbyCharactersAppliesToAllies;
|
||||
private readonly bool nearbyCharactersAppliesToEnemies;
|
||||
private readonly bool applyToSelected;
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
@@ -19,9 +21,11 @@ namespace Barotrauma.Abilities
|
||||
public CharacterAbilityApplyStatusEffects(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
applyToSelf = abilityElement.GetAttributeBool("applytoself", false);
|
||||
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
||||
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
|
||||
nearbyCharactersAppliesToAllies = abilityElement.GetAttributeBool("nearbycharactersappliestoallies", true);
|
||||
nearbyCharactersAppliesToEnemies = abilityElement.GetAttributeBool("nearbycharactersappliestoenemies", true);
|
||||
}
|
||||
|
||||
protected void ApplyEffectSpecific(Character targetCharacter)
|
||||
@@ -46,6 +50,10 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
targets.RemoveAll(c => c is Character otherCharacter && HumanAIController.IsFriendly(otherCharacter, Character));
|
||||
}
|
||||
if (!nearbyCharactersAppliesToEnemies)
|
||||
{
|
||||
targets.RemoveAll(c => c is Character otherCharacter && !HumanAIController.IsFriendly(otherCharacter, Character));
|
||||
}
|
||||
statusEffect.SetUser(Character);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
||||
}
|
||||
@@ -75,7 +83,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
|
||||
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter && !applyToSelf)
|
||||
{
|
||||
ApplyEffectSpecific(targetCharacter);
|
||||
}
|
||||
|
||||
+5
@@ -31,5 +31,10 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
ApplyEffect();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyAttackData : CharacterAbility
|
||||
{
|
||||
private readonly List<Affliction> afflictions;
|
||||
private readonly List<Affliction> afflictions = new List<Affliction>();
|
||||
|
||||
private readonly float addedDamageMultiplier;
|
||||
private readonly float addedPenetration;
|
||||
|
||||
+8
-2
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
@@ -15,14 +16,19 @@ namespace Barotrauma.Abilities
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(Character.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
var subTree = talentTree.TalentSubTrees.Find(t => t.TalentOptionStages.Any(ts => ts.Talents.Contains(CharacterTalent.Prefab)));
|
||||
|
||||
if (subTree != null)
|
||||
{
|
||||
subTree.ForceUnlock = true;
|
||||
foreach (var talentOption in subTree.TalentOptionStages)
|
||||
{
|
||||
foreach (var talent in talentOption.Talents)
|
||||
{
|
||||
if (talent == CharacterTalent.Prefab) { continue; }
|
||||
Character.GiveTalent(talent);
|
||||
if (Character.GiveTalent(talent))
|
||||
{
|
||||
Character.Info.AdditionalTalentPoints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,37 +101,40 @@ namespace Barotrauma
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
if (doc == null) { return; }
|
||||
|
||||
var rootElement = doc.Root;
|
||||
switch (rootElement.Name.ToString().ToLowerInvariant())
|
||||
void loadSinglePrefab(XElement element, bool isOverride)
|
||||
{
|
||||
case "talent":
|
||||
TalentPrefabs.Add(new TalentPrefab(rootElement, file.Path), false);
|
||||
break;
|
||||
case "talents":
|
||||
foreach (var element in rootElement.Elements())
|
||||
{
|
||||
if (element.IsOverride())
|
||||
{
|
||||
var itemElement = element.GetChildElement("talent");
|
||||
if (itemElement != null)
|
||||
{
|
||||
TalentPrefabs.Add(new TalentPrefab(rootElement, file.Path), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Cannot find a talent element from the children of the override element defined in {file.Path}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TalentPrefabs.Add(new TalentPrefab(element, file.Path), false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}");
|
||||
break;
|
||||
TalentPrefabs.Add(new TalentPrefab(element, file.Path) { ContentPackage = file.ContentPackage }, isOverride);
|
||||
}
|
||||
|
||||
void loadMultiplePrefabs(XElement element, bool isOverride)
|
||||
{
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
interpretElement(subElement, isOverride);
|
||||
}
|
||||
}
|
||||
|
||||
void interpretElement(XElement subElement, bool isOverride)
|
||||
{
|
||||
if (subElement.IsOverride())
|
||||
{
|
||||
loadMultiplePrefabs(subElement, true);
|
||||
}
|
||||
else if (subElement.Name.LocalName.Equals("talents", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loadMultiplePrefabs(subElement, isOverride);
|
||||
}
|
||||
else if (subElement.Name.LocalName.Equals("talent", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loadSinglePrefab(subElement, isOverride);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid XML element for the {nameof(TalentPrefab)} prefab type: '{subElement.Name}' in {file.Path}");
|
||||
}
|
||||
}
|
||||
|
||||
interpretElement(doc.Root, false);
|
||||
}
|
||||
|
||||
public static void LoadAll(IEnumerable<ContentFile> files)
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class TalentTree
|
||||
class TalentTree : IPrefab, IDisposable
|
||||
{
|
||||
public enum TalentTreeStageState
|
||||
{
|
||||
@@ -16,7 +16,7 @@ namespace Barotrauma
|
||||
Highlighted
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, TalentTree> JobTalentTrees = new Dictionary<string, TalentTree>();
|
||||
public static readonly PrefabCollection<TalentTree> JobTalentTrees = new PrefabCollection<TalentTree>();
|
||||
|
||||
public readonly List<TalentSubTree> TalentSubTrees = new List<TalentSubTree>();
|
||||
|
||||
@@ -26,13 +26,21 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public string OriginalName => Identifier;
|
||||
|
||||
public string Identifier { get; }
|
||||
|
||||
public string FilePath { get; }
|
||||
|
||||
public ContentPackage ContentPackage { get; set; }
|
||||
|
||||
public TalentTree(XElement element, string filePath)
|
||||
{
|
||||
ConfigElement = element;
|
||||
FilePath = filePath;
|
||||
Identifier = element.GetAttributeString("jobidentifier", "").ToLowerInvariant();
|
||||
|
||||
string jobIdentifier = element.GetAttributeString("jobidentifier", "").ToLowerInvariant();
|
||||
|
||||
if (string.IsNullOrEmpty(jobIdentifier))
|
||||
if (string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"No job defined for talent tree in \"{filePath}\"!");
|
||||
return;
|
||||
@@ -50,20 +58,15 @@ namespace Barotrauma
|
||||
TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c => c.Identifier.Equals(talent, StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Talent tree for job {jobIdentifier} contains non-existent talent {talent}! Talent tree not added.");
|
||||
DebugConsole.AddWarning($"Talent tree for job {Identifier} contains non-existent talent {talent}! Talent tree not added.");
|
||||
return;
|
||||
}
|
||||
if (!duplicateSet.Add(talent))
|
||||
{
|
||||
DebugConsole.ThrowError($"Talent tree for job {jobIdentifier} contains duplicate talent {talent}! Talent tree not added.");
|
||||
DebugConsole.ThrowError($"Talent tree for job {Identifier} contains duplicate talent {talent}! Talent tree not added.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JobTalentTrees.TryAdd(jobIdentifier, this))
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not add talent tree for job {jobIdentifier}! A talent tree for this job is already likely defined");
|
||||
}
|
||||
}
|
||||
|
||||
public bool TalentIsInTree(string talentIdentifier)
|
||||
@@ -78,37 +81,40 @@ namespace Barotrauma
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
if (doc == null) { return; }
|
||||
|
||||
var rootElement = doc.Root;
|
||||
switch (rootElement.Name.ToString().ToLowerInvariant())
|
||||
void loadSinglePrefab(XElement element, bool isOverride)
|
||||
{
|
||||
case "talenttree":
|
||||
new TalentTree(rootElement, file.Path);
|
||||
break;
|
||||
case "talenttrees":
|
||||
foreach (var element in rootElement.Elements())
|
||||
{
|
||||
if (element.IsOverride())
|
||||
{
|
||||
var treeElement = element.GetChildElement("talenttree");
|
||||
if (treeElement != null)
|
||||
{
|
||||
new TalentTree(rootElement, file.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Cannot find a talent tree element from the children of the override element defined in {file.Path}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new TalentTree(element, file.Path);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}");
|
||||
break;
|
||||
JobTalentTrees.Add(new TalentTree(element, file.Path) { ContentPackage = file.ContentPackage }, isOverride);
|
||||
}
|
||||
|
||||
void loadMultiplePrefabs(XElement element, bool isOverride)
|
||||
{
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
interpretElement(subElement, isOverride);
|
||||
}
|
||||
}
|
||||
|
||||
void interpretElement(XElement subElement, bool isOverride)
|
||||
{
|
||||
if (subElement.IsOverride())
|
||||
{
|
||||
loadMultiplePrefabs(subElement, true);
|
||||
}
|
||||
else if (subElement.Name.LocalName.Equals("talenttrees", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loadMultiplePrefabs(subElement, isOverride);
|
||||
}
|
||||
else if (subElement.Name.LocalName.Equals("talenttree", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loadSinglePrefab(subElement, isOverride);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid XML element for the {nameof(TalentTree)} prefab type: '{subElement.Name}' in {file.Path}");
|
||||
}
|
||||
}
|
||||
|
||||
interpretElement(doc.Root, false);
|
||||
}
|
||||
|
||||
public static void LoadAll(IEnumerable<ContentFile> files)
|
||||
@@ -190,6 +196,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
if (subTree.ForceUnlock && subTree.TalentOptionStages.Any(option => option.Talents.Any(t => t.Identifier == talentIdentifier))) { return true; }
|
||||
|
||||
foreach (var talentOptionStage in subTree.TalentOptionStages)
|
||||
{
|
||||
bool hasTalentInThisTier = talentOptionStage.Talents.Any(t => selectedTalents.Contains(t.Identifier));
|
||||
@@ -220,7 +228,7 @@ namespace Barotrauma
|
||||
canStillUnlock = false;
|
||||
foreach (string talent in selectedTalents)
|
||||
{
|
||||
if (IsViableTalentForCharacter(controlledCharacter, talent, viableTalents))
|
||||
if (!viableTalents.Contains(talent) && IsViableTalentForCharacter(controlledCharacter, talent, viableTalents))
|
||||
{
|
||||
viableTalents.Add(talent);
|
||||
canStillUnlock = true;
|
||||
@@ -229,6 +237,14 @@ namespace Barotrauma
|
||||
}
|
||||
return viableTalents;
|
||||
}
|
||||
|
||||
private bool disposed = false;
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed) { return; }
|
||||
disposed = true;
|
||||
JobTalentTrees.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TalentSubTree
|
||||
@@ -237,6 +253,8 @@ namespace Barotrauma
|
||||
|
||||
public string DisplayName { get; }
|
||||
|
||||
public bool ForceUnlock;
|
||||
|
||||
public readonly List<TalentOption> TalentOptionStages = new List<TalentOption>();
|
||||
|
||||
public TalentSubTree(XElement subTreeElement)
|
||||
|
||||
Reference in New Issue
Block a user