(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.

This commit is contained in:
Joonas Rikkonen
2019-05-23 15:19:08 +03:00
parent a95f1b7186
commit 79bb912a53
3 changed files with 46 additions and 13 deletions
@@ -615,7 +615,7 @@ namespace Barotrauma
NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White); NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White);
}, isCheat: true)); }, 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; Hull.EditFire = !Hull.EditFire;
NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White); NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White);
@@ -40,6 +40,9 @@ namespace Barotrauma.Items.Components
[Serialize(false, false)] [Serialize(false, false)]
public bool RepairThroughWalls { get; set; } public bool RepairThroughWalls { get; set; }
[Serialize(false, false)]
public bool RepairMultiple { get; set; }
public Vector2 TransformedBarrelPos public Vector2 TransformedBarrelPos
{ {
get get
@@ -158,12 +161,22 @@ namespace Barotrauma.Items.Components
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies) private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
{ {
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair; 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); var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
Type lastHitType = null;
foreach (Body body in bodies) 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 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; pickedPosition = Submarine.LastPickedPosition;
if (targetBody.UserData is Structure targetStructure) if (targetBody.UserData is Structure targetStructure)
{ {
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return; if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return false; }
if (targetStructure.IsPlatform) return; if (targetStructure.IsPlatform) { return false; }
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition)); int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
if (sectionIndex < 0) return; if (sectionIndex < 0) { return false; }
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex); FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user); targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
@@ -232,18 +245,21 @@ namespace Barotrauma.Items.Components
targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess); targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess);
} }
} }
return true;
} }
else if (targetBody.UserData is Character targetCharacter) else if (targetBody.UserData is Character targetCharacter)
{ {
targetCharacter.LastDamageSource = item; targetCharacter.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter }); ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter });
FixCharacterProjSpecific(user, deltaTime, targetCharacter); FixCharacterProjSpecific(user, deltaTime, targetCharacter);
return true;
} }
else if (targetBody.UserData is Limb targetLimb) else if (targetBody.UserData is Limb targetLimb)
{ {
targetLimb.character.LastDamageSource = item; targetLimb.character.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb }); ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb });
FixCharacterProjSpecific(user, deltaTime, targetLimb.character); FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
return true;
} }
else if (targetBody.UserData is Item targetItem) else if (targetBody.UserData is Item targetItem)
{ {
@@ -268,7 +284,9 @@ namespace Barotrauma.Items.Components
#endif #endif
} }
FixItemProjSpecific(user, deltaTime, targetItem, prevCondition); FixItemProjSpecific(user, deltaTime, targetItem, prevCondition);
return true;
} }
return false;
} }
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex); partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
@@ -730,7 +730,15 @@ namespace Barotrauma
return closestBody; return closestBody;
} }
public static List<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false) private static readonly Dictionary<Body, float> bodyDist = new Dictionary<Body, float>();
private static readonly List<Body> bodies = new List<Body>();
/// <summary>
/// Returns a list of physics bodies the ray intersects with, sorted according to distance (the closest body is at the beginning of the list).
/// </summary>
/// <param name="customPredicate">Can be used to filter the bodies based on some condition. If the predicate returns false, the body isignored.</param>
/// <param name="allowInsideFixture">Should fixtures that the start of the ray is inside be returned</param>
public static IEnumerable<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false)
{ {
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f) if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
{ {
@@ -738,20 +746,25 @@ namespace Barotrauma
} }
float closestFraction = 1.0f; float closestFraction = 1.0f;
List<Body> bodies = new List<Body>(); bodies.Clear();
bodyDist.Clear();
GameMain.World.RayCast((fixture, point, normal, fraction) => GameMain.World.RayCast((fixture, point, normal, fraction) =>
{ {
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; } 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) if (fraction < closestFraction)
{ {
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction; lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
lastPickedFraction = fraction; lastPickedFraction = fraction;
lastPickedNormal = normal; lastPickedNormal = normal;
} }
//continue
return fraction; return -1;
}, rayStart, rayEnd); }, rayStart, rayEnd);
if (allowInsideFixture) if (allowInsideFixture)
@@ -770,10 +783,12 @@ namespace Barotrauma
lastPickedFraction = 0.0f; lastPickedFraction = 0.0f;
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart); lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
bodies.Add(fixture.Body); bodies.Add(fixture.Body);
bodyDist[fixture.Body] = 0.0f;
return false; return false;
}, ref aabb); }, ref aabb);
} }
bodies.Sort((b1, b2) => { return bodyDist[b1].CompareTo(bodyDist[b2]); });
return bodies; return bodies;
} }