From 79bb912a53e1ebf62285a6fd5ca671d9d413c975 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 23 May 2019 15:19:08 +0300 Subject: [PATCH] (1da783d84) RepairTool fixes. Closes #1486 - Fixed Submarine.PickBodies only returning the closest body it hits (and the body the ray is inside, if any). - Welding tool raycasts can go through walls, but not fix other types of entities behind the walls. Now it's possible to weld multiple overlapping walls at the same time, but not doors/characters behind the wall. - Made the welding & plasma particles bigger to match the increased range of the tools better. --- .../BarotraumaShared/Source/DebugConsole.cs | 2 +- .../Items/Components/Holdable/RepairTool.cs | 32 +++++++++++++++---- .../BarotraumaShared/Source/Map/Submarine.cs | 25 ++++++++++++--- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index e1acbd9d4..4e0db2462 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -615,7 +615,7 @@ namespace Barotrauma NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White); }, isCheat: true)); - commands.Add(new Command("eventmanager", "eventmanager: Toggle event manager on/off. No new random events are created when the event manager is disabled.", (string[] args) => + commands.Add(new Command("fire|editfire", "fire/editfire: Allows putting up fires by left clicking.", (string[] args) => { Hull.EditFire = !Hull.EditFire; NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs index 0b70d6e8a..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); @@ -232,18 +245,21 @@ namespace Barotrauma.Items.Components targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess); } } + return true; } else if (targetBody.UserData is Character targetCharacter) { 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) { @@ -268,7 +284,9 @@ namespace Barotrauma.Items.Components #endif } FixItemProjSpecific(user, deltaTime, targetItem, prevCondition); + return true; } + return false; } partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex); 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; }