diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs index afa1d3daf..90748c3f2 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs @@ -606,7 +606,7 @@ namespace Barotrauma .ThenByDescending(a => a.Strength).FirstOrDefault(); if (affliction.DamagePerSecond > 0 || affliction.Strength > 0) { - var limbHealth = GetMathingLimbHealth(affliction); + var limbHealth = GetMatchingLimbHealth(affliction); if (limbHealth != null) { selectedLimbIndex = limbHealths.IndexOf(limbHealth); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs index c18db8935..dbf996ddf 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs @@ -202,22 +202,18 @@ namespace Barotrauma if (run || speedMultiplier <= 0.0f) targetMovement *= speedMultiplier; Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update Character.AnimController.TargetMovement = targetMovement; - if (!NeedsDivingGear(Character.CurrentHull)) { bool oxygenLow = Character.OxygenAvailable < CharacterHealth.LowOxygenThreshold; bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0; bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective(); - - // Don't allow to drop the diving suit in water or while climbing or if the current path has stairs - bool removeDivingSuit = - (oxygenLow && !highPressure) || - (!shouldKeepTheGearOn && - Character.CurrentHull.WaterPercentage < 1 && - !Character.IsClimbing && - steeringManager == insideSteering && - !PathSteering.InStairs); - + bool removeDivingSuit = oxygenLow && !highPressure; + if (!removeDivingSuit) + { + bool targetHasNoSuit = objectiveManager.CurrentOrder is AIObjectiveGoTo gtObj && gtObj.mimic && !HasDivingSuit(gtObj.Target as Character); + bool canDropTheSuit = Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs; + removeDivingSuit = (!shouldKeepTheGearOn || targetHasNoSuit) && canDropTheSuit; + } if (removeDivingSuit) { var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit"); @@ -227,7 +223,8 @@ namespace Barotrauma divingSuit.Drop(Character); } } - bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20); + bool targetHasNoMask = objectiveManager.CurrentOrder is AIObjectiveGoTo gotoObjective && gotoObjective.mimic && !HasDivingMask(gotoObjective.Target as Character); + bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20) || targetHasNoMask; if (takeMaskOff) { var mask = Character.Inventory.FindItemByIdentifier("divingmask"); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs index 0ca685008..cec8bfc44 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs @@ -36,7 +36,8 @@ namespace Barotrauma [Serialize(1.0f, true), Editable(MIN_SCALE, MAX_SCALE, DecimalCount = 3)] public float JointScale { get; set; } - [Serialize(1f, true), Editable(DecimalCount = 2)] + // Don't show in the editor, because shouldn't be edited in runtime. Requires that the limb scale and the collider sizes are adjusted. TODO: automatize. + [Serialize(1f, false)] public float TextureScale { get; set; } [Serialize(45f, true), Editable(0f, 1000f)] diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs index 4f5769f34..6425a776e 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs @@ -232,13 +232,13 @@ namespace Barotrauma } private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex]; - private LimbHealth GetMathingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb)); + private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb)); /// /// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb. /// private IEnumerable GetMatchingAfflictions(LimbHealth limb, Func predicate) - => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMathingLimbHealth(a) == limb)); + => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMatchingLimbHealth(a) == limb)); public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs index e39877bdb..a61ce2b23 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs @@ -40,6 +40,9 @@ namespace Barotrauma.Items.Components [Serialize(false, false)] public bool RepairThroughWalls { get; set; } + [Serialize(false, false)] + public bool RepairMultiple { get; set; } + public Vector2 TransformedBarrelPos { get @@ -158,12 +161,22 @@ namespace Barotrauma.Items.Components private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List ignoredBodies) { var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair; - if (RepairThroughWalls) + if (RepairMultiple) { var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true); + Type lastHitType = null; foreach (Body body in bodies) { - FixBody(user, deltaTime, degreeOfSuccess, body); + Type bodyType = body.UserData?.GetType(); + if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType) + { + //stop the ray if it already hit a door/wall and is now about to hit some other type of entity + if (lastHitType == typeof(Item) || lastHitType == typeof(Structure)) { break; } + } + if (FixBody(user, deltaTime, degreeOfSuccess, body)) + { + if (bodyType != null) { lastHitType = bodyType; } + } } } else @@ -202,19 +215,19 @@ namespace Barotrauma.Items.Components } } - private void FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody) + private bool FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody) { - if (targetBody?.UserData == null) { return; } + if (targetBody?.UserData == null) { return false; } pickedPosition = Submarine.LastPickedPosition; if (targetBody.UserData is Structure targetStructure) { - if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return; - if (targetStructure.IsPlatform) return; + if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return false; } + if (targetStructure.IsPlatform) { return false; } int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition)); - if (sectionIndex < 0) return; + if (sectionIndex < 0) { return false; } FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex); targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user); @@ -239,12 +252,14 @@ namespace Barotrauma.Items.Components targetCharacter.LastDamageSource = item; ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List() { targetCharacter }); FixCharacterProjSpecific(user, deltaTime, targetCharacter); + return true; } else if (targetBody.UserData is Limb targetLimb) { targetLimb.character.LastDamageSource = item; ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List() { targetLimb.character, targetLimb }); FixCharacterProjSpecific(user, deltaTime, targetLimb.character); + return true; } else if (targetBody.UserData is Item targetItem) { @@ -269,6 +284,7 @@ namespace Barotrauma.Items.Components #endif } FixItemProjSpecific(user, deltaTime, targetItem, prevCondition); + return true; } return false; } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index f9620770f..2cb8f3192 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -730,7 +730,15 @@ namespace Barotrauma return closestBody; } - public static List PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate customPredicate = null, bool allowInsideFixture = false) + private static readonly Dictionary bodyDist = new Dictionary(); + private static readonly List bodies = new List(); + + /// + /// Returns a list of physics bodies the ray intersects with, sorted according to distance (the closest body is at the beginning of the list). + /// + /// Can be used to filter the bodies based on some condition. If the predicate returns false, the body isignored. + /// Should fixtures that the start of the ray is inside be returned + public static IEnumerable PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate customPredicate = null, bool allowInsideFixture = false) { if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f) { @@ -738,20 +746,25 @@ namespace Barotrauma } float closestFraction = 1.0f; - List bodies = new List(); + bodies.Clear(); + bodyDist.Clear(); GameMain.World.RayCast((fixture, point, normal, fraction) => { if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; } - if (fixture.Body != null) { bodies.Add(fixture.Body); } + if (fixture.Body != null) + { + bodies.Add(fixture.Body); + bodyDist[fixture.Body] = fraction; + } if (fraction < closestFraction) { lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction; lastPickedFraction = fraction; lastPickedNormal = normal; } - - return fraction; + //continue + return -1; }, rayStart, rayEnd); if (allowInsideFixture) @@ -770,10 +783,12 @@ namespace Barotrauma lastPickedFraction = 0.0f; lastPickedNormal = Vector2.Normalize(rayEnd - rayStart); bodies.Add(fixture.Body); + bodyDist[fixture.Body] = 0.0f; return false; }, ref aabb); } + bodies.Sort((b1, b2) => { return bodyDist[b1].CompareTo(bodyDist[b2]); }); return bodies; }