Build 0.20.8.0

This commit is contained in:
Markus Isberg
2022-11-25 19:56:30 +02:00
parent ecb6d40b4b
commit df805574c4
111 changed files with 2347 additions and 1283 deletions
@@ -77,11 +77,11 @@ namespace Barotrauma
{
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection)
{
if (Timing.TotalTime < GameMain.GameSession.RoundStartTime + 30.0f) { currentFlags.Add("Initial".ToIdentifier()); }
if (GameMain.GameSession.RoundDuration > 30.0f) { currentFlags.Add("Initial".ToIdentifier()); }
}
else if (Level.Loaded.Type == LevelData.LevelType.Outpost)
{
if (Timing.TotalTime < GameMain.GameSession.RoundStartTime + 120.0f &&
if (GameMain.GameSession.RoundDuration > 120.0f &&
speaker?.CurrentHull != null &&
(speaker.TeamID == CharacterTeamType.FriendlyNPC || speaker.TeamID == CharacterTeamType.None) &&
Character.CharacterList.Any(c => c.TeamID != speaker.TeamID && c.CurrentHull == speaker.CurrentHull))
@@ -206,7 +206,7 @@ namespace Barotrauma
public float Stun { get; private set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Can damage only Humans."), Editable]
public bool OnlyHumans { get; private set; }
public bool OnlyHumans { get; set; }
[Serialize("", IsPropertySaveable.Yes), Editable]
public string ApplyForceOnLimbs
@@ -322,7 +322,7 @@ namespace Barotrauma
List<Affliction> multipliedAfflictions = new List<Affliction>();
foreach (Affliction affliction in Afflictions.Keys)
{
multipliedAfflictions.Add(affliction.CreateMultiplied(multiplier, affliction.Probability));
multipliedAfflictions.Add(affliction.CreateMultiplied(multiplier, affliction));
}
return multipliedAfflictions;
}
@@ -529,7 +529,7 @@ namespace Barotrauma
private Color speechBubbleColor;
private float speechBubbleTimer;
public bool ResetInteract;
public bool DisableInteract { get; set; }
//text displayed when the character is highlighted if custom interact is set
public LocalizedString CustomInteractHUDText { get; private set; }
@@ -798,6 +798,7 @@ namespace Barotrauma
public float MaxHealth => MaxVitality;
public AIState AIState => AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle;
public bool IsLatched => AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached;
public float EmpVulnerability => Params.Health.EmpVulnerability;
public float Bloodloss
{
@@ -845,6 +846,12 @@ namespace Barotrauma
set;
}
public bool IgnoreMeleeWeapons
{
get;
set;
}
/// <summary>
/// Current speed of the character's collider. Can be used by status effects to check if the character is moving.
/// </summary>
@@ -895,6 +902,10 @@ namespace Barotrauma
{
itemSelectedTime = Timing.TotalTime;
}
if (prevSelectedItem != _selectedItem && prevSelectedItem?.OnDeselect != null)
{
prevSelectedItem.OnDeselect(this);
}
}
}
/// <summary>
@@ -2687,9 +2698,9 @@ namespace Barotrauma
return;
}
if (ResetInteract)
if (DisableInteract)
{
ResetInteract = false;
DisableInteract = false;
return;
}
@@ -2710,25 +2721,31 @@ namespace Barotrauma
{
if (!IsMouseOnUI && (ViewTarget == null || ViewTarget == this))
{
if ((findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen) && (!PlayerInput.PrimaryMouseButtonHeld() || Barotrauma.Inventory.DraggingItemToWorld))
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{
FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null;
if (FocusedCharacter != null && !CanSeeCharacter(FocusedCharacter)) { FocusedCharacter = null; }
float aimAssist = GameSettings.CurrentConfig.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f);
if (HeldItems.Any(it => it?.GetComponent<Wire>()?.IsActive ?? false))
if (!PlayerInput.PrimaryMouseButtonHeld() || Barotrauma.Inventory.DraggingItemToWorld)
{
//disable aim assist when rewiring to make it harder to accidentally select items when adding wire nodes
aimAssist = 0.0f;
}
FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null;
if (FocusedCharacter != null && !CanSeeCharacter(FocusedCharacter)) { FocusedCharacter = null; }
float aimAssist = GameSettings.CurrentConfig.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f);
if (HeldItems.Any(it => it?.GetComponent<Wire>()?.IsActive ?? false))
{
//disable aim assist when rewiring to make it harder to accidentally select items when adding wire nodes
aimAssist = 0.0f;
}
var item = FindItemAtPosition(mouseSimPos, aimAssist);
focusedItem = CanInteract ? item : null;
if (focusedItem != null && focusedItem.CampaignInteractionType != CampaignMode.InteractionType.None)
{
FocusedCharacter = null;
focusedItem = CanInteract ? FindItemAtPosition(mouseSimPos, aimAssist) : null;
if (focusedItem != null && focusedItem.CampaignInteractionType != CampaignMode.InteractionType.None)
{
FocusedCharacter = null;
}
findFocusedTimer = 0.05f;
}
else
{
if (focusedItem != null && !CanInteractWith(focusedItem)) { focusedItem = null; }
if (FocusedCharacter != null && !CanInteractWith(FocusedCharacter)) { FocusedCharacter = null; }
}
findFocusedTimer = 0.05f;
}
}
else
@@ -2957,6 +2974,15 @@ namespace Barotrauma
{
UpdateProjSpecific(deltaTime, cam);
if (InvisibleTimer > 0.0f)
{
if (Controlled == null || Controlled == this || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
{
InvisibleTimer = Math.Min(InvisibleTimer, 1.0f);
}
InvisibleTimer -= deltaTime;
}
KnockbackCooldownTimer -= deltaTime;
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && this == Controlled && !isSynced) { return; }
@@ -2996,6 +3022,7 @@ namespace Barotrauma
}
HideFace = false;
IgnoreMeleeWeapons = false;
UpdateSightRange(deltaTime);
UpdateSoundRange(deltaTime);
@@ -4102,7 +4129,13 @@ namespace Barotrauma
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && !isNetworkMessage) { return; }
if (Screen.Selected != GameMain.GameScreen) { return; }
if (newStun > 0 && Params.Health.StunImmunity) { return; }
if (newStun > 0 && Params.Health.StunImmunity)
{
if (EmpVulnerability <= 0 || CharacterHealth.GetAfflictionStrength("emp", allowLimbAfflictions: false) <= 0)
{
return;
}
}
if ((newStun <= Stun && !allowStunDecrease) || !MathUtils.IsValid(newStun)) { return; }
if (Math.Sign(newStun) != Math.Sign(Stun))
{
@@ -1238,7 +1238,7 @@ namespace Barotrauma
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel);
public void GiveExperience(int amount, bool isMissionExperience = false)
public void GiveExperience(int amount)
{
int prevAmount = ExperiencePoints;
@@ -1292,6 +1292,18 @@ namespace Barotrauma
return experienceRequired + ExperienceRequiredPerLevel(level);
}
public int GetExperienceRequiredForLevel(int level)
{
int currentLevel = GetCurrentLevel(out int experienceRequired);
if (currentLevel >= level) { return 0; }
int required = experienceRequired;
for (int i = currentLevel + 1; i <= level; i++)
{
required += ExperienceRequiredPerLevel(i);
}
return required;
}
public int GetCurrentLevel()
{
return GetCurrentLevel(out _);
@@ -1309,7 +1321,7 @@ namespace Barotrauma
return level;
}
private int ExperienceRequiredPerLevel(int level)
private static int ExperienceRequiredPerLevel(int level)
{
return BaseExperienceRequired + AddedExperienceRequiredPerLevel * level;
}
@@ -61,6 +61,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes, description: "Explosion damage is applied per each affected limb. Should this affliction damage be divided by the count of affected limbs (1-15) or applied in full? Default: true. Only affects explosions."), Editable]
public bool DivideByLimbCount { get; set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Is the damage relative to the max vitality (percentage) or absolute (normal)"), Editable]
public bool MultiplyByMaxVitality { get; private set; }
public float DamagePerSecond;
public float DamagePerSecondTimer;
public float PreviousVitalityDecrease;
@@ -104,6 +107,15 @@ namespace Barotrauma
}
}
/// <summary>
/// Copy properties here instead of using SerializableProperties (with reflection).
/// </summary>
public void CopyProperties(Affliction source)
{
Probability = source.Probability;
DivideByLimbCount = source.DivideByLimbCount;
MultiplyByMaxVitality = source.MultiplyByMaxVitality;
}
public void Serialize(XElement element)
{
@@ -115,10 +127,10 @@ namespace Barotrauma
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
}
public Affliction CreateMultiplied(float multiplier, float probability)
public Affliction CreateMultiplied(float multiplier, Affliction affliction)
{
var instance = Prefab.Instantiate(NonClampedStrength * multiplier, Source);
instance.Probability = probability;
instance.CopyProperties(affliction);
return instance;
}
@@ -693,8 +693,15 @@ namespace Barotrauma
if (Character.Params.IsMachine && !newAffliction.Prefab.AffectMachines) { return; }
if (!DoesBleed && newAffliction is AfflictionBleeding) { return; }
if (!Character.NeedsOxygen && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; }
if (Character.Params.Health.StunImmunity && newAffliction.Prefab.AfflictionType == "stun") { return; }
if (Character.Params.Health.StunImmunity && newAffliction.Prefab.AfflictionType == "stun")
{
if (Character.EmpVulnerability <= 0 || GetAfflictionStrength("emp", allowLimbAfflictions: false) <= 0)
{
return;
}
}
if (Character.Params.Health.PoisonImmunity && newAffliction.Prefab.AfflictionType == "poison") { return; }
if (Character.EmpVulnerability <= 0 && newAffliction.Prefab.AfflictionType == "emp") { return; }
if (newAffliction.Prefab is AfflictionPrefabHusk huskPrefab)
{
if (huskPrefab.TargetSpecies.None(s => s == Character.SpeciesName))
@@ -757,6 +757,10 @@ namespace Barotrauma
}
if (!foundMatchingModifier && random > affliction.Probability) { continue; }
float finalDamageModifier = damageMultiplier;
if (affliction.Prefab.AfflictionType == "emp" && character.EmpVulnerability > 0)
{
finalDamageModifier *= character.EmpVulnerability;
}
foreach (DamageModifier damageModifier in tempModifiers)
{
float damageModifierValue = damageModifier.DamageMultiplier;
@@ -766,9 +770,13 @@ namespace Barotrauma
}
finalDamageModifier *= damageModifierValue;
}
if (affliction.MultiplyByMaxVitality)
{
finalDamageModifier *= character.MaxVitality / 100f;
}
if (!MathUtils.NearlyEqual(finalDamageModifier, 1.0f))
{
newAffliction = affliction.CreateMultiplied(finalDamageModifier, affliction.Probability);
newAffliction = affliction.CreateMultiplied(finalDamageModifier, affliction);
}
else
{
@@ -501,6 +501,9 @@ namespace Barotrauma
[Serialize(false, IsPropertySaveable.Yes), Editable]
public bool PoisonImmunity { get; set; }
[Serialize(0f, IsPropertySaveable.Yes), Editable]
public float EmpVulnerability { get; set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Can afflictions affect the face/body tint of the character."), Editable]
public bool ApplyAfflictionColors { get; private set; }
@@ -37,14 +37,19 @@ namespace Barotrauma.Abilities
{
if (GameMain.GameSession?.Campaign?.Factions is not { } factions) { return false; }
// FIXME there's probably a better way to check the faction affiliated with the mission later
foreach (Identifier factionIdentifier in mission.ReputationRewards.Keys)
foreach (var (factionIdentifier, amount) in mission.ReputationRewards)
{
if (factions.Where(faction => factionIdentifier == faction.Prefab.Identifier).Any(static faction => faction.GetPlayerAffiliationStatus() != FactionAffiliation.Affiliated))
if (amount <= 0) { continue; }
Faction faction = factions.FirstOrDefault(faction => factionIdentifier == faction.Prefab.Identifier);
if (faction?.GetPlayerAffiliationStatus() is FactionAffiliation.Affiliated)
{
return false;
return true;
}
}
return false;
}
return missionType.Contains(mission.Prefab.Type);
@@ -5,15 +5,33 @@ internal sealed class CharacterAbilityGiveExperience : CharacterAbility
public override bool AppliesEffectOnIntervalUpdate => true;
private readonly int amount;
private readonly int level;
public CharacterAbilityGiveExperience(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
amount = abilityElement.GetAttributeInt("amount", 0);
level = abilityElement.GetAttributeInt("level", 0);
if (amount == 0 && level == 0)
{
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier} - no exp amount or level defined in {nameof(CharacterAbilityGiveExperience)}.");
}
if (amount > 0 && level > 0)
{
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier} - {nameof(CharacterAbilityGiveExperience)} defines both an exp amount and a level.");
}
}
private void ApplyEffectSpecific(Character targetCharacter)
{
targetCharacter.Info?.GiveExperience(amount);
if (amount != 0)
{
targetCharacter.Info?.GiveExperience(amount);
}
if (level > 0)
{
targetCharacter.Info?.GiveExperience(targetCharacter.Info.GetExperienceRequiredForLevel(level));
}
}
protected override void ApplyEffect(AbilityObject abilityObject)
@@ -1,26 +0,0 @@
namespace Barotrauma.Abilities
{
class CharacterAbilityRevive : CharacterAbility
{
public override bool AppliesEffectOnIntervalUpdate => true;
public CharacterAbilityRevive(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
}
private void ApplyEffectSpecific()
{
Character.Revive(removeAllAfflictions: false);
}
protected override void ApplyEffect()
{
ApplyEffectSpecific();
}
protected override void ApplyEffect(AbilityObject abilityObject)
{
ApplyEffectSpecific();
}
}
}
@@ -35,10 +35,8 @@ namespace Barotrauma.Abilities
foreach (Identifier identifier in selectedTalentTree)
{
if (Character.HasTalent(identifier)) { continue; }
if (Character.GiveTalent(identifier))
{
Character.Info.AdditionalTalentPoints++;
}
Character.GiveTalent(identifier);
}
}
@@ -139,23 +139,13 @@ namespace Barotrauma
{
if (talentOptionStage.TalentIdentifiers.Contains(talentIdentifier))
{
return TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
return !talentOptionStage.HasMaxTalents(selectedTalents) && TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
}
bool optionStageCompleted = talentOptionStage.HasEnoughTalents(selectedTalents);
if (!optionStageCompleted)
{
break;
}
/*bool hasTalentInThisTier = talentOptionStage.HasMaxTalents(selectedTalents);
if (!hasTalentInThisTier)
{
if (talentOptionStage.TalentIdentifiers.Contains(talentIdentifier))
{
return TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
}
break;
}*/
}
}