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; float lastPickedFraction = 0.0f; if (RepairMultiple) { var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles, allowInsideFixture: true); lastPickedFraction = Submarine.LastPickedFraction; Type lastHitType = null; hitCharacters.Clear(); foreach (Body body in bodies) { 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; } } Character hitCharacter = null; if (body.UserData is Limb limb) { hitCharacter = limb.character; } else if (body.UserData is Character character) { hitCharacter = character; } //only do damage once to each character even if they ray hit multiple limbs if (hitCharacter != null) { if (hitCharacters.Contains(hitCharacter)) { continue; } hitCharacters.Add(hitCharacter); } if (FixBody(user, deltaTime, degreeOfSuccess, body)) { lastPickedFraction = Submarine.LastPickedBodyDist(body); if (bodyType != null) { lastHitType = bodyType; } } } } else { FixBody(user, deltaTime, degreeOfSuccess, Submarine.PickBody(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles, customPredicate: (Fixture f) => { return(f?.Body?.UserData != null); }, allowInsideFixture: true)); lastPickedFraction = Submarine.LastPickedFraction; } if (ExtinguishAmount > 0.0f && item.CurrentHull != null) { fireSourcesInRange.Clear(); //step along the ray in 10% intervals, collecting all fire sources in the range for (float x = 0.0f; x <= lastPickedFraction; x += 0.1f) { Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * x); if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; } Hull hull = Hull.FindHull(displayPos, item.CurrentHull); if (hull == null) { continue; } foreach (FireSource fs in hull.FireSources) { if (fs.IsInDamageRange(displayPos, 100.0f) && !fireSourcesInRange.Contains(fs)) { fireSourcesInRange.Add(fs); } } } foreach (FireSource fs in fireSourcesInRange) { fs.Extinguish(deltaTime, ExtinguishAmount); #if SERVER GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime); #endif } } if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime) { Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f); if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; } new FireSource(displayPos); } } }
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; //if the item can cut off limbs, activate nearby bodies to allow the raycast to hit them if (statusEffectLists != null && statusEffectLists.ContainsKey(ActionType.OnUse)) { if (statusEffectLists[ActionType.OnUse].Any(s => s.SeverLimbsProbability > 0.0f)) { float rangeSqr = ConvertUnits.ToSimUnits(Range); rangeSqr *= rangeSqr; foreach (Character c in Character.CharacterList) { if (!c.Enabled || !c.AnimController.BodyInRest) { continue; } //do a broad check first if (Math.Abs(c.WorldPosition.X - item.WorldPosition.X) > 1000.0f) { continue; } if (Math.Abs(c.WorldPosition.Y - item.WorldPosition.Y) > 1000.0f) { continue; } foreach (Limb limb in c.AnimController.Limbs) { if (Vector2.DistanceSquared(limb.SimPosition, item.SimPosition) < rangeSqr && Vector2.Dot(rayEnd - rayStart, limb.SimPosition - rayStart) > 0) { c.AnimController.BodyInRest = false; break; } } } } } float lastPickedFraction = 0.0f; if (RepairMultiple) { var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, customPredicate: (Fixture f) => { if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure) { return(false); } if (f.Body?.UserData as string == "ruinroom") { return(false); } return(true); }, allowInsideFixture: true); lastPickedFraction = Submarine.LastPickedFraction; Type lastHitType = null; hitCharacters.Clear(); foreach (Body body in bodies) { 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; } } Character hitCharacter = null; if (body.UserData is Limb limb) { hitCharacter = limb.character; } else if (body.UserData is Character character) { hitCharacter = character; } //only do damage once to each character even if they ray hit multiple limbs if (hitCharacter != null) { if (hitCharacters.Contains(hitCharacter)) { continue; } hitCharacters.Add(hitCharacter); } if (FixBody(user, deltaTime, degreeOfSuccess, body)) { lastPickedFraction = Submarine.LastPickedBodyDist(body); if (bodyType != null) { lastHitType = bodyType; } } } } else { FixBody(user, deltaTime, degreeOfSuccess, Submarine.PickBody(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, customPredicate: (Fixture f) => { if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure) { return(false); } if (f.Body?.UserData as string == "ruinroom") { return(false); } if (f.Body?.UserData is Item targetItem) { if (!HitItems) { return(false); } if (HitBrokenDoors) { if (targetItem.GetComponent <Door>() == null && targetItem.Condition <= 0) { return(false); } } else { if (targetItem.Condition <= 0) { return(false); } } } return(f.Body?.UserData != null); }, allowInsideFixture: true)); lastPickedFraction = Submarine.LastPickedFraction; } if (ExtinguishAmount > 0.0f && item.CurrentHull != null) { fireSourcesInRange.Clear(); //step along the ray in 10% intervals, collecting all fire sources in the range for (float x = 0.0f; x <= lastPickedFraction; x += 0.1f) { Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * x); if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; } Hull hull = Hull.FindHull(displayPos, item.CurrentHull); if (hull == null) { continue; } foreach (FireSource fs in hull.FireSources) { if (fs.IsInDamageRange(displayPos, 100.0f) && !fireSourcesInRange.Contains(fs)) { fireSourcesInRange.Add(fs); } } } foreach (FireSource fs in fireSourcesInRange) { fs.Extinguish(deltaTime, ExtinguishAmount); #if SERVER GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime); #endif } } if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime) { Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f); if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; } new FireSource(displayPos); } } }