Build 0.20.7.0
This commit is contained in:
@@ -102,6 +102,8 @@ namespace Barotrauma
|
||||
|
||||
private bool inDetectable;
|
||||
|
||||
public double InDetectableSetTime;
|
||||
|
||||
/// <summary>
|
||||
/// Should be reset to false each frame and kept indetectable by e.g. a status effect.
|
||||
/// </summary>
|
||||
@@ -115,7 +117,8 @@ namespace Barotrauma
|
||||
{
|
||||
inDetectable = value;
|
||||
if (inDetectable)
|
||||
{
|
||||
{
|
||||
InDetectableSetTime = Timing.TotalTime;
|
||||
NeedsUpdate = true;
|
||||
}
|
||||
}
|
||||
@@ -257,9 +260,14 @@ namespace Barotrauma
|
||||
SightRange -= speed * deltaTime * (MaxSightRange / FadeOutTime);
|
||||
}
|
||||
|
||||
public bool HasSector()
|
||||
{
|
||||
return sectorRad < MathHelper.TwoPi;
|
||||
}
|
||||
|
||||
public bool IsWithinSector(Vector2 worldPosition)
|
||||
{
|
||||
if (sectorRad >= MathHelper.TwoPi) { return true; }
|
||||
if (!HasSector()) { return true; }
|
||||
Vector2 diff = worldPosition - WorldPosition;
|
||||
return Math.Abs(MathUtils.GetShortestAngle(MathUtils.VectorToAngle(diff), MathUtils.VectorToAngle(sectorDir))) <= sectorRad * 0.5f;
|
||||
}
|
||||
|
||||
@@ -1083,7 +1083,7 @@ namespace Barotrauma
|
||||
State = AIState.Idle;
|
||||
return;
|
||||
}
|
||||
else
|
||||
else if (!owner.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI))
|
||||
{
|
||||
SelectedAiTarget = owner.AiTarget;
|
||||
}
|
||||
@@ -2147,7 +2147,6 @@ namespace Barotrauma
|
||||
if (SelectedAiTarget?.Entity == null) { return false; }
|
||||
if (AttackLimb?.attack == null) { return false; }
|
||||
if (damageTarget == null) { return false; }
|
||||
ActiveAttack = AttackLimb.attack;
|
||||
if (wallTarget != null)
|
||||
{
|
||||
// If the selected target is not the wall target, make the wall target the selected target.
|
||||
@@ -2156,9 +2155,10 @@ namespace Barotrauma
|
||||
{
|
||||
SelectTarget(aiTarget, GetTargetMemory(SelectedAiTarget, addIfNotFound: true).Priority);
|
||||
State = AIState.Attack;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (damageTarget == null) { return false; }
|
||||
ActiveAttack = AttackLimb.attack;
|
||||
if (ActiveAttack.Ranged && ActiveAttack.RequiredAngleToShoot > 0)
|
||||
{
|
||||
Limb referenceLimb = GetLimbToRotate(ActiveAttack);
|
||||
@@ -3810,6 +3810,7 @@ namespace Barotrauma
|
||||
{
|
||||
SelectTarget(door.Item.AiTarget, SelectedTargetMemory.Priority);
|
||||
State = AIState.Attack;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3881,9 +3882,8 @@ namespace Barotrauma
|
||||
return targetLimb;
|
||||
}
|
||||
|
||||
private Character GetOwner(Item item)
|
||||
private static Character GetOwner(Item item)
|
||||
{
|
||||
// If the item is held by a character, attack the character instead.
|
||||
var pickable = item.GetComponent<Pickable>();
|
||||
if (pickable != null)
|
||||
{
|
||||
|
||||
+2
-20
@@ -413,28 +413,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ApplyTreatment(Affliction affliction, Item item)
|
||||
{
|
||||
var targetLimb = targetCharacter.CharacterHealth.GetAfflictionLimb(affliction);
|
||||
bool remove = false;
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (!ic.HasRequiredContainedItems(user: character, addMessage: false)) { continue; }
|
||||
#if CLIENT
|
||||
ic.PlaySound(ActionType.OnUse, character);
|
||||
#endif
|
||||
ic.WasUsed = true;
|
||||
ic.ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: character);
|
||||
if (ic.DeleteOnUse)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
Entity.Spawner?.AddItemToRemoveQueue(item);
|
||||
}
|
||||
item.ApplyTreatment(character, targetCharacter, targetCharacter.CharacterHealth.GetAfflictionLimb(affliction));
|
||||
}
|
||||
|
||||
protected override bool CheckObjectiveSpecific()
|
||||
|
||||
+19
-17
@@ -1371,7 +1371,7 @@ namespace Barotrauma
|
||||
|
||||
Limb head = GetLimb(LimbType.Head);
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
|
||||
|
||||
Vector2 headDiff = targetHead == null ? diff : targetHead.SimPosition - character.SimPosition;
|
||||
targetMovement = new Vector2(diff.X, 0.0f);
|
||||
TargetDir = headDiff.X > 0.0f ? Direction.Right : Direction.Left;
|
||||
@@ -1386,15 +1386,25 @@ namespace Barotrauma
|
||||
|
||||
float prevVitality = target.Vitality;
|
||||
bool wasCritical = prevVitality < 0.0f;
|
||||
|
||||
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
|
||||
{
|
||||
target.Oxygen += deltaTime * 0.5f; //Stabilize them
|
||||
}
|
||||
|
||||
float cprBoost = character.GetStatValue(StatTypes.CPRBoost);
|
||||
|
||||
|
||||
int skill = (int)character.GetSkillLevel("medical");
|
||||
|
||||
if (GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
if (cprBoost >= 1f)
|
||||
{
|
||||
//prevent the patient from suffocating no matter how fast their oxygen level is dropping
|
||||
target.Oxygen = Math.Max(target.Oxygen, -10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//pump for 15 seconds (cprAnimTimer 0-15), then do mouth-to-mouth for 2 seconds (cprAnimTimer 15-17)
|
||||
if (cprAnimTimer > 15.0f && targetHead != null && head != null)
|
||||
{
|
||||
@@ -1405,23 +1415,15 @@ namespace Barotrauma
|
||||
torso.PullJointEnabled = true;
|
||||
|
||||
//Serverside code
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
if (GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
if (target.Oxygen < -10.0f)
|
||||
{
|
||||
if (cprBoost >= 1f)
|
||||
{
|
||||
//prevent the patient from suffocating no matter how fast their oxygen level is dropping
|
||||
target.Oxygen = Math.Max(target.Oxygen, -10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
//stabilize the oxygen level but don't allow it to go positive and revive the character yet
|
||||
float stabilizationAmount = skill * CPRSettings.Active.StabilizationPerSkill;
|
||||
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.Active.StabilizationMin, CPRSettings.Active.StabilizationMax);
|
||||
character.Oxygen -= 1.0f / stabilizationAmount * deltaTime; //Worse skill = more oxygen required
|
||||
if (character.Oxygen > 0.0f) { target.Oxygen += stabilizationAmount * deltaTime; } //we didn't suffocate yet did we
|
||||
}
|
||||
//stabilize the oxygen level but don't allow it to go positive and revive the character yet
|
||||
float stabilizationAmount = skill * CPRSettings.Active.StabilizationPerSkill;
|
||||
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.Active.StabilizationMin, CPRSettings.Active.StabilizationMax);
|
||||
character.Oxygen -= 1.0f / stabilizationAmount * deltaTime; //Worse skill = more oxygen required
|
||||
if (character.Oxygen > 0.0f) { target.Oxygen += stabilizationAmount * deltaTime; } //we didn't suffocate yet did we
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Barotrauma
|
||||
FriendlyNPC = 3
|
||||
}
|
||||
|
||||
public readonly record struct TalentResistanceIdentifier(Identifier ResistanceIdentifier, Identifier TalentIdentifier);
|
||||
|
||||
partial class Character : Entity, IDamageable, ISerializableEntity, IClientSerializable, IServerPositionSync
|
||||
{
|
||||
public readonly static List<Character> CharacterList = new List<Character>();
|
||||
@@ -347,7 +349,7 @@ namespace Barotrauma
|
||||
private readonly Dictionary<ItemPrefab, double> itemSelectedDurations = new Dictionary<ItemPrefab, double>();
|
||||
private double itemSelectedTime;
|
||||
|
||||
public float InvisibleTimer;
|
||||
public float InvisibleTimer { get; set; }
|
||||
|
||||
public readonly CharacterPrefab Prefab;
|
||||
|
||||
@@ -1372,7 +1374,28 @@ namespace Barotrauma
|
||||
tags.RemoveWhere(t => t.StartsWith("variant"));
|
||||
tags.Add($"variant{headId.Value}".ToIdentifier());
|
||||
}
|
||||
var oldHeadInfo = Info.Head;
|
||||
Info.RecreateHead(tags.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||
if (hairIndex == -1)
|
||||
{
|
||||
Info.Head.HairIndex = oldHeadInfo.HairIndex;
|
||||
}
|
||||
if (beardIndex == -1)
|
||||
{
|
||||
Info.Head.BeardIndex = oldHeadInfo.BeardIndex;
|
||||
}
|
||||
if (moustacheIndex == -1)
|
||||
{
|
||||
Info.Head.MoustacheIndex = oldHeadInfo.MoustacheIndex;
|
||||
}
|
||||
if (faceAttachmentIndex == -1)
|
||||
{
|
||||
Info.Head.FaceAttachmentIndex = oldHeadInfo.FaceAttachmentIndex;
|
||||
}
|
||||
Info.Head.SkinColor = oldHeadInfo.SkinColor;
|
||||
Info.Head.HairColor = oldHeadInfo.HairColor;
|
||||
Info.Head.FacialHairColor = oldHeadInfo.FacialHairColor;
|
||||
Info.CheckColors();
|
||||
#if CLIENT
|
||||
head.RecreateSprites();
|
||||
#endif
|
||||
@@ -3050,7 +3073,8 @@ namespace Barotrauma
|
||||
ApplyStatusEffects(AnimController.InWater ? ActionType.InWater : ActionType.NotInWater, deltaTime);
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime);
|
||||
|
||||
if (aiTarget != null)
|
||||
//wait 0.1 seconds so status effects that continuously set InDetectable to true can keep the character InDetectable
|
||||
if (aiTarget != null && Timing.TotalTime > aiTarget.InDetectableSetTime + 0.1f)
|
||||
{
|
||||
aiTarget.InDetectable = false;
|
||||
}
|
||||
@@ -5087,25 +5111,48 @@ namespace Barotrauma
|
||||
return abilityFlags.HasFlag(abilityFlag) || CharacterHealth.HasFlag(abilityFlag);
|
||||
}
|
||||
|
||||
private readonly Dictionary<Identifier, float> abilityResistances = new Dictionary<Identifier, float>();
|
||||
|
||||
private readonly Dictionary<TalentResistanceIdentifier, float> abilityResistances = new();
|
||||
|
||||
public float GetAbilityResistance(AfflictionPrefab affliction)
|
||||
{
|
||||
return abilityResistances.TryGetValue(affliction.Identifier, out float value) ? value : abilityResistances.TryGetValue(affliction.AfflictionType, out float typeValue) ? typeValue : 1f;
|
||||
float resistance = 0f;
|
||||
bool hadResistance = false;
|
||||
|
||||
foreach (var (key, value) in abilityResistances)
|
||||
{
|
||||
if (key.ResistanceIdentifier == affliction.AfflictionType ||
|
||||
key.ResistanceIdentifier == affliction.Identifier)
|
||||
{
|
||||
resistance += value;
|
||||
hadResistance = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hadResistance ? resistance : 1f;
|
||||
}
|
||||
|
||||
public void ChangeAbilityResistance(Identifier resistanceId, float value)
|
||||
public void ChangeAbilityResistance(TalentResistanceIdentifier identifier, float value)
|
||||
{
|
||||
if (abilityResistances.ContainsKey(resistanceId))
|
||||
if (!MathUtils.IsValid(value))
|
||||
{
|
||||
abilityResistances[resistanceId] *= value;
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Attempted to set ability resistance to an invalid value ({value})\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (abilityResistances.ContainsKey(identifier))
|
||||
{
|
||||
abilityResistances[identifier] *= value;
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityResistances.Add(resistanceId, value);
|
||||
abilityResistances.Add(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAbilityResistance(TalentResistanceIdentifier identifier) => abilityResistances.Remove(identifier);
|
||||
|
||||
/// <summary>
|
||||
/// Compares just the species name and the group, ignores teams. There's a more complex version found in HumanAIController.cs
|
||||
/// </summary>
|
||||
|
||||
@@ -63,27 +63,34 @@ namespace Barotrauma
|
||||
public readonly CharacterInfo CharacterInfo;
|
||||
public readonly HeadPreset Preset;
|
||||
|
||||
private int hairIndex;
|
||||
public int HairIndex { get; set; }
|
||||
|
||||
public int HairIndex
|
||||
private int? hairWithHatIndex;
|
||||
|
||||
public void SetHairWithHatIndex()
|
||||
{
|
||||
get => hairIndex;
|
||||
set
|
||||
if (CharacterInfo.Hairs is null)
|
||||
{
|
||||
hairIndex = value;
|
||||
if (CharacterInfo.Hairs is null)
|
||||
if (HairIndex == -1)
|
||||
{
|
||||
HairWithHatIndex = value;
|
||||
return;
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Setting \"hairWithHatIndex\" before \"Hairs\" are defined!");
|
||||
#else
|
||||
DebugConsole.AddWarning("Setting \"hairWithHatIndex\" before \"Hairs\" are defined!");
|
||||
#endif
|
||||
}
|
||||
HairWithHatIndex = HairElement?.GetAttributeInt("replacewhenwearinghat", hairIndex) ?? -1;
|
||||
if (HairWithHatIndex < 0 || HairWithHatIndex >= CharacterInfo.Hairs.Count)
|
||||
hairWithHatIndex = HairIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
hairWithHatIndex = HairElement?.GetAttributeInt("replacewhenwearinghat", HairIndex) ?? -1;
|
||||
if (hairWithHatIndex < 0 || hairWithHatIndex >= CharacterInfo.Hairs.Count)
|
||||
{
|
||||
HairWithHatIndex = hairIndex;
|
||||
hairWithHatIndex = HairIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int HairWithHatIndex { get; private set; }
|
||||
|
||||
public int BeardIndex;
|
||||
public int MoustacheIndex;
|
||||
public int FaceAttachmentIndex;
|
||||
@@ -99,26 +106,29 @@ namespace Barotrauma
|
||||
get
|
||||
{
|
||||
if (CharacterInfo.Hairs == null) { return null; }
|
||||
if (hairIndex >= CharacterInfo.Hairs.Count)
|
||||
if (HairIndex >= CharacterInfo.Hairs.Count)
|
||||
{
|
||||
DebugConsole.AddWarning($"Hair index out of range (character: {CharacterInfo?.Name ?? "null"}, index: {hairIndex})");
|
||||
DebugConsole.AddWarning($"Hair index out of range (character: {CharacterInfo?.Name ?? "null"}, index: {HairIndex})");
|
||||
}
|
||||
return CharacterInfo.Hairs.ElementAtOrDefault(hairIndex);
|
||||
return CharacterInfo.Hairs.ElementAtOrDefault(HairIndex);
|
||||
}
|
||||
}
|
||||
public ContentXElement HairWithHatElement
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CharacterInfo.Hairs == null) { return null; }
|
||||
if (HairWithHatIndex >= CharacterInfo.Hairs.Count)
|
||||
if (hairWithHatIndex == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Hair with hat index out of range (character: {CharacterInfo?.Name ?? "null"}, index: {HairWithHatIndex})");
|
||||
SetHairWithHatIndex();
|
||||
}
|
||||
return CharacterInfo.Hairs.ElementAtOrDefault(HairWithHatIndex);
|
||||
if (CharacterInfo.Hairs == null) { return null; }
|
||||
if (hairWithHatIndex >= CharacterInfo.Hairs.Count)
|
||||
{
|
||||
DebugConsole.AddWarning($"Hair with hat index out of range (character: {CharacterInfo?.Name ?? "null"}, index: {hairWithHatIndex})");
|
||||
}
|
||||
return CharacterInfo.Hairs.ElementAtOrDefault(hairWithHatIndex.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public ContentXElement BeardElement
|
||||
{
|
||||
get
|
||||
@@ -711,7 +721,7 @@ namespace Barotrauma
|
||||
private bool IsColorValid(in Color clr)
|
||||
=> clr.R != 0 || clr.G != 0 || clr.B != 0;
|
||||
|
||||
private void CheckColors()
|
||||
public void CheckColors()
|
||||
{
|
||||
if (!IsColorValid(Head.HairColor))
|
||||
{
|
||||
|
||||
+10
-2
@@ -27,6 +27,14 @@ namespace Barotrauma
|
||||
get { return _strength; }
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Attempted to set an affliction to an invalid strength ({value})\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (_nonClampedStrength < 0 && value > 0)
|
||||
{
|
||||
_nonClampedStrength = value;
|
||||
@@ -440,9 +448,9 @@ namespace Barotrauma
|
||||
{
|
||||
statusEffect.Apply(type, deltaTime, characterHealth.Character, targetLimb);
|
||||
}
|
||||
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
if (characterHealth?.Character?.AnimController?.Limbs != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
{
|
||||
statusEffect.Apply(type, deltaTime, targetLimb.character, targets: targetLimb.character.AnimController.Limbs);
|
||||
statusEffect.Apply(type, deltaTime, characterHealth.Character, targets: characterHealth.Character.AnimController.Limbs);
|
||||
}
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
|
||||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
|
||||
|
||||
+43
-35
@@ -405,45 +405,53 @@ namespace Barotrauma
|
||||
|
||||
var root = doc.Root.FromPackage(pathToAppendage.ContentPackage);
|
||||
var limbElements = root.GetChildElements("limb").ToDictionary(e => e.GetAttributeString("id", null), e => e);
|
||||
//the IDs may need to be offset if the character has other extra appendages (e.g. from gene splicing)
|
||||
//that take up the IDs of this appendage
|
||||
int idOffset = 0;
|
||||
foreach (var jointElement in root.GetChildElements("joint"))
|
||||
{
|
||||
if (limbElements.TryGetValue(jointElement.GetAttributeString("limb2", null), out ContentXElement limbElement))
|
||||
if (!limbElements.TryGetValue(jointElement.GetAttributeString("limb2", null), out ContentXElement limbElement)) { continue; }
|
||||
|
||||
var jointParams = new RagdollParams.JointParams(jointElement, ragdoll.RagdollParams);
|
||||
Limb attachLimb = null;
|
||||
if (matchingAffliction.AttachLimbId > -1)
|
||||
{
|
||||
var jointParams = new RagdollParams.JointParams(jointElement, ragdoll.RagdollParams);
|
||||
Limb attachLimb = null;
|
||||
if (matchingAffliction.AttachLimbId > -1)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == matchingAffliction.AttachLimbId);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbName != null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Name == matchingAffliction.AttachLimbName);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbType != LimbType.None)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.type == matchingAffliction.AttachLimbType);
|
||||
}
|
||||
if (attachLimb == null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == jointParams.Limb1);
|
||||
}
|
||||
if (attachLimb != null)
|
||||
{
|
||||
jointParams.Limb1 = attachLimb.Params.ID;
|
||||
var appendageLimbParams = new RagdollParams.LimbParams(limbElement, ragdoll.RagdollParams)
|
||||
{
|
||||
// Ensure that we have a valid id for the new limb
|
||||
ID = ragdoll.Limbs.Length
|
||||
};
|
||||
jointParams.Limb2 = appendageLimbParams.ID;
|
||||
Limb huskAppendage = new Limb(ragdoll, character, appendageLimbParams);
|
||||
huskAppendage.body.Submarine = character.Submarine;
|
||||
huskAppendage.body.SetTransform(attachLimb.SimPosition, attachLimb.Rotation);
|
||||
ragdoll.AddLimb(huskAppendage);
|
||||
ragdoll.AddJoint(jointParams);
|
||||
appendage.Add(huskAppendage);
|
||||
}
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == matchingAffliction.AttachLimbId);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbName != null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Name == matchingAffliction.AttachLimbName);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbType != LimbType.None)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.type == matchingAffliction.AttachLimbType);
|
||||
}
|
||||
if (attachLimb == null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == jointParams.Limb1);
|
||||
}
|
||||
if (attachLimb != null)
|
||||
{
|
||||
jointParams.Limb1 = attachLimb.Params.ID;
|
||||
//the joint attaches to a limb outside the character's normal limb count = to another part of the appendage
|
||||
// -> if the appendage's IDs have been offset, we need to take that into account to attach to the correct limb
|
||||
if (jointParams.Limb1 >= ragdoll.RagdollParams.Limbs.Count)
|
||||
{
|
||||
jointParams.Limb1 += idOffset;
|
||||
}
|
||||
var appendageLimbParams = new RagdollParams.LimbParams(limbElement, ragdoll.RagdollParams);
|
||||
if (idOffset == 0)
|
||||
{
|
||||
idOffset = ragdoll.Limbs.Length - appendageLimbParams.ID;
|
||||
}
|
||||
jointParams.Limb2 = appendageLimbParams.ID = ragdoll.Limbs.Length;
|
||||
Limb huskAppendage = new Limb(ragdoll, character, appendageLimbParams);
|
||||
huskAppendage.body.Submarine = character.Submarine;
|
||||
huskAppendage.body.SetTransform(attachLimb.SimPosition, attachLimb.Rotation);
|
||||
ragdoll.AddLimb(huskAppendage);
|
||||
ragdoll.AddJoint(jointParams);
|
||||
appendage.Add(huskAppendage);
|
||||
}
|
||||
}
|
||||
return appendage;
|
||||
}
|
||||
|
||||
@@ -887,7 +887,7 @@ namespace Barotrauma
|
||||
//clamp above 0.1 (no amount of oxygen low resistance should keep the character alive indefinitely)
|
||||
float decreaseSpeed = Math.Max(0.1f, 1f - oxygenlowResistance);
|
||||
//the character dies of oxygen deprivation in 100 seconds after losing consciousness
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount - decreaseSpeed * deltaTime, -100.0f, 100.0f);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount - decreaseSpeed * deltaTime, -100.0f, 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -895,15 +895,21 @@ namespace Barotrauma
|
||||
float increaseSpeed = 10.0f;
|
||||
decreaseSpeed *= (1f - oxygenlowResistance);
|
||||
increaseSpeed *= (1f + oxygenlowResistance);
|
||||
|
||||
float holdBreathMultiplier = 1f + GetStatValue(StatTypes.HoldBreathMultiplier);
|
||||
decreaseSpeed *= holdBreathMultiplier;
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f);
|
||||
float holdBreathMultiplier = Character.GetStatValue(StatTypes.HoldBreathMultiplier);
|
||||
if (holdBreathMultiplier <= -1.0f)
|
||||
{
|
||||
OxygenAmount = -100.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
decreaseSpeed /= 1.0f + Character.GetStatValue(StatTypes.HoldBreathMultiplier);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateOxygenProjSpecific(prevOxygen, deltaTime);
|
||||
}
|
||||
|
||||
|
||||
partial void UpdateOxygenProjSpecific(float prevOxygen, float deltaTime);
|
||||
|
||||
partial void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb, float deltaTime);
|
||||
|
||||
-1
@@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+8
-8
@@ -1,7 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGainSimultaneousSkill : CharacterAbility
|
||||
{
|
||||
@@ -15,6 +12,10 @@ namespace Barotrauma.Abilities
|
||||
skillIdentifier = abilityElement.GetAttributeIdentifier("skillidentifier", "");
|
||||
ignoreAbilitySkillGain = abilityElement.GetAttributeBool("ignoreabilityskillgain", true);
|
||||
targetAllies = abilityElement.GetAttributeBool("targetallies", false);
|
||||
if (skillIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}: skill identifier not defined.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
@@ -23,13 +24,12 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (ignoreAbilitySkillGain && abilitySkillGain.GainedFromAbility) { return; }
|
||||
Identifier identifier = skillIdentifier == "inherit" ? abilitySkillGain.SkillIdentifier : skillIdentifier;
|
||||
|
||||
if (targetAllies)
|
||||
{
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
foreach (Character otherCharacter in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
if (character == Character) { continue; }
|
||||
Character.Info?.IncreaseSkillLevel(identifier, abilitySkillGain.Value, gainedFromAbility: true);
|
||||
if (otherCharacter == Character) { continue; }
|
||||
otherCharacter.Info?.IncreaseSkillLevel(identifier, abilitySkillGain.Value, gainedFromAbility: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
+2
-4
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveAffliction : CharacterAbility
|
||||
{
|
||||
@@ -18,7 +16,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
if (afflictionId.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in CharacterAbilityGiveAffliction - affliction identifier not set.");
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, CharacterAbilityGiveAffliction - affliction identifier not set.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveFlag : CharacterAbility
|
||||
{
|
||||
|
||||
+6
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveMoney : CharacterAbility
|
||||
{
|
||||
@@ -13,6 +11,11 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
amount = abilityElement.GetAttributeInt("amount", 0);
|
||||
scalingStatIdentifier = abilityElement.GetAttributeIdentifier("scalingstatidentifier", Identifier.Empty);
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, CharacterAbilityGiveMoney - amount of money set to 0.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyEffectSpecific(Character targetCharacter)
|
||||
|
||||
+5
-3
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
public enum PermanentStatPlaceholder
|
||||
{
|
||||
@@ -28,6 +26,10 @@ namespace Barotrauma.Abilities
|
||||
public CharacterAbilityGivePermanentStat(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statIdentifier = abilityElement.GetAttributeIdentifier("statidentifier", Identifier.Empty);
|
||||
if (statIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent \"{CharacterTalent.DebugIdentifier}\" - stat identifier not defined.");
|
||||
}
|
||||
string statTypeName = abilityElement.GetAttributeString("stattype", string.Empty);
|
||||
statType = string.IsNullOrEmpty(statTypeName) ? StatTypes.None : CharacterAbilityGroup.ParseStatType(statTypeName, CharacterTalent.DebugIdentifier);
|
||||
value = abilityElement.GetAttributeFloat("value", 0f);
|
||||
|
||||
+8
@@ -11,6 +11,14 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
factionIdentifier = abilityElement.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
amount = abilityElement.GetAttributeFloat("amount", 0f);
|
||||
if (factionIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, faction identifier not defined.");
|
||||
}
|
||||
if (amount == 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, amount of reputation to give is 0.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
|
||||
+9
-5
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveResistance : CharacterAbility
|
||||
{
|
||||
@@ -10,17 +8,23 @@ namespace Barotrauma.Abilities
|
||||
public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
resistanceId = abilityElement.GetAttributeIdentifier("resistanceid", abilityElement.GetAttributeIdentifier("resistance", Identifier.Empty));
|
||||
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f); // rename this to resistance for consistency
|
||||
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
|
||||
|
||||
if (resistanceId.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in CharacterAbilityGiveResistance - resistance identifier not set.");
|
||||
}
|
||||
if (MathUtils.NearlyEqual(multiplier, 1))
|
||||
{
|
||||
DebugConsole.AddWarning($"Possible error in talent {CharacterTalent.DebugIdentifier} - multiplier set to 1, which will do nothing.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
{
|
||||
Character.ChangeAbilityResistance(resistanceId, multiplier);
|
||||
TalentResistanceIdentifier identifier = new(resistanceId, CharacterTalent.Prefab.Identifier);
|
||||
Character.ChangeAbilityResistance(identifier, multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveStat : CharacterAbility
|
||||
{
|
||||
|
||||
+6
-5
@@ -1,7 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveTalentPoints : CharacterAbility
|
||||
{
|
||||
@@ -9,7 +6,11 @@ namespace Barotrauma.Abilities
|
||||
|
||||
public CharacterAbilityGiveTalentPoints(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
amount = abilityElement.GetAttributeInt("amount", 0);
|
||||
amount = abilityElement.GetAttributeInt("amount", 0);
|
||||
if (amount == 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, amount of talent points to give is 0.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
|
||||
+4
@@ -9,6 +9,10 @@ namespace Barotrauma.Abilities
|
||||
public CharacterAbilityGiveTalentPointsToAllies(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
amount = abilityElement.GetAttributeInt("amount", 0);
|
||||
if (amount == 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, amount of talent points to give is 0.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
|
||||
-2
@@ -1,6 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+4
@@ -6,6 +6,10 @@ namespace Barotrauma.Abilities
|
||||
public CharacterAbilityMarkAsLooted(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
identifier = abilityElement.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
if (identifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, identifier is empty in {nameof(CharacterAbilityMarkAsLooted)}.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
|
||||
+1
-4
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyFlag : CharacterAbility
|
||||
{
|
||||
|
||||
+18
-8
@@ -1,23 +1,25 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyResistance : CharacterAbility
|
||||
{
|
||||
private readonly Identifier resistanceId;
|
||||
private readonly float resistance;
|
||||
private readonly float multiplier;
|
||||
bool lastState;
|
||||
public override bool AllowClientSimulation => true;
|
||||
|
||||
// should probably be split to different classes
|
||||
public CharacterAbilityModifyResistance(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
resistanceId = abilityElement.GetAttributeIdentifier("resistanceid", "");
|
||||
resistance = abilityElement.GetAttributeFloat("resistance", 1f);
|
||||
resistanceId = abilityElement.GetAttributeIdentifier("resistanceid", abilityElement.GetAttributeIdentifier("resistance", Identifier.Empty));
|
||||
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
|
||||
|
||||
if (resistanceId.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in CharacterAbilityModifyResistance - resistance identifier not set.");
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier} - resistance identifier not set in {nameof(CharacterAbilityModifyResistance)}.");
|
||||
}
|
||||
if (MathUtils.NearlyEqual(multiplier, 1.0f))
|
||||
{
|
||||
DebugConsole.AddWarning($"Possible error in talent {CharacterTalent.DebugIdentifier} - resistance set to 1, which will do nothing.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +27,15 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (conditionsMatched != lastState)
|
||||
{
|
||||
Character.ChangeAbilityResistance(resistanceId, conditionsMatched ? resistance : 1 / resistance);
|
||||
TalentResistanceIdentifier identifier = new(resistanceId, CharacterTalent.Prefab.Identifier);
|
||||
if (conditionsMatched)
|
||||
{
|
||||
Character.ChangeAbilityResistance(identifier, multiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
Character.RemoveAbilityResistance(identifier);
|
||||
}
|
||||
lastState = conditionsMatched;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyStat : CharacterAbility
|
||||
{
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+5
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyValue : CharacterAbility
|
||||
{
|
||||
@@ -11,6 +9,10 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||
if (MathUtils.NearlyEqual(addedValue, 0.0f) && MathUtils.NearlyEqual(multiplyValue, 1.0f))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, {nameof(CharacterAbilityModifyValue)} - added value is 0 and multiplier is 1, the ability will do nothing.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityPutItem : CharacterAbility
|
||||
{
|
||||
|
||||
+5
-1
@@ -9,7 +9,11 @@ namespace Barotrauma.Abilities
|
||||
|
||||
public CharacterAbilityResetPermanentStat(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statIdentifier = abilityElement.GetAttributeIdentifier("statidentifier", Identifier.Empty);
|
||||
statIdentifier = abilityElement.GetAttributeIdentifier("statidentifier", Identifier.Empty);
|
||||
if (statIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, {nameof(CharacterAbilityResetPermanentStat)} - statIdentifier is empty.");
|
||||
}
|
||||
}
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
|
||||
+1
-4
@@ -1,7 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityRevive : CharacterAbility
|
||||
{
|
||||
|
||||
+4
@@ -11,6 +11,10 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
identifier = abilityElement.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
value = abilityElement.GetAttributeInt("value", 0);
|
||||
if (identifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}, {nameof(CharacterAbilitySetMetadataInt)} - identifier is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApprenticeship : CharacterAbility
|
||||
{
|
||||
|
||||
-3
@@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityAtmosMachine : CharacterAbility
|
||||
{
|
||||
private readonly float addedValue;
|
||||
private readonly float multiplyValue;
|
||||
private readonly Identifier[] tags;
|
||||
private readonly int maxMultiplyCount;
|
||||
|
||||
public CharacterAbilityAtmosMachine(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||
tags = abilityElement.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>());
|
||||
maxMultiplyCount = abilityElement.GetAttributeInt("maxmultiplycount", int.MaxValue);
|
||||
}
|
||||
|
||||
+2
-5
@@ -1,11 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityBountyHunter : CharacterAbility
|
||||
{
|
||||
private float vitalityPercentage;
|
||||
private readonly float vitalityPercentage;
|
||||
|
||||
public CharacterAbilityBountyHunter(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+1
-4
@@ -1,7 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityMultitasker : CharacterAbility
|
||||
{
|
||||
|
||||
+4
-6
@@ -1,12 +1,10 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityPsychoClown : CharacterAbility
|
||||
{
|
||||
private StatTypes statType;
|
||||
private float maxValue;
|
||||
private string afflictionIdentifier;
|
||||
private readonly StatTypes statType;
|
||||
private readonly float maxValue;
|
||||
private readonly string afflictionIdentifier;
|
||||
private float lastValue = 0f;
|
||||
public override bool AllowClientSimulation => true;
|
||||
|
||||
|
||||
-3
@@ -1,8 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
#nullable enable
|
||||
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace Barotrauma
|
||||
IEnumerable<TalentSubTree> blockingSubTrees = tree.TalentSubTrees.Where(tst => tst.BlockedTrees.Contains(targetTree.Identifier)),
|
||||
requiredSubTrees = tree.TalentSubTrees.Where(tst => targetTree.RequiredTrees.Contains(tst.Identifier));
|
||||
|
||||
return requiredSubTrees.All(tst => tst.IsCompleted(selectedTalents)) && // check if we meet requirements
|
||||
!blockingSubTrees.Any(tst => tst.HasAnyTalent(selectedTalents)); // check if any other talent trees are blocking this one
|
||||
return requiredSubTrees.All(tst => tst.HasEnoughTalents(selectedTalents)) && // check if we meet requirements
|
||||
!blockingSubTrees.Any(tst => tst.HasAnyTalent(selectedTalents) && !tst.HasMaxTalents(selectedTalents)); // check if any other talent trees are blocking this one
|
||||
}
|
||||
|
||||
// i hate this function - markus
|
||||
@@ -128,16 +128,26 @@ namespace Barotrauma
|
||||
public static bool IsViableTalentForCharacter(Character character, Identifier talentIdentifier, IReadOnlyCollection<Identifier> selectedTalents)
|
||||
{
|
||||
if (character?.Info?.Job.Prefab == null) { return false; }
|
||||
|
||||
if (character.Info.GetTotalTalentPoints() - selectedTalents.Count <= 0) { return false; }
|
||||
|
||||
if (!JobTalentTrees.TryGet(character.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return false; }
|
||||
|
||||
foreach (var subTree in talentTree!.TalentSubTrees)
|
||||
{
|
||||
if (subTree.AllTalentIdentifiers.Contains(talentIdentifier) && subTree.HasMaxTalents(selectedTalents)) { return false; }
|
||||
|
||||
foreach (var talentOptionStage in subTree.TalentOptionStages)
|
||||
{
|
||||
bool hasTalentInThisTier = talentOptionStage.HasEnoughTalents(selectedTalents);
|
||||
if (talentOptionStage.TalentIdentifiers.Contains(talentIdentifier))
|
||||
{
|
||||
return TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
|
||||
}
|
||||
bool optionStageCompleted = talentOptionStage.HasEnoughTalents(selectedTalents);
|
||||
if (!optionStageCompleted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/*bool hasTalentInThisTier = talentOptionStage.HasMaxTalents(selectedTalents);
|
||||
if (!hasTalentInThisTier)
|
||||
{
|
||||
if (talentOptionStage.TalentIdentifiers.Contains(talentIdentifier))
|
||||
@@ -145,7 +155,7 @@ namespace Barotrauma
|
||||
return TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +206,8 @@ namespace Barotrauma
|
||||
public readonly ImmutableHashSet<Identifier> RequiredTrees;
|
||||
public readonly ImmutableHashSet<Identifier> BlockedTrees;
|
||||
|
||||
public bool IsCompleted(IReadOnlyCollection<Identifier> talents) => TalentOptionStages.All(option => option.HasEnoughTalents(talents));
|
||||
public bool HasEnoughTalents(IReadOnlyCollection<Identifier> talents) => TalentOptionStages.All(option => option.HasEnoughTalents(talents));
|
||||
public bool HasMaxTalents(IReadOnlyCollection<Identifier> talents) => TalentOptionStages.All(option => option.HasMaxTalents(talents));
|
||||
public bool HasAnyTalent(IReadOnlyCollection<Identifier> talents) => TalentOptionStages.Any(option => option.HasSelectedTalent(talents));
|
||||
|
||||
public TalentSubTree(ContentXElement subTreeElement)
|
||||
@@ -228,6 +239,13 @@ namespace Barotrauma
|
||||
|
||||
public IEnumerable<Identifier> TalentIdentifiers => talentIdentifiers;
|
||||
|
||||
/// <summary>
|
||||
/// How many talents need to be unlocked to consider this tree completed
|
||||
/// </summary>
|
||||
public readonly int RequiredTalents;
|
||||
/// <summary>
|
||||
/// How many talents can be unlocked in total
|
||||
/// </summary>
|
||||
public readonly int MaxChosenTalents;
|
||||
|
||||
/// <summary>
|
||||
@@ -236,8 +254,9 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public readonly Dictionary<Identifier, ImmutableHashSet<Identifier>> ShowCaseTalents = new Dictionary<Identifier, ImmutableHashSet<Identifier>>();
|
||||
|
||||
public bool HasEnoughTalents(CharacterInfo character) => CountMatchingTalents(character.UnlockedTalents) >= MaxChosenTalents;
|
||||
public bool HasEnoughTalents(IReadOnlyCollection<Identifier> selectedTalents) => CountMatchingTalents(selectedTalents) >= MaxChosenTalents;
|
||||
public bool HasEnoughTalents(CharacterInfo character) => CountMatchingTalents(character.UnlockedTalents) >= RequiredTalents;
|
||||
public bool HasEnoughTalents(IReadOnlyCollection<Identifier> selectedTalents) => CountMatchingTalents(selectedTalents) >= RequiredTalents;
|
||||
public bool HasMaxTalents(IReadOnlyCollection<Identifier> selectedTalents) => CountMatchingTalents(selectedTalents) >= MaxChosenTalents;
|
||||
|
||||
// No LINQ
|
||||
public bool HasSelectedTalent(IReadOnlyCollection<Identifier> selectedTalents)
|
||||
@@ -267,10 +286,15 @@ namespace Barotrauma
|
||||
|
||||
public TalentOption(ContentXElement talentOptionsElement, Identifier debugIdentifier)
|
||||
{
|
||||
MaxChosenTalents = talentOptionsElement.GetAttributeInt("maxchosentalents", 1);
|
||||
MaxChosenTalents = talentOptionsElement.GetAttributeInt(nameof(MaxChosenTalents), 1);
|
||||
RequiredTalents = talentOptionsElement.GetAttributeInt(nameof(RequiredTalents), MaxChosenTalents);
|
||||
|
||||
if (RequiredTalents > MaxChosenTalents)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent tree {debugIdentifier} - MaxChosenTalents is larger than RequiredTalents.");
|
||||
}
|
||||
|
||||
HashSet<Identifier> identifiers = new HashSet<Identifier>();
|
||||
|
||||
foreach (ContentXElement talentOptionElement in talentOptionsElement.Elements())
|
||||
{
|
||||
Identifier elementName = talentOptionElement.Name.ToIdentifier();
|
||||
@@ -293,6 +317,15 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
talentIdentifiers = identifiers.ToImmutableHashSet();
|
||||
|
||||
if (RequiredTalents > talentIdentifiers.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent tree {debugIdentifier} - completing a stage of the tree requires more talents than there are in the stage.");
|
||||
}
|
||||
if (MaxChosenTalents > talentIdentifiers.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent tree {debugIdentifier} - maximum number of talents to choose is larger than the number of talents.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user