0.1500.3.0 (🗿 edition)
This commit is contained in:
@@ -161,8 +161,8 @@ namespace Barotrauma
|
||||
for (int i = 0; i < container.Inventory.Capacity; i++)
|
||||
{
|
||||
if (container.Inventory.GetItemAt(i) != null) { continue; }
|
||||
if (MapEntityPrefab.List.GetRandom(e => e is ItemPrefab i && container.CanBeContained(i) &&
|
||||
Config.ForbiddenAmmunition.None(id => id.Equals(i.Identifier, StringComparison.OrdinalIgnoreCase)), Rand.RandSync.Server) is ItemPrefab ammoPrefab)
|
||||
if (MapEntityPrefab.List.GetRandom(e => e is ItemPrefab ip && container.CanBeContained(ip, i) &&
|
||||
Config.ForbiddenAmmunition.None(id => id.Equals(ip.Identifier, StringComparison.OrdinalIgnoreCase)), Rand.RandSync.Server) is ItemPrefab ammoPrefab)
|
||||
{
|
||||
Item ammo = new Item(ammoPrefab, container.Item.WorldPosition, Wreck);
|
||||
if (!container.Inventory.TryPutItem(ammo, i, allowSwapping: false, allowCombine: false, user: null, createNetworkEvent: false))
|
||||
|
||||
@@ -1430,6 +1430,7 @@ namespace Barotrauma
|
||||
|
||||
//throwing conscious/moving characters around takes more force -> double the flow force
|
||||
if (character.CanMove) { flowForce *= 2.0f; }
|
||||
flowForce *= 1 - Math.Clamp(character.GetStatValue(StatTypes.FlowResistance), 0f, 1f);
|
||||
|
||||
float flowForceMagnitude = flowForce.Length();
|
||||
float limbMultipier = limbs.Count(l => l.inWater) / (float)limbs.Length;
|
||||
|
||||
@@ -251,6 +251,8 @@ namespace Barotrauma
|
||||
private readonly List<Attacker> lastAttackers = new List<Attacker>();
|
||||
public IEnumerable<Attacker> LastAttackers => lastAttackers;
|
||||
public Character LastAttacker => lastAttackers.LastOrDefault()?.Character;
|
||||
public Character LastOrderedCharacter { get; private set; }
|
||||
public Character SecondLastOrderedCharacter { get; private set; }
|
||||
|
||||
public Entity LastDamageSource;
|
||||
|
||||
@@ -2720,7 +2722,7 @@ namespace Barotrauma
|
||||
|
||||
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
|
||||
bool allowRagdoll = GameMain.NetworkMember?.ServerSettings?.AllowRagdollButton ?? true;
|
||||
bool tooFastToUnragdoll = AnimController.Collider.LinearVelocity.LengthSquared() > 5.0f * 5.0f;
|
||||
bool tooFastToUnragdoll = AnimController.Collider.LinearVelocity.LengthSquared() > 2.5f * 2.5f;
|
||||
bool wasRagdolled = false;
|
||||
bool selfRagdolled = false;
|
||||
|
||||
@@ -3131,6 +3133,12 @@ namespace Barotrauma
|
||||
{
|
||||
var abilityOrderedCharacter = new AbilityCharacter(this);
|
||||
orderGiver.CheckTalents(AbilityEffectType.OnGiveOrder, abilityOrderedCharacter);
|
||||
|
||||
if (orderGiver.LastOrderedCharacter != this)
|
||||
{
|
||||
orderGiver.SecondLastOrderedCharacter = orderGiver.LastOrderedCharacter;
|
||||
orderGiver.LastOrderedCharacter = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (AIController is HumanAIController humanAI)
|
||||
@@ -3406,6 +3414,13 @@ namespace Barotrauma
|
||||
AddDamage(worldPosition, attackAfflictions, attack.Stun, playSound, attackImpulse, out limbHit, attacker, attack.DamageMultiplier * attackData.DamageMultiplier) :
|
||||
DamageLimb(worldPosition, targetLimb, attackAfflictions, attack.Stun, playSound, attackImpulse, attacker, attack.DamageMultiplier * attackData.DamageMultiplier, penetration: penetration + attackData.AddedPenetration);
|
||||
|
||||
if (attacker != null)
|
||||
{
|
||||
var abilityAttackResult = new AbilityAttackResult(attackResult);
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttackResult, abilityAttackResult);
|
||||
CheckTalents(AbilityEffectType.OnAttackedResult, abilityAttackResult);
|
||||
}
|
||||
|
||||
if (limbHit == null) { return new AttackResult(); }
|
||||
Vector2 forceWorld = attack.TargetImpulseWorld + attack.TargetForceWorld;
|
||||
if (attacker != null)
|
||||
@@ -3623,11 +3638,6 @@ namespace Barotrauma
|
||||
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
|
||||
hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
|
||||
}
|
||||
if (attacker != null)
|
||||
{
|
||||
var abilityAttackResult = new AbilityAttackResult(attackResult);
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttackResult, abilityAttackResult);
|
||||
}
|
||||
|
||||
return attackResult;
|
||||
}
|
||||
|
||||
@@ -979,6 +979,8 @@ namespace Barotrauma
|
||||
increase *= SkillSettings.Current.AssistantSkillIncreaseMultiplier;
|
||||
}
|
||||
|
||||
increase *= 1f + Character.GetStatValue(StatTypes.SkillGainSpeed);
|
||||
|
||||
float prevLevel = Job.GetSkillLevel(skillIdentifier);
|
||||
Job.IncreaseSkillLevel(skillIdentifier, increase, Character.HasAbilityFlag(AbilityFlags.GainSkillPastMaximum));
|
||||
|
||||
@@ -1527,6 +1529,17 @@ namespace Barotrauma
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
public float GetSavedStatValue(StatTypes statType, string statIdentifier)
|
||||
{
|
||||
if (savedStatValues.TryGetValue(statType, out var statValues))
|
||||
{
|
||||
return statValues.Where(s => s.StatIdentifier.Equals(statIdentifier, StringComparison.OrdinalIgnoreCase)).Sum(v => v.StatValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue)
|
||||
{
|
||||
|
||||
@@ -971,7 +971,7 @@ namespace Barotrauma
|
||||
/// <param name="treatmentSuitability">A dictionary where the key is the identifier of the item and the value the suitability</param>
|
||||
/// <param name="normalize">If true, the suitability values are normalized between 0 and 1. If not, they're arbitrary values defined in the medical item XML, where negative values are unsuitable, and positive ones suitable.</param>
|
||||
/// <param name="randomization">Amount of randomization to apply to the values (0 = the values are accurate, 1 = the values are completely random)</param>
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, Limb limb = null, float randomization = 0.0f)
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, Limb limb = null, bool ignoreHiddenAfflictions = false, float randomization = 0.0f)
|
||||
{
|
||||
//key = item identifier
|
||||
//float = suitability
|
||||
@@ -980,6 +980,7 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in getAfflictions(limb))
|
||||
{
|
||||
if (affliction.Strength < affliction.Prefab.TreatmentThreshold) { continue; }
|
||||
if (ignoreHiddenAfflictions && affliction.Strength < affliction.Prefab.ShowIconThreshold) { continue; }
|
||||
foreach (KeyValuePair<string, float> treatment in affliction.Prefab.TreatmentSuitability)
|
||||
{
|
||||
if (!treatmentSuitability.ContainsKey(treatment.Key))
|
||||
|
||||
+4
-4
@@ -7,12 +7,12 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
private enum WeaponType
|
||||
{
|
||||
Any = 0,
|
||||
Melee = 1,
|
||||
Any = 0,
|
||||
Melee = 1,
|
||||
Ranged = 2
|
||||
};
|
||||
|
||||
private WeaponType weapontype;
|
||||
private readonly WeaponType weapontype;
|
||||
public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
switch (conditionElement.GetAttributeString("weapontype", ""))
|
||||
@@ -43,7 +43,7 @@ namespace Barotrauma.Abilities
|
||||
break;
|
||||
default:
|
||||
aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -6,12 +6,12 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionItem : AbilityConditionData
|
||||
{
|
||||
private readonly string identifier;
|
||||
private readonly string[] identifiers;
|
||||
private readonly string[] tags;
|
||||
|
||||
public AbilityConditionItem(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
identifier = conditionElement.GetAttributeString("identifier", string.Empty).ToLowerInvariant();
|
||||
identifiers = conditionElement.GetAttributeStringArray("identifiers", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
tags = conditionElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ namespace Barotrauma.Abilities
|
||||
|
||||
if (itemPrefab != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
if (identifiers.Any())
|
||||
{
|
||||
if (itemPrefab.Identifier != identifier)
|
||||
if (!identifiers.Any(t => itemPrefab.Identifier == t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return tags.Any(t => itemPrefab.Tags.Any(p => t == p));
|
||||
return !tags.Any() || tags.Any(t => itemPrefab.Tags.Any(p => t == p));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionHasVelocity : AbilityConditionDataless
|
||||
{
|
||||
private readonly float velocity;
|
||||
|
||||
public AbilityConditionHasVelocity(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
velocity = conditionElement.GetAttributeFloat("velocity", 0f);
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
return character.AnimController.Collider.LinearVelocity.LengthSquared() > velocity * velocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
if (character.Submarine == null || character.Submarine.TeamID != character.TeamID) { return false; }
|
||||
if (!character.IsInFriendlySub) { return false; }
|
||||
float currentFloodPercentage = character.Submarine.GetHulls(false).Average(h => h.WaterPercentage);
|
||||
return currentFloodPercentage / 100 > floodPercentage;
|
||||
}
|
||||
|
||||
+7
-1
@@ -10,6 +10,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected readonly List<StatusEffect> statusEffects;
|
||||
|
||||
private readonly bool nearbyCharactersAppliesToSelf;
|
||||
private readonly bool applyToSelected;
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
@@ -18,6 +19,7 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
||||
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
|
||||
}
|
||||
|
||||
protected void ApplyEffectSpecific(Character targetCharacter)
|
||||
@@ -26,7 +28,7 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.UseTarget))
|
||||
{
|
||||
// currently used this to spawn items on the targeted character
|
||||
// currently used to spawn items on the targeted character
|
||||
statusEffect.SetUser(targetCharacter);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targetCharacter);
|
||||
}
|
||||
@@ -34,6 +36,10 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
targets.Clear();
|
||||
targets.AddRange(statusEffect.GetNearbyTargets(targetCharacter.WorldPosition, targets));
|
||||
if (!nearbyCharactersAppliesToSelf)
|
||||
{
|
||||
targets.RemoveAll(c => c == Character);
|
||||
}
|
||||
statusEffect.SetUser(Character);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApplyStatusEffectsToLastOrderedCharacter : CharacterAbilityApplyStatusEffects
|
||||
{
|
||||
public CharacterAbilityApplyStatusEffectsToLastOrderedCharacter(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
if (IsViableTarget(Character.LastOrderedCharacter))
|
||||
{
|
||||
ApplyEffectSpecific(Character.LastOrderedCharacter);
|
||||
}
|
||||
if (Character.HasAbilityFlag(AbilityFlags.AllowSecondOrderedTarget) && IsViableTarget(Character.SecondLastOrderedCharacter))
|
||||
{
|
||||
ApplyEffectSpecific(Character.SecondLastOrderedCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsViableTarget(Character targetCharacter)
|
||||
{
|
||||
if (targetCharacter == null || targetCharacter.Removed) { return false; }
|
||||
if (targetCharacter == Character) { return false; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -27,8 +27,7 @@ namespace Barotrauma.Abilities
|
||||
targetAllies = abilityElement.GetAttributeBool("targetallies", false);
|
||||
removeOnDeath = abilityElement.GetAttributeBool("removeondeath", true);
|
||||
removeAfterRound = abilityElement.GetAttributeBool("removeafterround", false);
|
||||
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", false);
|
||||
//maximumValue = abilityElement.GetAttributeFloat("maximumvalue", float.MaxValue);
|
||||
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", characterAbilityGroup.AbilityEffectType == AbilityEffectType.None);
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
|
||||
+24
-4
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
@@ -7,13 +8,22 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
|
||||
private string skillIdentifier;
|
||||
private float skillIncrease;
|
||||
private readonly string skillIdentifier;
|
||||
private readonly float skillIncrease;
|
||||
|
||||
public CharacterAbilityIncreaseSkill(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
skillIdentifier = abilityElement.GetAttributeString("skillidentifier", "").ToLowerInvariant();
|
||||
skillIncrease = abilityElement.GetAttributeFloat("skillincrease", 0f);
|
||||
|
||||
if (string.IsNullOrEmpty(skillIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent \"{characterAbilityGroup.CharacterTalent.DebugIdentifier}\" - skill identifier not defined in CharacterAbilityIncreaseSkill.");
|
||||
}
|
||||
if (MathUtils.NearlyEqual(skillIncrease, 0))
|
||||
{
|
||||
DebugConsole.AddWarning($"Possible error in talent \"{characterAbilityGroup.CharacterTalent.DebugIdentifier}\" - skill increase set to 0.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
@@ -35,7 +45,17 @@ namespace Barotrauma.Abilities
|
||||
|
||||
private void ApplyEffectSpecific(Character character)
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
if (skillIdentifier.Equals("random"))
|
||||
{
|
||||
var skill = character.Info?.Job?.Skills?.GetRandom();
|
||||
if (skill == null) { return; }
|
||||
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyStatToFlooding : CharacterAbility
|
||||
{
|
||||
private readonly StatTypes statType;
|
||||
private readonly float maxValue;
|
||||
private float lastValue = 0f;
|
||||
|
||||
public CharacterAbilityModifyStatToFlooding(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
maxValue = abilityElement.GetAttributeFloat("maxvalue", 0f);
|
||||
}
|
||||
|
||||
protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
{
|
||||
Character.ChangeStat(statType, -lastValue);
|
||||
|
||||
if (conditionsMatched && Character.IsInFriendlySub)
|
||||
{
|
||||
float currentFloodPercentage = Character.Submarine.GetHulls(false).Average(h => h.WaterPercentage);
|
||||
lastValue = currentFloodPercentage / 100f * maxValue;
|
||||
Character.ChangeStat(statType, lastValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastValue = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -4,8 +4,8 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyValue : CharacterAbility
|
||||
{
|
||||
private float addedValue;
|
||||
private float multiplyValue;
|
||||
private readonly float addedValue;
|
||||
private readonly float multiplyValue;
|
||||
|
||||
public CharacterAbilityModifyValue(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
|
||||
+8
-2
@@ -6,12 +6,14 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityByTheBook : CharacterAbility
|
||||
{
|
||||
private int moneyAmount;
|
||||
private int max;
|
||||
private readonly int moneyAmount;
|
||||
private readonly int experienceAmount;
|
||||
private readonly int max;
|
||||
|
||||
public CharacterAbilityByTheBook(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
moneyAmount = abilityElement.GetAttributeInt("moneyamount", 0);
|
||||
experienceAmount = abilityElement.GetAttributeInt("experienceamount", 0);
|
||||
max = abilityElement.GetAttributeInt("max", 0);
|
||||
}
|
||||
|
||||
@@ -28,6 +30,10 @@ namespace Barotrauma.Abilities
|
||||
if (!enemyCharacter.LockHands) { continue; }
|
||||
if (timesGiven > max) { continue; }
|
||||
Character.GiveMoney(moneyAmount);
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
character.Info?.GiveExperience(experienceAmount);
|
||||
}
|
||||
timesGiven++;
|
||||
}
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityEnigmaMachine : CharacterAbility
|
||||
{
|
||||
private readonly float addedValue;
|
||||
private readonly float multiplyValue;
|
||||
private readonly string[] tags;
|
||||
private readonly int maxMultiplyCount;
|
||||
|
||||
public CharacterAbilityEnigmaMachine(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||
tags = abilityElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
maxMultiplyCount = abilityElement.GetAttributeInt("maxmultiplycount", int.MaxValue);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if (abilityObject is IAbilityValue abilityValue)
|
||||
{
|
||||
int multiplyCount = 0;
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Prefab.Tags.Any(t => tags.Contains(t)))
|
||||
{
|
||||
multiplyCount++;
|
||||
if (multiplyCount == maxMultiplyCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abilityValue.Value += addedValue * multiplyCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityIndustrialRevolution : CharacterAbility
|
||||
{
|
||||
float addedFabricationSpeed;
|
||||
|
||||
public CharacterAbilityIndustrialRevolution(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedFabricationSpeed = abilityElement.GetAttributeFloat("addedfabricationspeed", 0f);
|
||||
}
|
||||
|
||||
public override void UpdateCharacterAbility(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
{
|
||||
if (conditionsMatched)
|
||||
{
|
||||
// not necessarily the cleanest or performant way, but at least this shouldn't break anything.
|
||||
// must be done every frame in order to work.
|
||||
if (Character.SelectedConstruction?.GetComponent<Fabricator>() is Fabricator fabricator && fabricator.IsActive)
|
||||
{
|
||||
fabricator.FabricationSpeedMultiplier += addedFabricationSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityTaskmaster : CharacterAbility
|
||||
{
|
||||
private readonly List<StatusEffect> statusEffects;
|
||||
private readonly List<StatusEffect> statusEffectsRemove;
|
||||
|
||||
private Character lastCharacter;
|
||||
|
||||
public CharacterAbilityTaskmaster(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
statusEffectsRemove = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffectsremove"));
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
|
||||
{
|
||||
if (targetCharacter == Character) { return; }
|
||||
|
||||
foreach (var statusEffect in statusEffectsRemove)
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, lastCharacter);
|
||||
}
|
||||
|
||||
foreach (var statusEffect in statusEffects)
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, targetCharacter);
|
||||
}
|
||||
|
||||
lastCharacter = targetCharacter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -14,6 +14,8 @@ namespace Barotrauma.Abilities
|
||||
// currently only used to turn off simulation if random conditions are in use
|
||||
public bool IsActive { get; private set; } = true;
|
||||
|
||||
public readonly AbilityEffectType AbilityEffectType;
|
||||
|
||||
protected int maxTriggerCount { get; }
|
||||
protected int timesTriggered = 0;
|
||||
|
||||
@@ -24,8 +26,9 @@ namespace Barotrauma.Abilities
|
||||
// separate dictionaries for each type of characterability?
|
||||
protected readonly List<CharacterAbility> characterAbilities = new List<CharacterAbility>();
|
||||
|
||||
public CharacterAbilityGroup(CharacterTalent characterTalent, XElement abilityElementGroup)
|
||||
public CharacterAbilityGroup(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup)
|
||||
{
|
||||
AbilityEffectType = abilityEffectType;
|
||||
CharacterTalent = characterTalent;
|
||||
Character = CharacterTalent.Character;
|
||||
maxTriggerCount = abilityElementGroup.GetAttributeInt("maxtriggercount", int.MaxValue);
|
||||
@@ -168,8 +171,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
public static StatTypes ParseStatType(string statTypeString, string debugIdentifier)
|
||||
{
|
||||
StatTypes statType;
|
||||
if (!Enum.TryParse(statTypeString, true, out statType))
|
||||
if (!Enum.TryParse(statTypeString, true, out StatTypes statType))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid stat type type \"" + statTypeString + "\" in CharacterTalent (" + debugIdentifier + ")");
|
||||
}
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGroupEffect : CharacterAbilityGroup
|
||||
{
|
||||
public CharacterAbilityGroupEffect(CharacterTalent characterTalent, XElement abilityElementGroup) : base(characterTalent, abilityElementGroup) { }
|
||||
public CharacterAbilityGroupEffect(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup) :
|
||||
base(abilityEffectType, characterTalent, abilityElementGroup) { }
|
||||
|
||||
public void CheckAbilityGroup(AbilityObject abilityObject)
|
||||
{
|
||||
|
||||
+2
-1
@@ -15,7 +15,8 @@ namespace Barotrauma.Abilities
|
||||
private float effectDelayTimer;
|
||||
|
||||
|
||||
public CharacterAbilityGroupInterval(CharacterTalent characterTalent, XElement abilityElementGroup) : base(characterTalent, abilityElementGroup)
|
||||
public CharacterAbilityGroupInterval(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup) :
|
||||
base(abilityEffectType, characterTalent, abilityElementGroup)
|
||||
{
|
||||
// too many overlapping intervals could cause hitching? maybe randomize a little
|
||||
interval = abilityElementGroup.GetAttributeFloat("interval", 0f);
|
||||
|
||||
@@ -85,14 +85,13 @@ namespace Barotrauma
|
||||
// XML logic
|
||||
private void LoadAbilityGroupInterval(XElement abilityGroup)
|
||||
{
|
||||
string name = abilityGroup.Name.ToString().ToLowerInvariant();
|
||||
characterAbilityGroupIntervals.Add(new CharacterAbilityGroupInterval(this, abilityGroup));
|
||||
characterAbilityGroupIntervals.Add(new CharacterAbilityGroupInterval(AbilityEffectType.Undefined, this, abilityGroup));
|
||||
}
|
||||
|
||||
private void LoadAbilityGroupEffect(XElement abilityGroup)
|
||||
{
|
||||
AbilityEffectType abilityEffectType = ParseAbilityEffectType(this, abilityGroup.GetAttributeString("abilityeffecttype", "none"));
|
||||
AddAbilityGroupEffect(new CharacterAbilityGroupEffect(this, abilityGroup), abilityEffectType);
|
||||
AddAbilityGroupEffect(new CharacterAbilityGroupEffect(abilityEffectType, this, abilityGroup), abilityEffectType);
|
||||
}
|
||||
|
||||
public void AddAbilityGroupEffect(CharacterAbilityGroupEffect characterAbilityGroup, AbilityEffectType abilityEffectType = AbilityEffectType.None)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -8,13 +7,19 @@ namespace Barotrauma
|
||||
{
|
||||
class TalentTree
|
||||
{
|
||||
public enum TalentTreeStageState
|
||||
{
|
||||
Invalid,
|
||||
Locked,
|
||||
Unlocked,
|
||||
Available,
|
||||
Highlighted
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, TalentTree> JobTalentTrees = new Dictionary<string, TalentTree>();
|
||||
|
||||
public readonly List<TalentSubTree> TalentSubTrees = new List<TalentSubTree>();
|
||||
|
||||
private static HashSet<string> subtreeTalents = new HashSet<string>();
|
||||
|
||||
private const string PlaceholderTalent = "placeholder";
|
||||
public XElement ConfigElement
|
||||
{
|
||||
get;
|
||||
@@ -35,14 +40,13 @@ namespace Barotrauma
|
||||
|
||||
foreach (XElement subTreeElement in element.GetChildElements("subtree"))
|
||||
{
|
||||
TalentSubTrees.Add(new TalentSubTree(subTreeElement));
|
||||
TalentSubTrees.Add(new TalentSubTree(subTreeElement));
|
||||
}
|
||||
|
||||
// talents found and unlocked using the identifier wihin the talent tree, so no duplicates may occur
|
||||
HashSet<string> duplicateSet = new HashSet<string>();
|
||||
foreach (string talent in TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier))))
|
||||
{
|
||||
if (talent == PlaceholderTalent) { continue; }
|
||||
TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c => c.Identifier.Equals(talent, StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
@@ -97,7 +101,7 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}");
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -117,10 +121,63 @@ namespace Barotrauma
|
||||
return IsViableTalentForCharacter(character, talentIdentifier, character?.Info?.UnlockedTalents ?? Enumerable.Empty<string>());
|
||||
}
|
||||
|
||||
// i hate this function - markus
|
||||
public static TalentTreeStageState GetTalentOptionStageState(Character character, string subTreeIdentifier, int index, List<string> selectedTalents)
|
||||
{
|
||||
if (character?.Info?.Job.Prefab is null) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
if (!JobTalentTrees.TryGetValue(character.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
TalentSubTree subTree = talentTree.TalentSubTrees.FirstOrDefault(tst => tst.Identifier == subTreeIdentifier);
|
||||
|
||||
if (subTree == null) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
TalentOption targetTalentOption = subTree.TalentOptionStages[index];
|
||||
|
||||
if (targetTalentOption.Talents.Any(t => character.HasTalent(t.Identifier)))
|
||||
{
|
||||
return TalentTreeStageState.Unlocked;
|
||||
}
|
||||
|
||||
if (targetTalentOption.Talents.Any(t => selectedTalents.Contains(t.Identifier)))
|
||||
{
|
||||
return TalentTreeStageState.Highlighted;
|
||||
}
|
||||
|
||||
bool hasTalentInLastTier = true;
|
||||
bool isLastTalentPurchased = true;
|
||||
|
||||
int lastindex = index - 1;
|
||||
if (lastindex >= 0)
|
||||
{
|
||||
TalentOption lastLatentOption = subTree.TalentOptionStages[lastindex];
|
||||
hasTalentInLastTier = lastLatentOption.Talents.Any(HasTalent);
|
||||
isLastTalentPurchased = lastLatentOption.Talents.Any(t => character.HasTalent(t.Identifier));
|
||||
}
|
||||
|
||||
if (!hasTalentInLastTier)
|
||||
{
|
||||
return TalentTreeStageState.Locked;
|
||||
}
|
||||
|
||||
bool hasPointsForNewTalent = character.Info.GetTotalTalentPoints() - selectedTalents.Count > 0;
|
||||
|
||||
if (hasPointsForNewTalent)
|
||||
{
|
||||
return isLastTalentPurchased ? TalentTreeStageState.Highlighted : TalentTreeStageState.Available;
|
||||
}
|
||||
|
||||
return TalentTreeStageState.Locked;
|
||||
|
||||
bool HasTalent(TalentPrefab t)
|
||||
{
|
||||
return selectedTalents.Contains(t.Identifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool IsViableTalentForCharacter(Character character, string talentIdentifier, IEnumerable<string> selectedTalents)
|
||||
{
|
||||
if (talentIdentifier == PlaceholderTalent) { return false; }
|
||||
if (character?.Info?.Job.Prefab == null) { return false; }
|
||||
if (character.Info.GetTotalTalentPoints() - selectedTalents.Count() <= 0) { return false; }
|
||||
|
||||
@@ -173,12 +230,16 @@ namespace Barotrauma
|
||||
{
|
||||
public string Identifier { get; }
|
||||
|
||||
public string DisplayName { get; }
|
||||
|
||||
public readonly List<TalentOption> TalentOptionStages = new List<TalentOption>();
|
||||
|
||||
public TalentSubTree(XElement subTreeElement)
|
||||
{
|
||||
Identifier = subTreeElement.GetAttributeString("identifier", "");
|
||||
|
||||
DisplayName = TextManager.Get("talenttree." + Identifier, returnNull: true) ?? Identifier;
|
||||
|
||||
foreach (XElement talentOptionsElement in subTreeElement.GetChildElements("talentoptions"))
|
||||
{
|
||||
TalentOptionStages.Add(new TalentOption(talentOptionsElement, Identifier));
|
||||
@@ -196,6 +257,7 @@ namespace Barotrauma
|
||||
foreach (XElement talentOptionElement in talentOptionsElement.GetChildElements("talentoption"))
|
||||
{
|
||||
string identifier = talentOptionElement.GetAttributeString("identifier", string.Empty);
|
||||
|
||||
if (!TalentPrefab.TalentPrefabs.ContainsKey(identifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent tree \"{debugIdentifier}\" - could not find a talent with the identifier \"{identifier}\".");
|
||||
|
||||
Reference in New Issue
Block a user