Exemplo n.º 1
0
        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);
                }
            }
        }
Exemplo n.º 2
0
        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);
                }
            }
        }