Build 0.21.6.0 (1.0 pre-patch)

This commit is contained in:
Regalis11
2023-01-31 18:08:26 +02:00
parent e1c04bc31d
commit cf9ecd35b3
231 changed files with 4479 additions and 2276 deletions
@@ -31,6 +31,9 @@ namespace Barotrauma
{
public readonly static List<Character> CharacterList = new List<Character>();
public const float MaxHighlightDistance = 150.0f;
public const float MaxDragDistance = 200.0f;
partial void UpdateLimbLightSource(Limb limb);
private bool enabled = true;
@@ -354,9 +357,15 @@ namespace Barotrauma
public readonly CharacterPrefab Prefab;
public readonly CharacterParams Params;
public Identifier SpeciesName => Params?.SpeciesName ?? "null".ToIdentifier();
public Identifier Group => Params.Group;
public bool IsHumanoid => Params.Humanoid;
public bool IsMachine => Params.IsMachine;
public bool IsHusk => Params.Husk;
public bool IsMale => info?.IsMale ?? false;
@@ -480,7 +489,7 @@ namespace Barotrauma
LocalizedString displayName = Params.DisplayName;
if (displayName.IsNullOrWhiteSpace())
{
if (string.IsNullOrWhiteSpace(Params.SpeciesTranslationOverride))
if (Params.SpeciesTranslationOverride.IsEmpty)
{
displayName = TextManager.Get($"Character.{SpeciesName}");
}
@@ -743,7 +752,7 @@ namespace Barotrauma
get
{
if (IsUnconscious) { return true; }
return CharacterHealth.GetAllAfflictions().Any(a => a.Prefab.AfflictionType == "paralysis" && a.Strength >= a.Prefab.MaxStrength);
return CharacterHealth.GetAllAfflictions().Any(a => a.Prefab.Identifier == "paralysis" && a.Strength >= a.Prefab.MaxStrength);
}
}
@@ -805,9 +814,15 @@ namespace Barotrauma
public float HealthPercentage => CharacterHealth.HealthPercentage;
public float MaxVitality => CharacterHealth.MaxVitality;
public float MaxHealth => MaxVitality;
/// <summary>
/// Was the character in full health at the beginning of the frame?
/// </summary>
public bool WasFullHealth => CharacterHealth.WasInFullHealth;
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 PoisonVulnerability => Params.Health.PoisonVulnerability;
public float Bloodloss
{
@@ -1026,6 +1041,8 @@ namespace Barotrauma
public bool InWater => AnimController is AnimController { InWater: true };
public bool IsLowInOxygen => NeedsOxygen && OxygenAvailable < CharacterHealth.LowOxygenThreshold;
public bool GodMode = false;
public CampaignMode.InteractionType CampaignInteractionType;
@@ -1741,7 +1758,7 @@ namespace Barotrauma
float maxSpeed = ApplyTemporarySpeedLimits(currentSpeed);
targetMovement.X = MathHelper.Clamp(targetMovement.X, -maxSpeed, maxSpeed);
targetMovement.Y = MathHelper.Clamp(targetMovement.Y, -maxSpeed, maxSpeed);
SpeedMultiplier = greatestPositiveSpeedMultiplier - (1f - greatestNegativeSpeedMultiplier);
SpeedMultiplier = Math.Max(0.0f, greatestPositiveSpeedMultiplier - (1f - greatestNegativeSpeedMultiplier));
targetMovement *= SpeedMultiplier;
// Reset, status effects will set the value before the next update
ResetSpeedMultiplier();
@@ -2201,7 +2218,9 @@ namespace Barotrauma
if (SelectedCharacter != null)
{
if (Vector2.DistanceSquared(SelectedCharacter.WorldPosition, WorldPosition) > 90000.0f || !SelectedCharacter.CanBeSelected)
if (!SelectedCharacter.CanBeSelected ||
(Vector2.DistanceSquared(SelectedCharacter.WorldPosition, WorldPosition) > MaxDragDistance * MaxDragDistance &&
SelectedCharacter.GetDistanceToClosestLimb(SimPosition) > ConvertUnits.ToSimUnits(MaxDragDistance)))
{
DeselectCharacter();
}
@@ -2494,8 +2513,12 @@ namespace Barotrauma
if (!skipDistanceCheck)
{
maxDist = ConvertUnits.ToSimUnits(maxDist);
if (Vector2.DistanceSquared(SimPosition, c.SimPosition) > maxDist * maxDist) { return false; }
maxDist = Math.Max(ConvertUnits.ToSimUnits(maxDist), c.AnimController.Collider.GetMaxExtent());
if (Vector2.DistanceSquared(SimPosition, c.SimPosition) > maxDist * maxDist &&
Vector2.DistanceSquared(SimPosition, c.AnimController.MainLimb.SimPosition) > maxDist * maxDist)
{
return false;
}
}
return checkVisibility ? CanSeeCharacter(c) : true;
@@ -2851,6 +2874,23 @@ namespace Barotrauma
}
else
{
#if CLIENT
if (Controlled == this)
{
HealingCooldown.PutOnCooldown();
}
#elif SERVER
if (GameMain.Server?.ConnectedClients is { } clients)
{
foreach (Client c in clients)
{
if (c.Character != this) { continue; }
HealingCooldown.SetCooldown(c);
break;
}
}
#endif
SelectCharacter(FocusedCharacter);
#if CLIENT
if (Controlled == this)
@@ -3138,56 +3178,57 @@ namespace Barotrauma
UpdateAIChatMessages(deltaTime);
//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() > 8.0f * 8.0f;
bool wasRagdolled = false;
bool selfRagdolled = false;
if (IsForceRagdolled)
if (GameMain.NetworkMember?.ServerSettings?.AllowRagdollButton ?? true)
{
IsRagdolled = IsForceRagdolled;
}
else if (this != Controlled)
{
wasRagdolled = IsRagdolled;
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll);
}
//Keep us ragdolled if we were forced or we're too speedy to unragdoll
else if (allowRagdoll && (!IsRagdolled || !tooFastToUnragdoll))
{
if (ragdollingLockTimer > 0.0f)
bool wasRagdolled = IsRagdolled;
if (IsForceRagdolled)
{
SetInput(InputType.Ragdoll, false, true);
ragdollingLockTimer -= deltaTime;
IsRagdolled = IsForceRagdolled;
}
else if (this != Controlled)
{
wasRagdolled = IsRagdolled;
IsRagdolled = IsKeyDown(InputType.Ragdoll);
}
else
{
wasRagdolled = IsRagdolled;
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.5f; }
bool tooFastToUnragdoll = bodyMovingTooFast(AnimController.Collider) || bodyMovingTooFast(AnimController.MainLimb.body);
bool bodyMovingTooFast(PhysicsBody body)
{
return
body.LinearVelocity.LengthSquared() > 8.0f * 8.0f ||
//falling down counts as going too fast
(!InWater && body.LinearVelocity.Y < -5.0f);
}
if (ragdollingLockTimer > 0.0f)
{
ragdollingLockTimer -= deltaTime;
}
else if (!tooFastToUnragdoll)
{
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.2f; }
}
if (IsRagdolled)
{
SetInput(InputType.Ragdoll, false, true);
}
}
}
if (!wasRagdolled && IsRagdolled)
{
if (selfRagdolled)
if (!wasRagdolled && IsRagdolled)
{
CheckTalents(AbilityEffectType.OnSelfRagdoll);
CheckTalents(AbilityEffectType.OnRagdoll);
}
// currently does not work when you are stunned, like it should
CheckTalents(AbilityEffectType.OnRagdoll);
}
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
//ragdoll button
if (IsRagdolled || !CanMove)
{
if (AnimController is HumanoidAnimController humanAnimController)
{
humanAnimController.Crouching = false;
}
if (IsRagdolled) { AnimController.IgnorePlatforms = true; }
AnimController.ResetPullJoints();
SelectedItem = SelectedSecondaryItem = null;
return;
@@ -3365,6 +3406,20 @@ namespace Barotrauma
return distSqr;
}
public float GetDistanceToClosestLimb(Vector2 simPos)
{
float closestDist = float.MaxValue;
foreach (Limb limb in AnimController.Limbs)
{
if (limb.IsSevered) { continue; }
float dist = Vector2.Distance(simPos, limb.SimPosition);
dist -= limb.body.GetMaxExtent();
closestDist = Math.Min(closestDist, dist);
if (closestDist <= 0.0f) { return 0.0f; }
}
return closestDist;
}
private float despawnTimer;
private void UpdateDespawn(float deltaTime, bool ignoreThresholds = false, bool createNetworkEvents = true)
{
@@ -3756,9 +3811,10 @@ namespace Barotrauma
message.SendDelay -= deltaTime;
if (message.SendDelay > 0.0f) { continue; }
bool canUseRadio = ChatMessage.CanUseRadio(this, out WifiComponent radio);
if (message.MessageType == null)
{
message.MessageType = ChatMessage.CanUseRadio(this) ? ChatMessageType.Radio : ChatMessageType.Default;
message.MessageType = canUseRadio ? ChatMessageType.Radio : ChatMessageType.Default;
}
#if CLIENT
if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.IsSinglePlayer)
@@ -3768,6 +3824,11 @@ namespace Barotrauma
{
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(Name, modifiedMessage, message.MessageType.Value, this);
}
if (canUseRadio)
{
Signal s = new Signal(modifiedMessage, sender: this, source: radio.Item);
radio.TransmitSignal(s, sentFromChat: true);
}
}
#endif
#if SERVER
@@ -3885,8 +3946,8 @@ namespace Barotrauma
{
foreach (Affliction affliction in attackResult.Afflictions)
{
if (affliction.Strength == 0.0f) continue;
sb.Append($" {affliction.Prefab.Name}: {affliction.Strength}");
if (Math.Abs(affliction.Strength) <= 0.1f) { continue;}
sb.Append($" {affliction.Prefab.Name}: {affliction.Strength.ToString("0.0")}");
}
}
GameServer.Log(sb.ToString(), ServerLog.MessageType.Attack);
@@ -4087,13 +4148,13 @@ namespace Barotrauma
OnAttackedProjSpecific(attacker, attackResult, stun);
if (!wasDead)
{
TryAdjustAttackerSkill(attacker, CharacterHealth.Vitality - prevVitality);
TryAdjustAttackerSkill(attacker, attackResult);
}
};
}
if (attackResult.Damage > 0)
{
LastDamage = attackResult;
if (attacker != null)
if (attacker != null && attacker != this && !attacker.Removed)
{
AddAttacker(attacker, attackResult.Damage);
AddEncounter(attacker);
@@ -4108,26 +4169,84 @@ namespace Barotrauma
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun);
public void TryAdjustAttackerSkill(Character attacker, float healthChange)
public void TryAdjustAttackerSkill(Character attacker, AttackResult attackResult)
{
if (attacker == null) { return; }
if (!attacker.IsOnPlayerTeam) { return; }
bool isEnemy = AIController is EnemyAIController || TeamID != attacker.TeamID;
if (isEnemy)
if (!isEnemy) { return; }
float weaponDamage = 0;
float medicalDamage = 0;
foreach (var affliction in attackResult.Afflictions)
{
if (healthChange < 0.0f)
if (affliction.Prefab.IsBuff) { continue; }
if (Params.IsMachine && !affliction.Prefab.AffectMachines) { continue; }
if (affliction.Prefab.AfflictionType == "poison" || affliction.Prefab.AfflictionType == "paralysis")
{
float attackerSkillLevel = attacker.GetSkillLevel("weapons");
attacker.Info?.IncreaseSkillLevel("weapons".ToIdentifier(),
-healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f));
if (!Params.Health.PoisonImmunity)
{
float relativeVitality = MaxVitality / 100f;
// Undo the applied modifiers to get the base value. Poison damage is multiplied by max vitality when it's applied.
float dmg = affliction.Strength;
if (relativeVitality > 0)
{
dmg /= relativeVitality;
}
if (PoisonVulnerability > 0)
{
dmg /= PoisonVulnerability;
}
float strength = MaxVitality;
if (Params.AI != null)
{
strength = Params.AI.CombatStrength;
}
// Adjust the skill gain by the strength of the target. Combat strength >= 1000 gives 2x bonus, combat strength < 333 less than 1x.
float vitalityFactor = MathHelper.Lerp(0.5f, 2f, MathUtils.InverseLerp(0, 1000, strength));
dmg *= vitalityFactor;
medicalDamage += dmg * affliction.Prefab.MedicalSkillGain;
}
}
else
{
medicalDamage += affliction.GetVitalityDecrease(null) * affliction.Prefab.MedicalSkillGain;
}
weaponDamage += affliction.GetVitalityDecrease(null) * affliction.Prefab.WeaponsSkillGain;
}
else if (healthChange > 0.0f)
if (medicalDamage > 0)
{
float attackerSkillLevel = attacker.GetSkillLevel("medical");
attacker.Info?.IncreaseSkillLevel("medical".ToIdentifier(),
healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f));
IncreaseSkillLevel("medical".ToIdentifier(), medicalDamage);
}
if (weaponDamage > 0)
{
IncreaseSkillLevel("weapons".ToIdentifier(), weaponDamage);
}
void IncreaseSkillLevel(Identifier skill, float damage)
{
float attackerSkillLevel = attacker.GetSkillLevel(skill);
// The formula is too generous on low skill levels, hence the minimum divider.
float minSkillDivider = 15f;
attacker.Info?.IncreaseSkillLevel(skill, damage * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, minSkillDivider));
}
}
public void TryAdjustHealerSkill(Character healer, float healthChange = 0, Affliction affliction = null)
{
if (healer == null) { return; }
bool isEnemy = AIController is EnemyAIController || TeamID != healer.TeamID;
if (isEnemy) { return; }
float medicalGain = healthChange;
if (affliction?.Prefab is { IsBuff: true } && (!Params.IsMachine || affliction.Prefab.AffectMachines))
{
medicalGain += affliction.Strength * affliction.Prefab.MedicalSkillGain;
}
if (medicalGain <= 0) { return; }
Identifier skill = new Identifier("medical");
float attackerSkillLevel = healer.GetSkillLevel(skill);
// The formula is too generous on low skill levels, hence the minimum divider.
float minSkillDivider = 15f;
healer.Info?.IncreaseSkillLevel(skill, medicalGain * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, minSkillDivider));
}
/// <summary>
@@ -4484,7 +4603,10 @@ namespace Barotrauma
#if CLIENT
//ensure we apply any pending inventory updates to drop any items that need to be dropped when the character despawns
Inventory?.ApplyReceivedState();
if (GameMain.Client?.ClientPeer is { IsActive: true })
{
Inventory?.ApplyReceivedState();
}
#endif
base.Remove();
@@ -5200,15 +5322,30 @@ namespace Barotrauma
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>
public bool IsFriendly(Character other) => IsFriendly(this, other);
/// <summary>
/// Compares just the species name and the group, ignores teams. There's a more complex version found in HumanAIController.cs
/// </summary>
public static bool IsFriendly(Character me, Character other) => other.SpeciesName == me.SpeciesName || other.Params.CompareGroup(me.Params.Group);
public static bool IsFriendly(Character me, Character other) => IsOnFriendlyTeam(me, other) && IsSameSpeciesOrGroup(me, other);
public static bool IsOnFriendlyTeam(CharacterTeamType myTeam, CharacterTeamType otherTeam)
{
if (myTeam == otherTeam) { return true; }
return myTeam switch
{
// NPCs are friendly to the same team and the friendly NPCs
CharacterTeamType.None or CharacterTeamType.Team1 or CharacterTeamType.Team2 => otherTeam == CharacterTeamType.FriendlyNPC,
// Friendly NPCs are friendly to both player teams
CharacterTeamType.FriendlyNPC => otherTeam == CharacterTeamType.Team1 || otherTeam == CharacterTeamType.Team2,
_ => true
};
}
public static bool IsOnFriendlyTeam(Character me, Character other) => IsOnFriendlyTeam(me.TeamID, other.TeamID);
public bool IsOnFriendlyTeam(Character other) => IsOnFriendlyTeam(TeamID, other.TeamID);
public bool IsOnFriendlyTeam(CharacterTeamType otherTeam) => IsOnFriendlyTeam(TeamID, otherTeam);
public bool IsSameSpeciesOrGroup(Character other) => IsSameSpeciesOrGroup(this, other);
public static bool IsSameSpeciesOrGroup(Character me, Character other) => other.SpeciesName == me.SpeciesName || other.Params.CompareGroup(me.Params.Group);
public void StopClimbing()
{