Пример #1
0
        public static void CreateItems(List <PurchasedItem> itemsToSpawn, Submarine sub)
        {
            if (itemsToSpawn.Count == 0)
            {
                return;
            }

            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, sub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

            if (sub == Submarine.MainSub)
            {
#if CLIENT
                new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon");
#else
                foreach (Client client in GameMain.Server.ConnectedClients)
                {
                    ChatMessage msg = ChatMessage.Create("",
                                                         TextManager.ContainsTag(cargoRoom.RoomName) ? $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}" : $"CargoSpawnNotification~[roomname]={cargoRoom.RoomName}",
                                                         ChatMessageType.ServerMessageBoxInGame, null);
                    msg.IconStyle = "StoreShoppingCrateIcon";
                    GameMain.Server.SendDirectChatMessage(msg, client);
                }
#endif
            }

            List <ItemContainer> availableContainers = new List <ItemContainer>();
            ItemPrefab           containerPrefab     = null;
            foreach (PurchasedItem pi in itemsToSpawn)
            {
                Vector2 position = GetCargoPos(cargoRoom, pi.ItemPrefab);

                for (int i = 0; i < pi.Quantity; i++)
                {
                    ItemContainer itemContainer = null;
                    if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier))
                    {
                        itemContainer = availableContainers.Find(ac =>
                                                                 ac.Inventory.CanBePut(pi.ItemPrefab) &&
                                                                 (ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                  ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())));

                        if (itemContainer == null)
                        {
                            containerPrefab = ItemPrefab.Prefabs.Find(ep =>
                                                                      ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                      (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())));

                            if (containerPrefab == null)
                            {
                                DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + pi.ItemPrefab.CargoContainerIdentifier + "\"!");
                                continue;
                            }

                            Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                            itemContainer = containerItem.GetComponent <ItemContainer>();
                            if (itemContainer == null)
                            {
                                DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                                continue;
                            }
                            availableContainers.Add(itemContainer);
    #if SERVER
                            if (GameMain.Server != null)
                            {
                                Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                            }
    #endif
                        }
                    }

                    if (itemContainer == null)
                    {
                        //no container, place at the waypoint
                        if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                        {
                            Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine, onSpawned: itemSpawned);
                        }
                        else
                        {
                            var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                            itemSpawned(item);
                        }
                        continue;
                    }

                    //place in the container
                    if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                    {
                        Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory, onSpawned: itemSpawned);
                    }
                    else
                    {
                        var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                        itemContainer.Inventory.TryPutItem(item, null);
                        itemSpawned(item);
                    }
Пример #2
0
 partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull);
Пример #3
0
        public void Explode(Vector2 worldPosition, Entity damageSource, Character attacker = null)
        {
            prevExplosions.Add(new Triplet <Explosion, Vector2, float>(this, worldPosition, (float)Timing.TotalTime));
            if (prevExplosions.Count > 100)
            {
                prevExplosions.RemoveAt(0);
            }

            Hull hull = Hull.FindHull(worldPosition);

            ExplodeProjSpecific(worldPosition, hull);

            float displayRange = attack.Range;

            if (displayRange < 0.1f)
            {
                return;
            }

            Vector2 cameraPos  = Character.Controlled != null ? Character.Controlled.WorldPosition : GameMain.GameScreen.Cam.Position;
            float   cameraDist = Vector2.Distance(cameraPos, worldPosition) / 2.0f;

            GameMain.GameScreen.Cam.Shake = CameraShake * Math.Max((displayRange - cameraDist) / displayRange, 0.0f);

            if (attack.GetStructureDamage(1.0f) > 0.0f)
            {
                RangedStructureDamage(worldPosition, displayRange, attack.GetStructureDamage(1.0f), attacker);
            }

            if (empStrength > 0.0f)
            {
                float displayRangeSqr = displayRange * displayRange;
                foreach (Item item in Item.ItemList)
                {
                    float distSqr = Vector2.DistanceSquared(item.WorldPosition, worldPosition);
                    if (distSqr > displayRangeSqr)
                    {
                        continue;
                    }

                    float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange;

                    //damage repairable power-consuming items
                    var powered = item.GetComponent <Powered>();
                    if (powered == null || !powered.VulnerableToEMP)
                    {
                        continue;
                    }
                    if (item.Repairables.Any())
                    {
                        item.Condition -= 100 * empStrength * distFactor;
                    }

                    //discharge batteries
                    var powerContainer = item.GetComponent <PowerContainer>();
                    if (powerContainer != null)
                    {
                        powerContainer.Charge -= powerContainer.Capacity * empStrength * distFactor;
                    }
                }
            }

            if (MathUtils.NearlyEqual(force, 0.0f) && MathUtils.NearlyEqual(attack.Stun, 0.0f) && MathUtils.NearlyEqual(attack.GetTotalDamage(false), 0.0f))
            {
                return;
            }

            DamageCharacters(worldPosition, attack, force, damageSource, attacker);

            if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
            {
                if (flames)
                {
                    foreach (Item item in Item.ItemList)
                    {
                        if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f)
                        {
                            continue;
                        }

                        //don't apply OnFire effects if the item is inside a fireproof container
                        //(or if it's inside a container that's inside a fireproof container, etc)
                        Item container = item.Container;
                        bool fireProof = false;
                        while (container != null)
                        {
                            if (container.FireProof)
                            {
                                fireProof = true; break;
                            }
                            container = container.Container;
                        }

                        if (fireProof || Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.5f)
                        {
                            continue;
                        }

                        item.ApplyStatusEffects(ActionType.OnFire, 1.0f);
                        if (item.Condition <= 0.0f && GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                        {
                            GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
                        }

                        if (item.Prefab.DamagedByExplosions && !item.Indestructible)
                        {
                            float limbRadius = item.body == null ? 0.0f : item.body.GetMaxExtent();
                            float dist       = Vector2.Distance(item.WorldPosition, worldPosition);
                            dist = Math.Max(0.0f, dist - ConvertUnits.ToDisplayUnits(limbRadius));

                            if (dist > attack.Range)
                            {
                                continue;
                            }

                            float distFactor   = 1.0f - dist / attack.Range;
                            float damageAmount = attack.GetItemDamage(1.0f);
                            item.Condition -= damageAmount * distFactor;
                        }
                    }
                }
            }
        }
Пример #4
0
        void UpdateRoomToRoom(float deltaTime, Hull hull1, Hull hull2)
        {
            Vector2 subOffset = Vector2.Zero;

            if (hull1.Submarine != Submarine)
            {
                subOffset = Submarine.Position - hull1.Submarine.Position;
            }
            else if (hull2.Submarine != Submarine)
            {
                subOffset = hull2.Submarine.Position - Submarine.Position;
            }

            if (hull1.WaterVolume <= 0.0 && hull2.WaterVolume <= 0.0)
            {
                return;
            }

            float size = IsHorizontal ? rect.Height : rect.Width;

            //a variable affecting the water flow through the gap
            //the larger the gap is, the faster the water flows
            float sizeModifier = size / 100.0f * open;

            //horizontal gap (such as a regular door)
            if (IsHorizontal)
            {
                higherSurface = Math.Max(hull1.Surface, hull2.Surface + subOffset.Y);
                float delta = 0.0f;

                //water level is above the lower boundary of the gap
                if (Math.Max(hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1], hull2.Surface + subOffset.Y + hull2.WaveY[0]) > rect.Y - size)
                {
                    int dir = (hull1.Pressure > hull2.Pressure + subOffset.Y) ? 1 : -1;

                    //water flowing from the righthand room to the lefthand room
                    if (dir == -1)
                    {
                        if (!(hull2.WaterVolume > 0.0f))
                        {
                            return;
                        }
                        lowerSurface = hull1.Surface - hull1.WaveY[hull1.WaveY.Length - 1];
                        //delta = Math.Min((room2.water.pressure - room1.water.pressure) * sizeModifier, Math.Min(room2.water.Volume, room2.Volume));
                        //delta = Math.Min(delta, room1.Volume - room1.water.Volume + Water.MaxCompress);

                        flowTargetHull = hull1;

                        //make sure not to move more than what the room contains
                        delta = Math.Min(((hull2.Pressure + subOffset.Y) - hull1.Pressure) * 5.0f * sizeModifier, Math.Min(hull2.WaterVolume, hull2.Volume));

                        //make sure not to place more water to the target room than it can hold
                        delta              = Math.Min(delta, hull1.Volume * Hull.MaxCompress - (hull1.WaterVolume));
                        hull1.WaterVolume += delta;
                        hull2.WaterVolume -= delta;
                        if (hull1.WaterVolume > hull1.Volume)
                        {
                            hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure + subOffset.Y) / 2);
                        }

                        flowForce = new Vector2(-delta, 0.0f);
                    }
                    else if (dir == 1)
                    {
                        if (!(hull1.WaterVolume > 0.0f))
                        {
                            return;
                        }
                        lowerSurface = hull2.Surface - hull2.WaveY[hull2.WaveY.Length - 1];

                        flowTargetHull = hull2;

                        //make sure not to move more than what the room contains
                        delta = Math.Min((hull1.Pressure - (hull2.Pressure + subOffset.Y)) * 5.0f * sizeModifier, Math.Min(hull1.WaterVolume, hull1.Volume));

                        //make sure not to place more water to the target room than it can hold
                        delta              = Math.Min(delta, hull2.Volume * Hull.MaxCompress - (hull2.WaterVolume));
                        hull1.WaterVolume -= delta;
                        hull2.WaterVolume += delta;
                        if (hull2.WaterVolume > hull2.Volume)
                        {
                            hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure - subOffset.Y) + hull2.Pressure) / 2);
                        }

                        flowForce = new Vector2(delta, 0.0f);
                    }

                    if (delta > 100.0f && subOffset == Vector2.Zero)
                    {
                        float avg = (hull1.Surface + hull2.Surface) / 2.0f;

                        if (hull1.WaterVolume < hull1.Volume / Hull.MaxCompress &&
                            hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1] < rect.Y)
                        {
                            hull1.WaveVel[hull1.WaveY.Length - 1] = (avg - (hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1])) * 0.1f;
                            hull1.WaveVel[hull1.WaveY.Length - 2] = hull1.WaveVel[hull1.WaveY.Length - 1];
                        }

                        if (hull2.WaterVolume < hull2.Volume / Hull.MaxCompress &&
                            hull2.Surface + hull2.WaveY[0] < rect.Y)
                        {
                            hull2.WaveVel[0] = (avg - (hull2.Surface + hull2.WaveY[0])) * 0.1f;
                            hull2.WaveVel[1] = hull2.WaveVel[0];
                        }
                    }
                }
            }
            else
            {
                //lower room is full of water
                if (hull2.Pressure + subOffset.Y > hull1.Pressure && hull2.WaterVolume > 0.0f)
                {
                    float delta = Math.Min(hull2.WaterVolume - hull2.Volume + (hull2.Volume * Hull.MaxCompress), deltaTime * 8000.0f * sizeModifier);

                    //make sure not to place more water to the target room than it can hold
                    if (hull1.WaterVolume + delta > hull1.Volume * Hull.MaxCompress)
                    {
                        delta -= (hull1.WaterVolume + delta) - (hull1.Volume * Hull.MaxCompress);
                    }

                    delta              = Math.Max(delta, 0.0f);
                    hull1.WaterVolume += delta;
                    hull2.WaterVolume -= delta;

                    flowForce = new Vector2(
                        0.0f,
                        Math.Min(Math.Min((hull2.Pressure + subOffset.Y) - hull1.Pressure, 200.0f), delta));

                    flowTargetHull = hull1;

                    if (hull1.WaterVolume > hull1.Volume)
                    {
                        hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + (hull2.Pressure + subOffset.Y)) / 2);
                    }
                }
                //there's water in the upper room, drop to lower
                else if (hull1.WaterVolume > 0)
                {
                    flowTargetHull = hull2;

                    //make sure the amount of water moved isn't more than what the room contains
                    float delta = Math.Min(hull1.WaterVolume, deltaTime * 25000f * sizeModifier);

                    //make sure not to place more water to the target room than it can hold
                    if (hull2.WaterVolume + delta > hull2.Volume * Hull.MaxCompress)
                    {
                        delta -= (hull2.WaterVolume + delta) - (hull2.Volume * Hull.MaxCompress);
                    }
                    hull1.WaterVolume -= delta;
                    hull2.WaterVolume += delta;

                    flowForce = new Vector2(
                        hull1.WaveY[hull1.GetWaveIndex(rect.X)] - hull1.WaveY[hull1.GetWaveIndex(rect.Right)],
                        MathHelper.Clamp(-delta, -200.0f, 0.0f));

                    if (hull2.WaterVolume > hull2.Volume)
                    {
                        hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure - subOffset.Y) + hull2.Pressure) / 2);
                    }
                }
            }

            if (open > 0.0f)
            {
                if (hull1.WaterVolume > hull1.Volume / Hull.MaxCompress && hull2.WaterVolume > hull2.Volume / Hull.MaxCompress)
                {
                    float avgLethality = (hull1.LethalPressure + hull2.LethalPressure) / 2.0f;
                    hull1.LethalPressure = avgLethality;
                    hull2.LethalPressure = avgLethality;
                }
                else
                {
                    hull1.LethalPressure = 0.0f;
                    hull2.LethalPressure = 0.0f;
                }
            }
        }
Пример #5
0
 public DummyFireSource(Vector2 maxSize, Vector2 worldPosition, Hull spawningHull = null, bool isNetworkMessage = false) : base(worldPosition, spawningHull, isNetworkMessage)
 {
     this.maxSize = maxSize;
 }
Пример #6
0
        protected override Vector2 DoSteeringSeek(Vector2 target, float weight)
        {
            bool needsNewPath = currentPath != null && currentPath.Unreachable || Vector2.DistanceSquared(target, currentTarget) > 1;

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (currentPath == null || needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;

                if (findPathTimer > 0.0f)
                {
                    return(Vector2.Zero);
                }

                currentTarget = target;
                Vector2 pos = host.SimPosition;
                // TODO: remove this and handle differently?
                if (character != null && character.Submarine == null)
                {
                    var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false);
                    if (targetHull != null && targetHull.Submarine != null)
                    {
                        pos -= targetHull.Submarine.SimPosition;
                    }
                }

                var  newPath    = pathFinder.FindPath(pos, target, character.Submarine, "(Character: " + character.Name + ")");
                bool useNewPath = currentPath == null || needsNewPath;
                if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                {
                    // It's possible that the current path was calculated from a start point that is no longer valid.
                    // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                    useNewPath = newPath.Cost <currentPath.Cost ||
                                               Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition)> Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 2, 2);
                }
                if (useNewPath)
                {
                    currentPath = newPath;
                }

                findPathTimer = Rand.Range(1.0f, 1.2f);

                IsPathDirty = false;
                return(DiffToCurrentNode());
            }

            Vector2 diff = DiffToCurrentNode();

            var collider = character.AnimController.Collider;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (!character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }

            if (diff.LengthSquared() < 0.001f)
            {
                return(-host.Steering);
            }

            return(Vector2.Normalize(diff) * weight);
        }
Пример #7
0
        public void Explode(Vector2 worldPosition)
        {
            Hull hull = Hull.FindHull(worldPosition);

            if (shockwave)
            {
                GameMain.ParticleManager.CreateParticle("shockwave", worldPosition,
                                                        Vector2.Zero, 0.0f, hull);
            }

            for (int i = 0; i < attack.Range * 0.1f; i++)
            {
                Vector2 bubblePos = Rand.Vector(attack.Range * 0.5f);
                GameMain.ParticleManager.CreateParticle("bubbles", worldPosition + bubblePos,
                                                        bubblePos, 0.0f, hull);

                if (sparks)
                {
                    GameMain.ParticleManager.CreateParticle("spark", worldPosition,
                                                            Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f, hull);
                }
                if (flames)
                {
                    GameMain.ParticleManager.CreateParticle("explosionfire", ClampParticlePos(worldPosition + Rand.Vector(50f), hull),
                                                            Rand.Vector(Rand.Range(50.0f, 100.0f)), 0.0f, hull);
                }
                if (smoke)
                {
                    GameMain.ParticleManager.CreateParticle("smoke", ClampParticlePos(worldPosition + Rand.Vector(50f), hull),
                                                            Rand.Vector(Rand.Range(1.0f, 10.0f)), 0.0f, hull);
                }
            }

            float displayRange = attack.Range;

            if (displayRange < 0.1f)
            {
                return;
            }

            var light = new LightSource(worldPosition, displayRange, Color.LightYellow, null);

            CoroutineManager.StartCoroutine(DimLight(light));

            float cameraDist = Vector2.Distance(GameMain.GameScreen.Cam.Position, worldPosition) / 2.0f;

            GameMain.GameScreen.Cam.Shake = CameraShake * Math.Max((displayRange - cameraDist) / displayRange, 0.0f);

            if (attack.GetStructureDamage(1.0f) > 0.0f)
            {
                RangedStructureDamage(worldPosition, displayRange, attack.GetStructureDamage(1.0f));
            }

            if (force == 0.0f && attack.Stun == 0.0f && attack.GetDamage(1.0f) == 0.0f)
            {
                return;
            }

            ApplyExplosionForces(worldPosition, attack.Range, force, attack.GetDamage(1.0f), attack.Stun);

            if (flames && GameMain.Client == null)
            {
                foreach (Item item in Item.ItemList)
                {
                    if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f)
                    {
                        continue;
                    }

                    if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f)
                    {
                        continue;
                    }

                    item.ApplyStatusEffects(ActionType.OnFire, 1.0f);

                    if (item.Condition <= 0.0f && GameMain.Server != null)
                    {
                        GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
                    }
                }
            }
        }
Пример #8
0
        public static SoundChannel PlaySound(string soundTag, float volume, float range, Vector2 position, Hull hullGuess = null)
        {
            var sound = GetSound(soundTag);

            if (sound == null)
            {
                return(null);
            }
            return(PlaySound(sound, sound.BaseGain * volume, range, position, hullGuess));
        }
Пример #9
0
 public static SoundChannel PlaySound(Sound sound, float volume, float range, Vector2 position, Hull hullGuess = null)
 {
     if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > range * range)
     {
         return(null);
     }
     return(sound.Play(sound.BaseGain * volume, range, position, muffle: ShouldMuffleSound(Character.Controlled, position, range, hullGuess)));
 }
Пример #10
0
        /// <summary>
        /// Play a sound defined in a sound xml file. If the volume or range parameters are omitted, the volume and range defined in the sound xml are used.
        /// </summary>
        public static SoundChannel PlaySound(string soundTag, Vector2 position, float?volume = null, float?range = null, Hull hullGuess = null)
        {
            var sound = GetSound(soundTag);

            if (sound == null)
            {
                return(null);
            }
            return(PlaySound(sound, position, volume ?? sound.BaseGain, range ?? sound.BaseFar, hullGuess));
        }
Пример #11
0
        public static SoundChannel PlaySound(Sound sound, Vector2 position, float?volume = null, float?range = null, Hull hullGuess = null)
        {
            if (sound == null)
            {
                string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace;
                GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
                return(null);
            }

            float far = range ?? sound.BaseFar;

            if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > far * far)
            {
                return(null);
            }
            bool muffle = !sound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, far, hullGuess);

            return(sound.Play(volume ?? sound.BaseGain, far, position, muffle: muffle));
        }
 public static bool NeedsDivingGear(Hull hull) => hull == null || hull.OxygenPercentage < 50 || hull.WaterPercentage > 50;
Пример #13
0
        static DebugConsole()
        {
            commands.Add(new Command("help", "", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    foreach (Command c in commands)
                    {
                        if (string.IsNullOrEmpty(c.help))
                        {
                            continue;
                        }
                        NewMessage(c.help, Color.Cyan);
                    }
                }
                else
                {
                    var matchingCommand = commands.Find(c => c.names.Any(name => name == args[0]));
                    if (matchingCommand == null)
                    {
                        NewMessage("Command " + args[0] + " not found.", Color.Red);
                    }
                    else
                    {
                        NewMessage(matchingCommand.help, Color.Cyan);
                    }
                }
            }));

            commands.Add(new Command("clientlist", "clientlist: List all the clients connected to the server.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                NewMessage("***************", Color.Cyan);
                foreach (Client c in GameMain.Server.ConnectedClients)
                {
                    NewMessage("- " + c.ID.ToString() + ": " + c.name + ", " + c.Connection.RemoteEndPoint.Address.ToString(), Color.Cyan);
                }
                NewMessage("***************", Color.Cyan);
            }));


            commands.Add(new Command("createfilelist", "", (string[] args) =>
            {
                UpdaterUtil.SaveFileList("filelist.xml");
            }));

            commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename] [near/inside/outside]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine).", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    return;
                }

                Character spawnedCharacter = null;

                Vector2 spawnPosition = Vector2.Zero;
                WayPoint spawnPoint   = null;

                if (args.Length > 1)
                {
                    switch (args[1].ToLowerInvariant())
                    {
                    case "inside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                        break;

                    case "outside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Enemy);
                        break;

                    case "near":
                    case "close":
                        float closestDist = -1.0f;
                        foreach (WayPoint wp in WayPoint.WayPointList)
                        {
                            if (wp.Submarine != null)
                            {
                                continue;
                            }

                            //don't spawn inside hulls
                            if (Hull.FindHull(wp.WorldPosition, null) != null)
                            {
                                continue;
                            }

                            float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter);

                            if (closestDist < 0.0f || dist < closestDist)
                            {
                                spawnPoint  = wp;
                                closestDist = dist;
                            }
                        }
                        break;

                    case "cursor":
                        spawnPosition = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                        break;

                    default:
                        spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                        break;
                    }
                }
                else
                {
                    spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                }

                if (string.IsNullOrWhiteSpace(args[0]))
                {
                    return;
                }

                if (spawnPoint != null)
                {
                    spawnPosition = spawnPoint.WorldPosition;
                }

                if (args[0].ToLowerInvariant() == "human")
                {
                    spawnedCharacter = Character.Create(Character.HumanConfigFile, spawnPosition);

#if CLIENT
                    if (GameMain.GameSession != null)
                    {
                        SinglePlayerMode mode = GameMain.GameSession.gameMode as SinglePlayerMode;
                        if (mode != null)
                        {
                            Character.Controlled = spawnedCharacter;
                            GameMain.GameSession.CrewManager.AddCharacter(Character.Controlled);
                            GameMain.GameSession.CrewManager.SelectCharacter(null, Character.Controlled);
                        }
                    }
#endif
                }
                else
                {
                    spawnedCharacter = Character.Create(
                        "Content/Characters/"
                        + args[0].First().ToString().ToUpper() + args[0].Substring(1)
                        + "/" + args[0].ToLower() + ".xml", spawnPosition);
                }
            }));

            commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.", (string[] args) =>
            {
                if (args.Length < 1)
                {
                    return;
                }

                Vector2?spawnPos         = null;
                Inventory spawnInventory = null;

                int extraParams = 0;
                switch (args.Last())
                {
                case "cursor":
                    extraParams = 1;
                    spawnPos    = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                    break;

                case "inventory":
                    extraParams    = 1;
                    spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory;
                    break;

                default:
                    extraParams = 0;
                    break;
                }

                string itemName = string.Join(" ", args.Take(args.Length - extraParams)).ToLowerInvariant();

                var itemPrefab = MapEntityPrefab.list.Find(ip => ip.Name.ToLowerInvariant() == itemName) as ItemPrefab;
                if (itemPrefab == null)
                {
                    ThrowError("Item \"" + itemName + "\" not found!");
                    return;
                }

                if (spawnPos == null && spawnInventory == null)
                {
                    var wp   = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                    spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition;
                }

                if (spawnPos != null)
                {
                    Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos);
                }
                else if (spawnInventory != null)
                {
                    Entity.Spawner.AddToSpawnQueue(itemPrefab, spawnInventory);
                }
            }));

            commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) =>
            {
                HumanAIController.DisableCrewAI = true;
                NewMessage("Crew AI disabled", Color.White);
            }));

            commands.Add(new Command("enablecrewai", "enablecrewai: Enable the AI of the NPCs in the crew.", (string[] args) =>
            {
                HumanAIController.DisableCrewAI = false;
                NewMessage("Crew AI enabled", Color.White);
            }));

            commands.Add(new Command("kick", "kick [name]: Kick a player out of the server.", (string[] args) =>
            {
                if (GameMain.NetworkMember == null || args.Length == 0)
                {
                    return;
                }

                string playerName = string.Join(" ", args);

                ShowQuestionPrompt("Reason for kicking \"" + playerName + "\"?", (reason) =>
                {
                    GameMain.NetworkMember.KickPlayer(playerName, reason);
                });
            }));

            commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                int id = 0;
                int.TryParse(args[0], out id);
                var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
                if (client == null)
                {
                    ThrowError("Client id \"" + id + "\" not found.");
                    return;
                }

                ShowQuestionPrompt("Reason for kicking \"" + client.name + "\"?", (reason) =>
                {
                    GameMain.Server.KickPlayer(client.name, reason);
                });
            }));

            commands.Add(new Command("ban", "ban [name]: Kick and ban the player from the server.", (string[] args) =>
            {
                if (GameMain.NetworkMember == null || args.Length == 0)
                {
                    return;
                }

                string clientName = string.Join(" ", args);
                ShowQuestionPrompt("Reason for banning \"" + clientName + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        GameMain.NetworkMember.BanPlayer(clientName, reason, false, banDuration);
                    });
                });
            }));

            commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                int id = 0;
                int.TryParse(args[0], out id);
                var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
                if (client == null)
                {
                    ThrowError("Client id \"" + id + "\" not found.");
                    return;
                }

                ShowQuestionPrompt("Reason for banning \"" + client.name + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        GameMain.Server.BanPlayer(client.name, reason, false, banDuration);
                    });
                });
            }));


            commands.Add(new Command("banip", "banip [ip]: Ban the IP address from the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                ShowQuestionPrompt("Reason for banning the ip \"" + commands[1] + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        var client = GameMain.Server.ConnectedClients.Find(c => c.Connection.RemoteEndPoint.Address.ToString() == args[0]);
                        if (client == null)
                        {
                            GameMain.Server.BanList.BanPlayer("Unnamed", args[0], reason, banDuration);
                        }
                        else
                        {
                            GameMain.Server.KickClient(client, reason);
                        }
                    });
                });
            }));

            commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) =>
            {
                Character tpCharacter = null;

                if (args.Length == 0)
                {
                    tpCharacter = Character.Controlled;
                }
                else
                {
                    tpCharacter = FindMatchingCharacter(args, false);
                }

                if (tpCharacter == null)
                {
                    return;
                }

                var cam = GameMain.GameScreen.Cam;
                tpCharacter.AnimController.CurrentHull = null;
                tpCharacter.Submarine = null;
                tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)));
                tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true);
            }));

            commands.Add(new Command("godmode", "godmode: Toggle submarine godmode. Makes the main submarine invulnerable to damage.", (string[] args) =>
            {
                if (Submarine.MainSub == null)
                {
                    return;
                }

                Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode;
                NewMessage(Submarine.MainSub.GodMode ? "Godmode on" : "Godmode off", Color.White);
            }));

            commands.Add(new Command("lockx", "lockx: Lock horizontal movement of the main submarine.", (string[] args) =>
            {
                Submarine.LockX = !Submarine.LockX;
            }));

            commands.Add(new Command("locky", "loxky: Lock vertical movement of the main submarine.", (string[] args) =>
            {
                Submarine.LockY = !Submarine.LockY;
            }));

            commands.Add(new Command("dumpids", "", (string[] args) =>
            {
                try
                {
                    int count = args.Length == 0 ? 10 : int.Parse(args[0]);
                    Entity.DumpIds(count);
                }
                catch (Exception e)
                {
                    ThrowError("Failed to dump ids", e);
                }
            }));

            commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) =>
            {
                Character healedCharacter = null;
                if (args.Length == 0)
                {
                    healedCharacter = Character.Controlled;
                }
                else
                {
                    healedCharacter = FindMatchingCharacter(args);
                }

                if (healedCharacter != null)
                {
                    healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
                    healedCharacter.Oxygen   = 100.0f;
                    healedCharacter.Bleeding = 0.0f;
                    healedCharacter.SetStun(0.0f, true);
                }
            }));

            commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) =>
            {
                Character revivedCharacter = null;
                if (args.Length == 0)
                {
                    revivedCharacter = Character.Controlled;
                }
                else
                {
                    revivedCharacter = FindMatchingCharacter(args);
                }

                if (revivedCharacter == null)
                {
                    return;
                }

                revivedCharacter.Revive(false);
                if (GameMain.Server != null)
                {
                    foreach (Client c in GameMain.Server.ConnectedClients)
                    {
                        if (c.Character != revivedCharacter)
                        {
                            continue;
                        }
                        //clients stop controlling the character when it dies, force control back
                        GameMain.Server.SetClientCharacter(c, revivedCharacter);
                        break;
                    }
                }
            }));

            commands.Add(new Command("freeze", "", (string[] args) =>
            {
                if (Character.Controlled != null)
                {
                    Character.Controlled.AnimController.Frozen = !Character.Controlled.AnimController.Frozen;
                }
            }));

            commands.Add(new Command("freecamera|freecam", "freecam: Detach the camera from the controlled character.", (string[] args) =>
            {
                Character.Controlled = null;
                GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
            }));

            commands.Add(new Command("water|editwater", "water/editwater: Toggle water editing. Allows adding water into rooms by holding the left mouse button and removing it by holding the right mouse button.", (string[] args) =>
            {
                if (GameMain.Client == null)
                {
                    Hull.EditWater = !Hull.EditWater;
                    NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White);
                }
            }));

            commands.Add(new Command("fire|editfire", "fire/editfire: Allows putting up fires by left clicking.", (string[] args) =>
            {
                if (GameMain.Client == null)
                {
                    Hull.EditFire = !Hull.EditFire;
                    NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White);
                }
            }));

            commands.Add(new Command("explosion", "explosion [range] [force] [damage] [structuredamage]: Creates an explosion at the position of the cursor.", (string[] args) =>
            {
                Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                float range          = 500, force = 10, damage = 50, structureDamage = 10;
                if (args.Length > 0)
                {
                    float.TryParse(args[0], out range);
                }
                if (args.Length > 1)
                {
                    float.TryParse(args[1], out force);
                }
                if (args.Length > 2)
                {
                    float.TryParse(args[2], out damage);
                }
                if (args.Length > 3)
                {
                    float.TryParse(args[3], out structureDamage);
                }
                new Explosion(range, force, damage, structureDamage).Explode(explosionPos);
            }));

            commands.Add(new Command("fixitems", "fixitems: Repairs all items and restores them to full condition.", (string[] args) =>
            {
                foreach (Item it in Item.ItemList)
                {
                    it.Condition = it.Prefab.Health;
                }
            }));

            commands.Add(new Command("fixhulls|fixwalls", "fixwalls/fixhulls: Fixes all walls.", (string[] args) =>
            {
                foreach (Structure w in Structure.WallList)
                {
                    for (int i = 0; i < w.SectionCount; i++)
                    {
                        w.AddDamage(i, -100000.0f);
                    }
                }
            }));

            commands.Add(new Command("power", "power [temperature]: Immediately sets the temperature of the nuclear reactor to the specified value.", (string[] args) =>
            {
                Item reactorItem = Item.ItemList.Find(i => i.GetComponent <Reactor>() != null);
                if (reactorItem == null)
                {
                    return;
                }

                float power = 5000.0f;
                if (args.Length > 0)
                {
                    float.TryParse(args[0], out power);
                }

                var reactor          = reactorItem.GetComponent <Reactor>();
                reactor.ShutDownTemp = power == 0 ? 0 : 7000.0f;
                reactor.AutoTemp     = true;
                reactor.Temperature  = power;

                if (GameMain.Server != null)
                {
                    reactorItem.CreateServerEvent(reactor);
                }
            }));

            commands.Add(new Command("oxygen|air", "oxygen/air: Replenishes the oxygen levels in every room to 100%.", (string[] args) =>
            {
                foreach (Hull hull in Hull.hullList)
                {
                    hull.OxygenPercentage = 100.0f;
                }
            }));

            commands.Add(new Command("killmonsters", "killmonsters: Immediately kills all AI-controlled enemies in the level.", (string[] args) =>
            {
                foreach (Character c in Character.CharacterList)
                {
                    if (!(c.AIController is EnemyAIController))
                    {
                        continue;
                    }
                    c.AddDamage(CauseOfDeath.Damage, 10000.0f, null);
                }
            }));

            commands.Add(new Command("netstats", "netstats: Toggles the visibility of the network statistics UI.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats;
            }));

            commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] ; [character name]: Gives the client control of the specified character.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }

                int separatorIndex = Array.IndexOf(args, ";");

                if (separatorIndex == -1 || args.Length < 3)
                {
                    ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"");
                    return;
                }

                string[] argsLeft  = args.Take(separatorIndex).ToArray();
                string[] argsRight = args.Skip(separatorIndex).ToArray();

                string clientName = String.Join(" ", argsLeft);

                var client = GameMain.Server.ConnectedClients.Find(c => c.name == clientName);
                if (client == null)
                {
                    ThrowError("Client \"" + clientName + "\" not found.");
                }

                var character = FindMatchingCharacter(argsRight, false);
                GameMain.Server.SetClientCharacter(client, character);
            }));
#if DEBUG
            commands.Add(new Command("spamevents", "A debug command that immediately creates entity events for all items, characters and structures.", (string[] args) =>
            {
                foreach (Item item in Item.ItemList)
                {
                    for (int i = 0; i < item.components.Count; i++)
                    {
                        if (item.components[i] is IServerSerializable)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, i });
                        }
                        var itemContainer = item.GetComponent <ItemContainer>();
                        if (itemContainer != null)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.InventoryState });
                        }

                        GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status });

                        item.NeedsPositionUpdate = true;
                    }
                }

                foreach (Character c in Character.CharacterList)
                {
                    GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status });
                }

                foreach (Structure wall in Structure.WallList)
                {
                    GameMain.Server.CreateEntityEvent(wall);
                }
            }));
#endif
            InitProjectSpecific();

            commands.Sort((c1, c2) => c1.names[0].CompareTo(c2.names[0]));
        }
Пример #14
0
 //returns the water block which contains the point (or null if it isn't inside any)
 public static Hull FindHullOld(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = false)
 {
     return(FindHullOld(position, hullList, guess, useWorldCoordinates, inclusive));
 }
Пример #15
0
        public Hull FindBestHull(IEnumerable <Hull> ignoredHulls = null, bool allowChangingTheSubmarine = true)
        {
            Hull  bestHull  = null;
            float bestValue = 0;

            foreach (Hull hull in Hull.hullList)
            {
                if (hull.Submarine == null)
                {
                    continue;
                }
                if (!allowChangingTheSubmarine && hull.Submarine != character.Submarine)
                {
                    continue;
                }
                if (ignoredHulls != null && ignoredHulls.Contains(hull))
                {
                    continue;
                }
                if (unreachable.Contains(hull))
                {
                    continue;
                }
                float hullSafety = 0;
                if (character.CurrentHull != null && character.Submarine != null)
                {
                    // Inside
                    if (!character.Submarine.IsConnectedTo(hull.Submarine))
                    {
                        continue;
                    }
                    hullSafety = HumanAIController.GetHullSafety(hull, character);
                    // Vertical distance matters more than horizontal (climbing up/down is harder than moving horizontally)
                    float dist           = Math.Abs(character.WorldPosition.X - hull.WorldPosition.X) + Math.Abs(character.WorldPosition.Y - hull.WorldPosition.Y) * 2.0f;
                    float distanceFactor = MathHelper.Lerp(1, 0.9f, MathUtils.InverseLerp(0, 10000, dist));
                    hullSafety *= distanceFactor;
                    //skip the hull if the safety is already less than the best hull
                    //(no need to do the expensive pathfinding if we already know we're not going to choose this hull)
                    if (hullSafety < bestValue)
                    {
                        continue;
                    }
                    var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition);
                    if (path.Unreachable)
                    {
                        unreachable.Add(hull);
                        continue;
                    }
                    // Each unsafe node reduces the hull safety value.
                    // Ignore the current hull, because otherwise we couldn't find a path out.
                    int unsafeNodes = path.Nodes.Count(n => n.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(n.CurrentHull));
                    hullSafety /= 1 + unsafeNodes;
                    // If the target is not inside a friendly submarine, considerably reduce the hull safety.
                    if (!character.Submarine.IsEntityFoundOnThisSub(hull, true))
                    {
                        hullSafety /= 10;
                    }
                }
                else
                {
                    // Outside
                    if (hull.RoomName != null && hull.RoomName.ToLowerInvariant().Contains("airlock"))
                    {
                        hullSafety = 100;
                    }
                    else
                    {
                        // TODO: could also target gaps that get us inside?
                        foreach (Item item in Item.ItemList)
                        {
                            if (item.CurrentHull != hull && item.HasTag("airlock"))
                            {
                                hullSafety = 100;
                                break;
                            }
                        }
                    }
                    // TODO: could we get a closest door to the outside and target the flowing hull if no airlock is found?
                    // Huge preference for closer targets
                    float distance       = Vector2.DistanceSquared(character.WorldPosition, hull.WorldPosition);
                    float distanceFactor = MathHelper.Lerp(1, 0.2f, MathUtils.InverseLerp(0, MathUtils.Pow(100000, 2), distance));
                    hullSafety *= distanceFactor;
                    // If the target is not inside a friendly submarine, considerably reduce the hull safety.
                    if (hull.Submarine.TeamID != character.TeamID && hull.Submarine.TeamID != Character.TeamType.FriendlyNPC)
                    {
                        hullSafety /= 10;
                    }
                }
                if (hullSafety > bestValue)
                {
                    bestHull  = hull;
                    bestValue = hullSafety;
                }
            }
            return(bestHull);
        }
Пример #16
0
        public static bool ShouldMuffleSound(Character listener, Vector2 soundWorldPos, float range, Hull hullGuess)
        {
            if (listener == null)
            {
                return(false);
            }

            float          lowpassHFGain  = 1.0f;
            AnimController animController = listener.AnimController;

            if (animController.HeadInWater)
            {
                lowpassHFGain = 0.2f;
            }
            lowpassHFGain *= Character.Controlled.LowPassMultiplier;
            if (lowpassHFGain < 0.5f)
            {
                return(true);
            }

            Hull targetHull = Hull.FindHull(soundWorldPos, hullGuess, true);

            if (listener.CurrentHull == null || targetHull == null)
            {
                return(listener.CurrentHull != targetHull);
            }
            Vector2 soundPos = soundWorldPos;

            if (targetHull.Submarine != null)
            {
                soundPos += -targetHull.Submarine.WorldPosition + targetHull.Submarine.HiddenSubPosition;
            }
            return(listener.CurrentHull.GetApproximateDistance(listener.Position, soundPos, targetHull, range) > range);
        }
Пример #17
0
        protected override void Act(float deltaTime)
        {
            var  currentHull     = character.AnimController.CurrentHull;
            bool needsDivingGear = HumanAIController.NeedsDivingGear(currentHull);
            bool needsDivingSuit = needsDivingGear && (currentHull == null || currentHull.WaterPercentage > 90);
            bool needsEquipment  = false;

            if (needsDivingSuit)
            {
                needsEquipment = !HumanAIController.HasDivingSuit(character);
            }
            else if (needsDivingGear)
            {
                needsEquipment = !HumanAIController.HasDivingMask(character);
            }
            if (needsEquipment)
            {
                TryAddSubObjective(ref divingGearObjective,
                                   () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager),
                                   onAbandon: () => searchHullTimer = Math.Min(1, searchHullTimer));
            }
            else
            {
                if (divingGearObjective != null && divingGearObjective.IsCompleted())
                {
                    // Reset the devotion.
                    Priority            = 0;
                    divingGearObjective = null;
                }
                if (currenthullSafety < HumanAIController.HULL_SAFETY_THRESHOLD)
                {
                    searchHullTimer = Math.Min(1, searchHullTimer);
                }
                if (searchHullTimer > 0.0f)
                {
                    searchHullTimer -= deltaTime;
                }
                else
                {
                    searchHullTimer  = SearchHullInterval;
                    previousSafeHull = currentSafeHull;
                    currentSafeHull  = FindBestHull();
                    if (currentSafeHull == null)
                    {
                        currentSafeHull = previousSafeHull;
                    }
                    if (currentSafeHull != null && currentSafeHull != currentHull)
                    {
                        if (goToObjective?.Target != currentSafeHull)
                        {
                            goToObjective = null;
                        }
                        TryAddSubObjective(ref goToObjective,
                                           constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true)
                        {
                            AllowGoingOutside = HumanAIController.HasDivingSuit(character)
                        },
                                           onAbandon: () => unreachable.Add(goToObjective.Target as Hull));
                    }
                    else
                    {
                        goToObjective = null;
                    }
                }
                if (goToObjective != null)
                {
                    if (goToObjective.IsCompleted())
                    {
                        objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime);
                    }
                    Priority = 0;
                    return;
                }
                if (currentHull == null)
                {
                    return;
                }
                //goto objective doesn't exist (a safe hull not found, or a path to a safe hull not found)
                // -> attempt to manually steer away from hazards
                Vector2 escapeVel = Vector2.Zero;
                // TODO: optimize
                foreach (FireSource fireSource in HumanAIController.VisibleHulls.SelectMany(h => h.FireSources))
                {
                    Vector2 dir            = character.Position - fireSource.Position;
                    float   distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.Position, character.Position), 0.1f, 10.0f);
                    escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
                }
                foreach (Character enemy in Character.CharacterList)
                {
                    if (enemy.IsDead || enemy.IsUnconscious || enemy.Removed || HumanAIController.IsFriendly(enemy))
                    {
                        continue;
                    }
                    if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull))
                    {
                        Vector2 dir            = character.Position - enemy.Position;
                        float   distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f);
                        escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
                    }
                }
                if (escapeVel != Vector2.Zero)
                {
                    float left  = currentHull.Rect.X + 50;
                    float right = currentHull.Rect.Right - 50;
                    //only move if we haven't reached the edge of the room
                    if (escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right)
                    {
                        character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
                    }
                    else
                    {
                        character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left;
                        character.AIController.SteeringManager.Reset();
                    }
                }
                else
                {
                    Priority = 0;
                    objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime);
                }
            }
        }
Пример #18
0
        public void Load(bool unloadPrevious, XElement submarineElement = null)
        {
            if (unloadPrevious)
            {
                Unload();
            }

            Loading = true;

            if (submarineElement == null)
            {
                XDocument doc = OpenFile(filePath);
                if (doc == null || doc.Root == null)
                {
                    return;
                }

                submarineElement = doc.Root;
            }

            Description = submarineElement.GetAttributeString("description", "");
            Enum.TryParse(submarineElement.GetAttributeString("tags", ""), out tags);

            //place the sub above the top of the level
            HiddenSubPosition = HiddenSubStartPosition;
            if (GameMain.GameSession != null && GameMain.GameSession.Level != null)
            {
                HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.Level.Size.Y;
            }

            foreach (Submarine sub in Submarine.loaded)
            {
                HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f);
            }

            IdOffset = 0;
            foreach (MapEntity me in MapEntity.mapEntityList)
            {
                IdOffset = Math.Max(IdOffset, me.ID);
            }

            foreach (XElement element in submarineElement.Elements())
            {
                string typeName = element.Name.ToString();

                Type t;
                try
                {
                    t = Type.GetType("Barotrauma." + typeName, true, true);
                    if (t == null)
                    {
                        DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\".");
                        continue;
                    }
                }
                catch (Exception e)
                {
                    DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\".", e);
                    continue;
                }

                try
                {
                    MethodInfo loadMethod = t.GetMethod("Load");
                    loadMethod.Invoke(t, new object[] { element, this });
                }
                catch (Exception e)
                {
                    DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".", e);
                }
            }

            Vector2 center = Vector2.Zero;

            var matchingHulls = Hull.hullList.FindAll(h => h.Submarine == this);

            if (matchingHulls.Any())
            {
                Vector2 topLeft     = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
                Vector2 bottomRight = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
                foreach (Hull hull in matchingHulls)
                {
                    if (hull.Rect.X < topLeft.X)
                    {
                        topLeft.X = hull.Rect.X;
                    }
                    if (hull.Rect.Y > topLeft.Y)
                    {
                        topLeft.Y = hull.Rect.Y;
                    }

                    if (hull.Rect.Right > bottomRight.X)
                    {
                        bottomRight.X = hull.Rect.Right;
                    }
                    if (hull.Rect.Y - hull.Rect.Height < bottomRight.Y)
                    {
                        bottomRight.Y = hull.Rect.Y - hull.Rect.Height;
                    }
                }

                center    = (topLeft + bottomRight) / 2.0f;
                center.X -= center.X % GridSize.X;
                center.Y -= center.Y % GridSize.Y;

                if (center != Vector2.Zero)
                {
                    foreach (Item item in Item.ItemList)
                    {
                        if (item.Submarine != this)
                        {
                            continue;
                        }

                        var wire = item.GetComponent <Items.Components.Wire>();
                        if (wire != null)
                        {
                            wire.MoveNodes(-center);
                        }
                    }

                    for (int i = 0; i < MapEntity.mapEntityList.Count; i++)
                    {
                        if (MapEntity.mapEntityList[i].Submarine != this)
                        {
                            continue;
                        }

                        MapEntity.mapEntityList[i].Move(-center);
                    }
                }
            }

            subBody = new SubmarineBody(this);
            subBody.SetPosition(HiddenSubPosition);

            loaded.Add(this);

            if (entityGrid != null)
            {
                Hull.EntityGrids.Remove(entityGrid);
                entityGrid = null;
            }
            entityGrid = Hull.GenerateEntityGrid(this);

            for (int i = 0; i < MapEntity.mapEntityList.Count; i++)
            {
                if (MapEntity.mapEntityList[i].Submarine != this)
                {
                    continue;
                }
                MapEntity.mapEntityList[i].Move(HiddenSubPosition);
            }

            Loading = false;

            MapEntity.MapLoaded(this);

            //WayPoint.GenerateSubWaypoints();

#if CLIENT
            GameMain.LightManager.OnMapLoaded();
#endif

            ID = (ushort)(ushort.MaxValue - Submarine.loaded.IndexOf(this));
        }
Пример #19
0
        private void FindHulls()
        {
            Hull[] hulls = new Hull[2];

            foreach (var linked in linkedTo)
            {
                if (linked is Hull hull)
                {
                    hull.ConnectedGaps.Remove(this);
                }
            }
            linkedTo.Clear();

            Vector2[] searchPos = new Vector2[2];
            if (IsHorizontal)
            {
                searchPos[0] = new Vector2(rect.X, rect.Y - rect.Height / 2);
                searchPos[1] = new Vector2(rect.Right, rect.Y - rect.Height / 2);
            }
            else
            {
                searchPos[0] = new Vector2(rect.Center.X, rect.Y);
                searchPos[1] = new Vector2(rect.Center.X, rect.Y - rect.Height);
            }

            for (int i = 0; i < 2; i++)
            {
                hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false);
                if (hulls[i] == null)
                {
                    hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false, true);
                }
            }

            if (hulls[0] == null && hulls[1] == null)
            {
                return;
            }

            if (hulls[0] == null && hulls[1] != null)
            {
                Hull temp = hulls[0];
                hulls[0] = hulls[1];
                hulls[1] = temp;
            }

            flowTargetHull = hulls[0];

            for (int i = 0; i < 2; i++)
            {
                if (hulls[i] == null)
                {
                    continue;
                }
                linkedTo.Add(hulls[i]);
                if (!hulls[i].ConnectedGaps.Contains(this))
                {
                    hulls[i].ConnectedGaps.Add(this);
                }
            }
        }
Пример #20
0
        public void FlipX(List <Submarine> parents = null)
        {
            if (parents == null)
            {
                parents = new List <Submarine>();
            }
            parents.Add(this);

            flippedX = !flippedX;

            Item.UpdateHulls();

            List <Item> bodyItems = Item.ItemList.FindAll(it => it.Submarine == this && it.body != null);

            List <MapEntity> subEntities = MapEntity.mapEntityList.FindAll(me => me.Submarine == this);

            foreach (MapEntity e in subEntities)
            {
                if (e.MoveWithLevel || e is Item)
                {
                    continue;
                }

                if (e is LinkedSubmarine)
                {
                    Submarine sub = ((LinkedSubmarine)e).Sub;
                    if (!parents.Contains(sub))
                    {
                        Vector2 relative1 = sub.SubBody.Position - SubBody.Position;
                        relative1.X = -relative1.X;
                        sub.SetPosition(relative1 + SubBody.Position);
                        sub.FlipX(parents);
                    }
                }
                else
                {
                    e.FlipX();
                }
            }

            foreach (MapEntity mapEntity in subEntities)
            {
                mapEntity.Move(-HiddenSubPosition);
            }

            Vector2 pos = new Vector2(subBody.Position.X, subBody.Position.Y);

            subBody.Body.Remove();
            subBody = new SubmarineBody(this);
            SetPosition(pos);

            if (entityGrid != null)
            {
                Hull.EntityGrids.Remove(entityGrid);
                entityGrid = null;
            }
            entityGrid = Hull.GenerateEntityGrid(this);

            foreach (MapEntity mapEntity in subEntities)
            {
                mapEntity.Move(HiddenSubPosition);
            }

            foreach (Item item in Item.ItemList)
            {
                if (bodyItems.Contains(item))
                {
                    item.Submarine = this;
                    if (Position == Vector2.Zero)
                    {
                        item.Move(-HiddenSubPosition);
                    }
                }
                else if (item.Submarine != this)
                {
                    continue;
                }

                item.FlipX();
            }

            Item.UpdateHulls();
            Gap.UpdateHulls();
        }
Пример #21
0
        public override void Update(float deltaTime, Camera cam)
        {
            flowForce = Vector2.Zero;

            outsideColliderRaycastTimer -= deltaTime;

            if (open == 0.0f || linkedTo.Count == 0)
            {
                lerpedFlowForce = Vector2.Zero;
                return;
            }

            Hull hull1 = (Hull)linkedTo[0];
            Hull hull2 = linkedTo.Count < 2 ? null : (Hull)linkedTo[1];

            if (hull1 == hull2)
            {
                return;
            }

            UpdateOxygen(hull1, hull2);

            if (linkedTo.Count == 1)
            {
                //gap leading from a room to outside
                UpdateRoomToOut(deltaTime, hull1);
            }
            else if (linkedTo.Count == 2)
            {
                //gap leading from a room to another
                UpdateRoomToRoom(deltaTime, hull1, hull2);
            }

            flowForce.X     = MathHelper.Clamp(flowForce.X, -MaxFlowForce, MaxFlowForce);
            flowForce.Y     = MathHelper.Clamp(flowForce.Y, -MaxFlowForce, MaxFlowForce);
            lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, deltaTime * 5.0f);

            EmitParticles(deltaTime);

            if (flowTargetHull != null && lerpedFlowForce.LengthSquared() > 0.0001f)
            {
                foreach (Character character in Character.CharacterList)
                {
                    if (character.CurrentHull == null)
                    {
                        continue;
                    }
                    if (character.CurrentHull != linkedTo[0] as Hull &&
                        (linkedTo.Count < 2 || character.CurrentHull != linkedTo[1] as Hull))
                    {
                        continue;
                    }

                    foreach (Limb limb in character.AnimController.Limbs)
                    {
                        if (!limb.inWater)
                        {
                            continue;
                        }

                        float dist = Vector2.Distance(limb.WorldPosition, WorldPosition);
                        if (dist > lerpedFlowForce.Length())
                        {
                            continue;
                        }

                        Vector2 force = lerpedFlowForce / (float)Math.Max(Math.Sqrt(dist), 20.0f) * 0.025f;

                        //vertical gaps only apply forces if the character is roughly above/below the gap
                        if (!IsHorizontal)
                        {
                            float xDist = Math.Abs(limb.WorldPosition.X - WorldPosition.X);
                            if (xDist > rect.Width || rect.Width == 0)
                            {
                                break;
                            }

                            force *= 1.0f - xDist / rect.Width;
                        }

                        if (!MathUtils.IsValid(force))
                        {
                            string errorMsg = "Attempted to apply invalid flow force to the character \"" + character.Name +
                                              "\", gap pos: " + WorldPosition +
                                              ", limb pos: " + limb.WorldPosition +
                                              ", flowforce: " + flowForce + ", lerpedFlowForce:" + lerpedFlowForce +
                                              ", dist: " + dist;

                            DebugConsole.Log(errorMsg);
                            GameAnalyticsManager.AddErrorEventOnce("Gap.Update:InvalidFlowForce:" + character.Name,
                                                                   GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                                                                   errorMsg);
                            continue;
                        }
                        character.AnimController.Collider.ApplyForce(force * limb.body.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
                    }
                }
            }
        }
Пример #22
0
        public static void GenerateSubWaypoints(Submarine submarine)
        {
            if (!Hull.hullList.Any())
            {
                DebugConsole.ThrowError("Couldn't generate waypoints: no hulls found.");
                return;
            }

            List <WayPoint> existingWaypoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Path);

            foreach (WayPoint wayPoint in existingWaypoints)
            {
                wayPoint.Remove();
            }

            //find all open doors and temporarily activate their bodies to prevent visibility checks
            //from ignoring the doors and generating waypoint connections that go straight through the door
            List <Door> openDoors = new List <Door>();

            foreach (Item item in Item.ItemList)
            {
                var door = item.GetComponent <Door>();
                if (door != null && !door.Body.Enabled)
                {
                    openDoors.Add(door);
                    door.Body.Enabled = true;
                }
            }


            float minDist         = 150.0f;
            float heightFromFloor = 110.0f;

            foreach (Hull hull in Hull.hullList)
            {
                if (hull.Rect.Height < 150)
                {
                    continue;
                }

                WayPoint prevWaypoint = null;

                if (hull.Rect.Width < minDist * 3.0f)
                {
                    new WayPoint(
                        new Vector2(hull.Rect.X + hull.Rect.Width / 2.0f, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);
                    continue;
                }

                for (float x = hull.Rect.X + minDist; x <= hull.Rect.Right - minDist; x += minDist)
                {
                    var wayPoint = new WayPoint(new Vector2(x, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);

                    if (prevWaypoint != null)
                    {
                        wayPoint.ConnectTo(prevWaypoint);
                    }

                    prevWaypoint = wayPoint;
                }
            }

            float outSideWaypointInterval = 200.0f;
            int   outsideWaypointDist     = 100;

            Rectangle borders = Hull.GetBorders();

            borders.X -= outsideWaypointDist;
            borders.Y += outsideWaypointDist;

            borders.Width  += outsideWaypointDist * 2;
            borders.Height += outsideWaypointDist * 2;

            borders.Location -= MathUtils.ToPoint(submarine.HiddenSubPosition);

            if (borders.Width <= outSideWaypointInterval * 2)
            {
                borders.Inflate(outSideWaypointInterval * 2 - borders.Width, 0);
            }

            if (borders.Height <= outSideWaypointInterval * 2)
            {
                int inflateAmount = (int)(outSideWaypointInterval * 2) - borders.Height;
                borders.Y += inflateAmount / 2;

                borders.Height += inflateAmount;
            }

            WayPoint[,] cornerWaypoint = new WayPoint[2, 2];

            for (int i = 0; i < 2; i++)
            {
                for (float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
                {
                    var wayPoint = new WayPoint(
                        new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (x == borders.X + outSideWaypointInterval)
                    {
                        cornerWaypoint[i, 0] = wayPoint;
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
                    }
                }

                cornerWaypoint[i, 1] = WayPointList[WayPointList.Count - 1];
            }

            for (int i = 0; i < 2; i++)
            {
                WayPoint wayPoint = null;
                for (float y = borders.Y - borders.Height; y < borders.Y; y += outSideWaypointInterval)
                {
                    wayPoint = new WayPoint(
                        new Vector2(borders.X + borders.Width * i, y) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (y == borders.Y - borders.Height)
                    {
                        wayPoint.ConnectTo(cornerWaypoint[1, i]);
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPoint.WayPointList[WayPointList.Count - 2]);
                    }
                }

                wayPoint.ConnectTo(cornerWaypoint[0, i]);
            }

            List <Structure> stairList = new List <Structure>();

            foreach (MapEntity me in mapEntityList)
            {
                Structure stairs = me as Structure;
                if (stairs == null)
                {
                    continue;
                }

                if (stairs.StairDirection != Direction.None)
                {
                    stairList.Add(stairs);
                }
            }

            foreach (Structure stairs in stairList)
            {
                WayPoint[] stairPoints = new WayPoint[3];

                stairPoints[0] = new WayPoint(
                    new Vector2(stairs.Rect.X - 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? 80 : stairs.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);

                stairPoints[1] = new WayPoint(
                    new Vector2(stairs.Rect.Right + 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? stairs.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);

                for (int i = 0; i < 2; i++)
                {
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = stairPoints[i].FindClosest(dir, true, new Vector2(-30.0f, 30f));
                        if (closest == null)
                        {
                            continue;
                        }
                        stairPoints[i].ConnectTo(closest);
                    }
                }

                stairPoints[2] = new WayPoint((stairPoints[0].Position + stairPoints[1].Position) / 2, SpawnType.Path, submarine);
                stairPoints[0].ConnectTo(stairPoints[2]);
                stairPoints[2].ConnectTo(stairPoints[1]);
            }

            foreach (Item item in Item.ItemList)
            {
                var ladders = item.GetComponent <Ladder>();
                if (ladders == null)
                {
                    continue;
                }

                List <WayPoint> ladderPoints = new List <WayPoint>();
                ladderPoints.Add(new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height + heightFromFloor), SpawnType.Path, submarine));

                WayPoint    prevPoint     = ladderPoints[0];
                Vector2     prevPos       = prevPoint.SimPosition;
                List <Body> ignoredBodies = new List <Body>();

                for (float y = ladderPoints[0].Position.Y + 100.0f; y < item.Rect.Y - 1.0f; y += 100.0f)
                {
                    //first check if there's a door in the way
                    //(we need to create a waypoint linked to the door for NPCs to open it)
                    Body pickedBody = Submarine.PickBody(
                        ConvertUnits.ToSimUnits(new Vector2(ladderPoints[0].Position.X, y)),
                        prevPos, ignoredBodies, Physics.CollisionWall, false,
                        (Fixture f) => f.Body.UserData is Item && ((Item)f.Body.UserData).GetComponent <Door>() != null);

                    Door pickedDoor = null;
                    if (pickedBody != null)
                    {
                        pickedDoor = (pickedBody?.UserData as Item).GetComponent <Door>();
                    }
                    else
                    {
                        //no door, check for walls
                        pickedBody = Submarine.PickBody(
                            ConvertUnits.ToSimUnits(new Vector2(ladderPoints[0].Position.X, y)), prevPos, ignoredBodies, null, false);
                    }

                    if (pickedBody == null)
                    {
                        prevPos = Submarine.LastPickedPosition;
                        continue;
                    }
                    else
                    {
                        ignoredBodies.Add(pickedBody);
                    }


                    if (pickedDoor != null)
                    {
                        WayPoint newPoint = new WayPoint(pickedDoor.Item.Position, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectedGap = pickedDoor.LinkedGap;
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = new Vector2(prevPos.X, ConvertUnits.ToSimUnits(pickedDoor.Item.Position.Y - pickedDoor.Item.Rect.Height));
                    }
                    else
                    {
                        WayPoint newPoint = new WayPoint(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + Vector2.UnitY * heightFromFloor, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = ConvertUnits.ToSimUnits(newPoint.Position);
                    }
                }

                if (prevPoint.rect.Y < item.Rect.Y - 10.0f)
                {
                    WayPoint newPoint = new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - 1.0f), SpawnType.Path, submarine);
                    ladderPoints.Add(newPoint);
                    newPoint.ConnectTo(prevPoint);
                }

                //connect ladder waypoints to hull points at the right and left side
                foreach (WayPoint ladderPoint in ladderPoints)
                {
                    ladderPoint.Ladders = ladders;
                    //don't connect if the waypoint is at a gap (= at the boundary of hulls and/or at a hatch)
                    if (ladderPoint.ConnectedGap != null)
                    {
                        continue;
                    }

                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = ladderPoint.FindClosest(dir, true, new Vector2(-150.0f, 10f));
                        if (closest == null)
                        {
                            continue;
                        }
                        ladderPoint.ConnectTo(closest);
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (!gap.IsHorizontal)
                {
                    continue;
                }

                //too small to walk through
                if (gap.Rect.Height < 150.0f)
                {
                    continue;
                }

                var wayPoint = new WayPoint(
                    new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor), SpawnType.Path, submarine, gap);

                for (int dir = -1; dir <= 1; dir += 2)
                {
                    float tolerance = gap.IsRoomToRoom ? 50.0f : outSideWaypointInterval / 2.0f;

                    WayPoint closest = wayPoint.FindClosest(
                        dir, true, new Vector2(-tolerance, tolerance),
                        gap.ConnectedDoor?.Body.FarseerBody);

                    if (closest != null)
                    {
                        wayPoint.ConnectTo(closest);
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (gap.IsHorizontal || gap.IsRoomToRoom || !gap.linkedTo.Any(l => l is Hull))
                {
                    continue;
                }

                //too small to walk through
                if (gap.Rect.Width < 100.0f)
                {
                    continue;
                }

                var wayPoint = new WayPoint(
                    new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height / 2), SpawnType.Path, submarine, gap);

                float tolerance     = outSideWaypointInterval / 2.0f;
                Hull  connectedHull = (Hull)gap.linkedTo.First(l => l is Hull);
                int   dir           = Math.Sign(connectedHull.Position.Y - gap.Position.Y);

                WayPoint closest = wayPoint.FindClosest(
                    dir, false, new Vector2(-tolerance, tolerance),
                    gap.ConnectedDoor?.Body.FarseerBody);

                if (closest != null)
                {
                    wayPoint.ConnectTo(closest);
                }
            }

            var orphans = WayPointList.FindAll(w => w.spawnType == SpawnType.Path && !w.linkedTo.Any());

            foreach (WayPoint wp in orphans)
            {
                wp.Remove();
            }

            //re-disable the bodies of the doors that are supposed to be open
            foreach (Door door in openDoors)
            {
                door.Body.Enabled = false;
            }
        }
Пример #23
0
        void UpdateRoomToOut(float deltaTime, Hull hull1)
        {
            float size = IsHorizontal ? rect.Height : rect.Width;

            //a variable affecting the water flow through the gap
            //the larger the gap is, the faster the water flows
            float sizeModifier = size * open * open;

            float delta = 500.0f * sizeModifier * deltaTime;

            //make sure not to place more water to the target room than it can hold
            delta              = Math.Min(delta, hull1.Volume * Hull.MaxCompress - hull1.WaterVolume);
            hull1.WaterVolume += delta;

            if (hull1.WaterVolume > hull1.Volume)
            {
                hull1.Pressure += 0.5f;
            }

            flowTargetHull = hull1;

            if (IsHorizontal)
            {
                //water flowing from right to left
                if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
                {
                    flowForce = new Vector2(-delta, 0.0f);
                }
                else
                {
                    flowForce = new Vector2(delta, 0.0f);
                }

                higherSurface = hull1.Surface;
                lowerSurface  = rect.Y;

                if (hull1.WaterVolume < hull1.Volume / Hull.MaxCompress &&
                    hull1.Surface < rect.Y)
                {
                    if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
                    {
                        float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1])) * 0.1f;
                        vel *= Math.Min(Math.Abs(flowForce.X) / 200.0f, 1.0f);

                        hull1.WaveVel[hull1.WaveY.Length - 1] += vel;
                        hull1.WaveVel[hull1.WaveY.Length - 2] += vel;
                    }
                    else
                    {
                        float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[0])) * 0.1f;
                        vel *= Math.Min(Math.Abs(flowForce.X) / 200.0f, 1.0f);

                        hull1.WaveVel[0] += vel;
                        hull1.WaveVel[1] += vel;
                    }
                }
                else
                {
                    hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime;
                }
            }
            else
            {
                if (rect.Y > hull1.Rect.Y - hull1.Rect.Height / 2.0f)
                {
                    flowForce = new Vector2(0.0f, -delta);
                }
                else
                {
                    flowForce = new Vector2(0.0f, delta);
                }
                if (hull1.WaterVolume >= hull1.Volume / Hull.MaxCompress)
                {
                    hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime;
                }
            }
        }
Пример #24
0
        partial void UpdateNetPlayerPositionProjSpecific(float deltaTime, float lowestSubPos)
        {
            if (character != GameMain.Client.Character || !character.CanMove)
            {
                //remove states without a timestamp (there may still be ID-based states
                //in the list when the controlled character switches to timestamp-based interpolation)
                character.MemState.RemoveAll(m => m.Timestamp == 0.0f);

                //use simple interpolation for other players' characters and characters that can't move
                if (character.MemState.Count > 0)
                {
                    CharacterStateInfo serverPos = character.MemState.Last();
                    if (!character.isSynced)
                    {
                        SetPosition(serverPos.Position, false);
                        Collider.LinearVelocity = Vector2.Zero;
                        character.MemLocalState.Clear();
                        character.LastNetworkUpdateID = serverPos.ID;
                        character.isSynced            = true;
                        return;
                    }

                    if (character.MemState[0].SelectedCharacter == null || character.MemState[0].SelectedCharacter.Removed)
                    {
                        character.DeselectCharacter();
                    }
                    else if (character.MemState[0].SelectedCharacter != null)
                    {
                        character.SelectCharacter(character.MemState[0].SelectedCharacter);
                    }

                    if (character.MemState[0].SelectedItem == null || character.MemState[0].SelectedItem.Removed)
                    {
                        character.SelectedConstruction = null;
                    }
                    else
                    {
                        if (character.SelectedConstruction != character.MemState[0].SelectedItem)
                        {
                            foreach (var ic in character.MemState[0].SelectedItem.Components)
                            {
                                if (ic.CanBeSelected)
                                {
                                    ic.Select(character);
                                }
                            }
                        }
                        character.SelectedConstruction = character.MemState[0].SelectedItem;
                    }

                    if (character.MemState[0].Animation == AnimController.Animation.CPR)
                    {
                        character.AnimController.Anim = AnimController.Animation.CPR;
                    }
                    else if (character.AnimController.Anim == AnimController.Animation.CPR)
                    {
                        character.AnimController.Anim = AnimController.Animation.None;
                    }

                    Vector2 newVelocity        = Collider.LinearVelocity;
                    Vector2 newPosition        = Collider.SimPosition;
                    float   newRotation        = Collider.Rotation;
                    float   newAngularVelocity = Collider.AngularVelocity;
                    Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);

                    newVelocity = newVelocity.ClampLength(100.0f);
                    if (!MathUtils.IsValid(newVelocity))
                    {
                        newVelocity = Vector2.Zero;
                    }
                    overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero;

                    Collider.LinearVelocity  = newVelocity;
                    Collider.AngularVelocity = newAngularVelocity;

                    float distSqrd       = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
                    float errorTolerance = character.CanMove ? 0.01f : 0.2f;
                    if (distSqrd > errorTolerance)
                    {
                        if (distSqrd > 10.0f || !character.CanMove)
                        {
                            Collider.TargetRotation = newRotation;
                            SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
                        }
                        else
                        {
                            Collider.TargetRotation = newRotation;
                            Collider.TargetPosition = newPosition;
                            Collider.MoveToTargetPosition(true);
                        }
                    }

                    //immobilized characters can't correct their position using AnimController movement
                    // -> we need to correct it manually
                    if (!character.CanMove)
                    {
                        float mainLimbDistSqrd       = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition);
                        float mainLimbErrorTolerance = 0.1f;
                        //if the main limb is roughly at the correct position and the collider isn't moving (much at least),
                        //don't attempt to correct the position.
                        if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f)
                        {
                            MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
                            MainLimb.PullJointEnabled      = true;
                        }
                    }
                }
                character.MemLocalState.Clear();
            }
            else
            {
                //remove states with a timestamp (there may still timestamp-based states
                //in the list if the controlled character switches from timestamp-based interpolation to ID-based)
                character.MemState.RemoveAll(m => m.Timestamp > 0.0f);

                for (int i = 0; i < character.MemLocalState.Count; i++)
                {
                    if (character.Submarine == null)
                    {
                        //transform in-sub coordinates to outside coordinates
                        if (character.MemLocalState[i].Position.Y > lowestSubPos)
                        {
                            character.MemLocalState[i].TransformInToOutside();
                        }
                    }
                    else if (currentHull?.Submarine != null)
                    {
                        //transform outside coordinates to in-sub coordinates
                        if (character.MemLocalState[i].Position.Y < lowestSubPos)
                        {
                            character.MemLocalState[i].TransformOutToInside(currentHull.Submarine);
                        }
                    }
                }

                if (character.MemState.Count < 1)
                {
                    return;
                }

                overrideTargetMovement = Vector2.Zero;

                CharacterStateInfo serverPos = character.MemState.Last();

                if (!character.isSynced)
                {
                    SetPosition(serverPos.Position, false);
                    Collider.LinearVelocity = Vector2.Zero;
                    character.MemLocalState.Clear();
                    character.LastNetworkUpdateID = serverPos.ID;
                    character.isSynced            = true;
                    return;
                }

                int localPosIndex = character.MemLocalState.FindIndex(m => m.ID == serverPos.ID);
                if (localPosIndex > -1)
                {
                    CharacterStateInfo localPos = character.MemLocalState[localPosIndex];

                    //the entity we're interacting with doesn't match the server's
                    if (localPos.SelectedCharacter != serverPos.SelectedCharacter)
                    {
                        if (serverPos.SelectedCharacter == null || serverPos.SelectedCharacter.Removed)
                        {
                            character.DeselectCharacter();
                        }
                        else if (serverPos.SelectedCharacter != null)
                        {
                            character.SelectCharacter(serverPos.SelectedCharacter);
                        }
                    }
                    if (localPos.SelectedItem != serverPos.SelectedItem)
                    {
                        if (serverPos.SelectedItem == null || serverPos.SelectedItem.Removed)
                        {
                            character.SelectedConstruction = null;
                        }
                        else if (serverPos.SelectedItem != null)
                        {
                            if (character.SelectedConstruction != serverPos.SelectedItem)
                            {
                                serverPos.SelectedItem.TryInteract(character, true, true);
                            }
                            character.SelectedConstruction = serverPos.SelectedItem;
                        }
                    }

                    if (localPos.Animation != serverPos.Animation)
                    {
                        if (serverPos.Animation == AnimController.Animation.CPR)
                        {
                            character.AnimController.Anim = AnimController.Animation.CPR;
                        }
                        else if (character.AnimController.Anim == AnimController.Animation.CPR)
                        {
                            character.AnimController.Anim = AnimController.Animation.None;
                        }
                    }

                    Hull serverHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(serverPos.Position), character.CurrentHull, serverPos.Position.Y < lowestSubPos);
                    Hull clientHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(localPos.Position), serverHull, localPos.Position.Y < lowestSubPos);

                    if (serverHull != null && clientHull != null && serverHull.Submarine != clientHull.Submarine)
                    {
                        //hull subs don't match => teleport the camera to the other sub
                        character.Submarine   = serverHull.Submarine;
                        character.CurrentHull = CurrentHull = serverHull;
                        SetPosition(serverPos.Position);
                        character.MemLocalState.Clear();
                    }
                    else
                    {
                        Vector2 positionError = serverPos.Position - localPos.Position;
                        float   rotationError = serverPos.Rotation.HasValue && localPos.Rotation.HasValue ?
                                                serverPos.Rotation.Value - localPos.Rotation.Value :
                                                0.0f;

                        for (int i = localPosIndex; i < character.MemLocalState.Count; i++)
                        {
                            Hull pointHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(character.MemLocalState[i].Position), clientHull, character.MemLocalState[i].Position.Y < lowestSubPos);
                            if (pointHull != clientHull && ((pointHull == null) || (clientHull == null) || (pointHull.Submarine == clientHull.Submarine)))
                            {
                                break;
                            }
                            character.MemLocalState[i].Translate(positionError, rotationError);
                        }

                        float errorMagnitude = positionError.Length();
                        if (errorMagnitude > 0.5f)
                        {
                            character.MemLocalState.Clear();
                            SetPosition(serverPos.Position, lerp: true, ignorePlatforms: false);
                        }
                        else if (errorMagnitude > 0.01f)
                        {
                            Collider.TargetPosition = Collider.SimPosition + positionError;
                            Collider.TargetRotation = Collider.Rotation + rotationError;
                            Collider.MoveToTargetPosition(lerp: true);
                        }
                    }
                }

                if (character.MemLocalState.Count > 120)
                {
                    character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120);
                }
                character.MemState.Clear();
            }
        }
Пример #25
0
        public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch, double deltaTime)
        {
            foreach (Submarine sub in Submarine.Loaded)
            {
                sub.UpdateTransform();
            }

            GameMain.ParticleManager.UpdateTransforms();

            GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision;

            if (Character.Controlled != null)
            {
                GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled.CursorWorldPosition);
            }


            //------------------------------------------------------------------------
            graphics.SetRenderTarget(renderTarget);
            graphics.Clear(Color.Transparent);
            //Draw resizeable background structures (= background walls) and wall background sprites
            //(= the background texture that's revealed when a wall is destroyed) into the background render target
            //These will be visible through the LOS effect.
            //Could be drawn with one Submarine.DrawBack call, but we can avoid sorting by depth by doing it like this.
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (s.ResizeVertical || s.ResizeHorizontal) && !s.DrawDamageEffect);
            Submarine.DrawBack(spriteBatch, false, e => e is Structure s && !(s.ResizeVertical && s.ResizeHorizontal) && s.Prefab.BackgroundSprite != null);
            spriteBatch.End();

            graphics.SetRenderTarget(null);
            GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam, renderTarget);

            //------------------------------------------------------------------------
            graphics.SetRenderTarget(renderTargetBackground);
            if (Level.Loaded == null)
            {
                graphics.Clear(new Color(11, 18, 26, 255));
            }
            else
            {
                //graphics.Clear(new Color(255, 255, 255, 255));
                Level.Loaded.DrawBack(graphics, spriteBatch, cam);
            }

            //draw alpha blended particles that are in water and behind subs
#if LINUX || OSX
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
#else
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
#endif
            GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            //draw additive particles that are in water and behind subs
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.Additive);
            spriteBatch.End();
            //Draw resizeable background structures (= background walls) and wall background sprites
            //(= the background texture that's revealed when a wall is destroyed) into the background render target
            //These will be visible through the LOS effect.
            //Could be drawn with one Submarine.DrawBack call, but we can avoid sorting by depth by doing it like this.
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None);
            spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
            spriteBatch.End();

            //----------------------------------------------------------------------------

            //Start drawing to the normal render target (stuff that can't be seen through the LOS effect)
            graphics.SetRenderTarget(renderTarget);
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, null);
            spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
            spriteBatch.End();
            //Draw the rest of the structures, characters and front structures
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawBack(spriteBatch, false, s => !(s is Structure) || !(s.ResizeVertical && s.ResizeHorizontal));
            foreach (Character c in Character.CharacterList)
            {
                if (c.AnimController.Limbs.Any(l => l.DeformSprite != null))
                {
                    continue;
                }
                c.Draw(spriteBatch, Cam);
            }
            spriteBatch.End();

            //draw characters with deformable limbs last, because they can't be batched into SpriteBatch
            //pretty hacky way of preventing draw order issues between normal and deformable sprites
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
            foreach (Character c in Character.CharacterList)
            {
                if (c.AnimController.Limbs.All(l => l.DeformSprite == null))
                {
                    continue;
                }
                c.Draw(spriteBatch, Cam);
            }
            spriteBatch.End();

            //draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
            graphics.SetRenderTarget(renderTargetWater);

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
            spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);// waterColor);
            spriteBatch.End();

            //draw alpha blended particles that are inside a sub
#if LINUX || OSX
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#else
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#endif
            GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            graphics.SetRenderTarget(renderTarget);

            //draw alpha blended particles that are not in water
#if LINUX || OSX
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#else
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#endif
            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            //draw additive particles that are not in water
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
            spriteBatch.End();

            graphics.DepthStencilState = DepthStencilState.DepthRead;
            graphics.SetRenderTarget(renderTargetFinal);

            WaterRenderer.Instance.ResetBuffers();
            Hull.UpdateVertices(graphics, cam, WaterRenderer.Instance);
            WaterRenderer.Instance.RenderWater(spriteBatch, renderTargetWater, cam);
            WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform);
            graphics.DepthStencilState = DepthStencilState.None;

            spriteBatch.Begin(SpriteSortMode.Immediate,
                              BlendState.NonPremultiplied, SamplerState.LinearWrap,
                              null, null,
                              damageEffect,
                              cam.Transform);
            Submarine.DrawDamageable(spriteBatch, damageEffect, false);
            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawFront(spriteBatch, false, null);
            spriteBatch.End();

            //draw additive particles that are inside a sub
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive);
            foreach (var discharger in Items.Components.ElectricalDischarger.List)
            {
                discharger.DrawElectricity(spriteBatch);
            }
            spriteBatch.End();
            if (GameMain.LightManager.LightingEnabled)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, Lights.CustomBlendStates.Multiplicative, null, DepthStencilState.None, null, null, null);
                spriteBatch.Draw(GameMain.LightManager.LightMap, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
                spriteBatch.End();
            }

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform);
            foreach (Character c in Character.CharacterList)
            {
                c.DrawFront(spriteBatch, cam);
            }

            if (Level.Loaded != null)
            {
                Level.Loaded.DrawFront(spriteBatch, cam);
            }
            if (GameMain.DebugDraw && GameMain.GameSession?.EventManager != null)
            {
                GameMain.GameSession.EventManager.DebugDraw(spriteBatch);
            }

            spriteBatch.End();

            if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Character.Controlled != null)
            {
                GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];

                GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground);
                GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture);

                Color losColor;
                if (GameMain.LightManager.LosMode == LosMode.Transparent)
                {
                    //convert the los color to HLS and make sure the luminance of the color is always the same
                    //as the luminance of the ambient light color
                    float r = Character.Controlled?.CharacterHealth == null ?
                              0.0f : Math.Min(Character.Controlled.CharacterHealth.DamageOverlayTimer * 0.5f, 0.5f);
                    Vector3 ambientLightHls = GameMain.LightManager.AmbientLight.RgbToHLS();
                    Vector3 losColorHls     = Color.Lerp(GameMain.LightManager.AmbientLight, Color.Red, r).RgbToHLS();
                    losColorHls.Y = ambientLightHls.Y;
                    losColor      = ToolBox.HLSToRGB(losColorHls);
                }
                else
                {
                    losColor = Color.Black;
                }

                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, GameMain.LightManager.LosEffect, null);
                spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, spriteBatch.GraphicsDevice.Viewport.Width, spriteBatch.GraphicsDevice.Viewport.Height), losColor);
                spriteBatch.End();
            }
            graphics.SetRenderTarget(null);

            float   BlurStrength                = 0.0f;
            float   DistortStrength             = 0.0f;
            Vector3 chromaticAberrationStrength = GameMain.Config.ChromaticAberrationEnabled ?
                                                  new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero;

            if (Character.Controlled != null)
            {
                BlurStrength                 = Character.Controlled.BlurStrength * 0.005f;
                DistortStrength              = Character.Controlled.DistortStrength;
                chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
                chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
            }
            else
            {
                BlurStrength    = 0.0f;
                DistortStrength = 0.0f;
            }

            string postProcessTechnique = "";
            if (BlurStrength > 0.0f)
            {
                postProcessTechnique += "Blur";
                postProcessEffect.Parameters["blurDistance"].SetValue(BlurStrength);
            }
            if (chromaticAberrationStrength != Vector3.Zero)
            {
                postProcessTechnique += "ChromaticAberration";
                postProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(chromaticAberrationStrength);
            }
            if (DistortStrength > 0.0f)
            {
                postProcessTechnique += "Distort";
                postProcessEffect.Parameters["distortScale"].SetValue(Vector2.One * DistortStrength);
                postProcessEffect.Parameters["distortUvOffset"].SetValue(WaterRenderer.Instance.WavePos * 0.001f);
#if LINUX || OSX
                postProcessEffect.Parameters["xTexture"].SetValue(distortTexture);
#else
                postProcessEffect.Parameters["xTexture"].SetValue(renderTargetFinal);
#endif
            }

            if (string.IsNullOrEmpty(postProcessTechnique))
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None);
            }
            else
            {
                postProcessEffect.CurrentTechnique = postProcessEffect.Techniques[postProcessTechnique];
                postProcessEffect.CurrentTechnique.Passes[0].Apply();
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, effect: postProcessEffect);
            }
#if LINUX || OSX
            spriteBatch.Draw(renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
#else
            spriteBatch.Draw(DistortStrength > 0.0f ? distortTexture : renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
#endif
            spriteBatch.End();
        }
Пример #26
0
        public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
        {
            if (back && Screen.Selected != GameMain.SubEditorScreen)
            {
                DrawDecals(spriteBatch);
                return;
            }

            /*if (!Visible)
             * {
             *  drawRect =
             *      Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
             *
             *  GUI.DrawRectangle(spriteBatch,
             *      new Vector2(drawRect.X, -drawRect.Y),
             *      new Vector2(rect.Width, rect.Height),
             *      Color.Black, true,
             *      0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
             * }*/

            if (!ShowHulls && !GameMain.DebugDraw)
            {
                return;
            }

            if (!editing && !GameMain.DebugDraw)
            {
                return;
            }

            if (aiTarget != null)
            {
                aiTarget.Draw(spriteBatch);
            }

            Rectangle drawRect =
                Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);

            GUI.DrawRectangle(spriteBatch,
                              new Vector2(drawRect.X, -drawRect.Y),
                              new Vector2(rect.Width, rect.Height),
                              Color.Blue, false, (ID % 255) * 0.000001f, (int)Math.Max((1.5f / Screen.Selected.Cam.Zoom), 1.0f));

            GUI.DrawRectangle(spriteBatch,
                              new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height),
                              Color.Red * ((100.0f - OxygenPercentage) / 400.0f), true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));

            if (GameMain.DebugDraw)
            {
                GUI.SmallFont.DrawString(spriteBatch, "Pressure: " + ((int)pressure - rect.Y).ToString() +
                                         " - Oxygen: " + ((int)OxygenPercentage), new Vector2(drawRect.X + 5, -drawRect.Y + 5), Color.White);
                GUI.SmallFont.DrawString(spriteBatch, waterVolume + " / " + Volume, new Vector2(drawRect.X + 5, -drawRect.Y + 20), Color.White);

                GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * Math.Min(waterVolume / Volume, 1.0f))), Color.Cyan, true);
                if (WaterVolume > Volume)
                {
                    GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / MaxCompress)), Color.Red, true);
                }
                GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, 100), Color.Black);

                foreach (FireSource fs in FireSources)
                {
                    Rectangle fireSourceRect = new Rectangle((int)fs.WorldPosition.X, -(int)fs.WorldPosition.Y, (int)fs.Size.X, (int)fs.Size.Y);
                    GUI.DrawRectangle(spriteBatch, fireSourceRect, Color.Orange, false, 0, 5);
                    //GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
                }

                /*GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
                 * for (int i = 0; i < waveY.Length - 1; i++)
                 * {
                 *  GUI.DrawLine(spriteBatch,
                 *      new Vector2(drawRect.X + WaveWidth * i, -WorldSurface - waveY[i] - 10),
                 *      new Vector2(drawRect.X + WaveWidth * (i + 1), -WorldSurface - waveY[i + 1] - 10), Color.Blue * 0.5f);
                 * }*/
            }

            if ((IsSelected || IsHighlighted) && editing)
            {
                GUI.DrawRectangle(spriteBatch,
                                  new Vector2(drawRect.X + 5, -drawRect.Y + 5),
                                  new Vector2(rect.Width - 10, rect.Height - 10),
                                  IsHighlighted ? Color.LightBlue * 0.5f : Color.Red * 0.5f, true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
            }

            foreach (MapEntity e in linkedTo)
            {
                if (e is Hull)
                {
                    Hull      linkedHull        = (Hull)e;
                    Rectangle connectedHullRect = e.Submarine == null ?
                                                  linkedHull.rect :
                                                  new Rectangle(
                        (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X),
                        (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y),
                        linkedHull.WorldRect.Width, linkedHull.WorldRect.Height);

                    //center of the hull
                    Rectangle currentHullRect = Submarine == null ?
                                                WorldRect :
                                                new Rectangle(
                        (int)(Submarine.DrawPosition.X + WorldPosition.X),
                        (int)(Submarine.DrawPosition.Y + WorldPosition.Y),
                        WorldRect.Width, WorldRect.Height);

                    GUI.DrawLine(spriteBatch,
                                 new Vector2(currentHullRect.X, -currentHullRect.Y),
                                 new Vector2(connectedHullRect.X, -connectedHullRect.Y),
                                 Color.Green, width: 2);
                }
            }
        }
Пример #27
0
        public static void DamageCharacters(Vector2 worldPosition, Attack attack, float force, Entity damageSource, Character attacker)
        {
            if (attack.Range <= 0.0f)
            {
                return;
            }

            //long range for the broad distance check, because large characters may still be in range even if their collider isn't
            float broadRange = Math.Max(attack.Range * 10.0f, 10000.0f);

            foreach (Character c in Character.CharacterList)
            {
                if (!c.Enabled ||
                    Math.Abs(c.WorldPosition.X - worldPosition.X) > broadRange ||
                    Math.Abs(c.WorldPosition.Y - worldPosition.Y) > broadRange)
                {
                    continue;
                }

                Vector2 explosionPos = worldPosition;
                if (c.Submarine != null)
                {
                    explosionPos -= c.Submarine.Position;
                }

                Hull hull       = Hull.FindHull(ConvertUnits.ToDisplayUnits(explosionPos), null, false);
                bool underWater = hull == null || explosionPos.Y < hull.Surface;

                explosionPos = ConvertUnits.ToSimUnits(explosionPos);

                Dictionary <Limb, float> distFactors = new Dictionary <Limb, float>();
                foreach (Limb limb in c.AnimController.Limbs)
                {
                    float dist = Vector2.Distance(limb.WorldPosition, worldPosition);

                    //calculate distance from the "outer surface" of the physics body
                    //doesn't take the rotation of the limb into account, but should be accurate enough for this purpose
                    float limbRadius = Math.Max(Math.Max(limb.body.width * 0.5f, limb.body.height * 0.5f), limb.body.radius);
                    dist = Math.Max(0.0f, dist - ConvertUnits.ToDisplayUnits(limbRadius));

                    if (dist > attack.Range)
                    {
                        continue;
                    }

                    float distFactor = 1.0f - dist / attack.Range;

                    //solid obstacles between the explosion and the limb reduce the effect of the explosion by 90%
                    if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null)
                    {
                        distFactor *= 0.1f;
                    }

                    distFactors.Add(limb, distFactor);

                    List <Affliction> modifiedAfflictions = new List <Affliction>();
                    foreach (Affliction affliction in attack.Afflictions.Keys)
                    {
                        modifiedAfflictions.Add(affliction.CreateMultiplied(distFactor / c.AnimController.Limbs.Length));
                    }
                    c.LastDamageSource = damageSource;
                    if (attacker == null)
                    {
                        if (damageSource is Item item)
                        {
                            attacker = item.GetComponent <Projectile>()?.User;
                            if (attacker == null)
                            {
                                attacker = item.GetComponent <MeleeWeapon>()?.User;
                            }
                        }
                    }

                    //use a position slightly from the limb's position towards the explosion
                    //ensures that the attack hits the correct limb and that the direction of the hit can be determined correctly in the AddDamage methods
                    Vector2 hitPos = limb.WorldPosition + (worldPosition - limb.WorldPosition) / dist * 0.01f;
                    c.AddDamage(hitPos, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker);

                    if (attack.StatusEffects != null && attack.StatusEffects.Any())
                    {
                        attack.SetUser(attacker);
                        var statusEffectTargets = new List <ISerializableEntity>()
                        {
                            c, limb
                        };
                        foreach (StatusEffect statusEffect in attack.StatusEffects)
                        {
                            statusEffect.Apply(ActionType.OnUse, 1.0f, damageSource, statusEffectTargets);
                            statusEffect.Apply(ActionType.Always, 1.0f, damageSource, statusEffectTargets);
                            statusEffect.Apply(underWater ? ActionType.InWater : ActionType.NotInWater, 1.0f, damageSource, statusEffectTargets);
                        }
                    }

                    if (limb.WorldPosition != worldPosition && !MathUtils.NearlyEqual(force, 0.0f))
                    {
                        Vector2 limbDiff = Vector2.Normalize(limb.WorldPosition - worldPosition);
                        if (!MathUtils.IsValid(limbDiff))
                        {
                            limbDiff = Rand.Vector(1.0f);
                        }
                        Vector2 impulse      = limbDiff * distFactor * force;
                        Vector2 impulsePoint = limb.SimPosition - limbDiff * limbRadius;
                        limb.body.ApplyLinearImpulse(impulse, impulsePoint, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
                    }
                }

                //sever joints
                if (c.IsDead && attack.SeverLimbsProbability > 0.0f)
                {
                    foreach (Limb limb in c.AnimController.Limbs)
                    {
                        if (!distFactors.ContainsKey(limb))
                        {
                            continue;
                        }
                        if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability * distFactors[limb])
                        {
                            c.TrySeverLimbJoints(limb, 1.0f);
                        }
                    }
                }
            }
        }
Пример #28
0
        protected void Apply(float deltaTime, Entity entity, List <IPropertyObject> targets)
        {
#if CLIENT
            if (sound != null)
            {
                sound.Play(1.0f, 1000.0f, entity.WorldPosition);
            }
#endif

            if (useItem)
            {
                foreach (Item item in targets.FindAll(t => t is Item).Cast <Item>())
                {
                    item.Use(deltaTime, targets.FirstOrDefault(t => t is Character) as Character);
                }
            }

            foreach (IPropertyObject target in targets)
            {
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    ObjectProperty property;

                    if (!target.ObjectProperties.TryGetValue(propertyNames[i], out property))
                    {
                        continue;
                    }

                    if (duration > 0.0f)
                    {
                        CoroutineManager.StartCoroutine(
                            ApplyToPropertyOverDuration(duration, property, propertyEffects[i]), "statuseffect");
                    }
                    else
                    {
                        ApplyToProperty(property, propertyEffects[i], deltaTime);
                    }
                }
            }

            if (explosion != null)
            {
                explosion.Explode(entity.WorldPosition);
            }


            Hull hull = null;
            if (entity is Character)
            {
                hull = ((Character)entity).AnimController.CurrentHull;
            }
            else if (entity is Item)
            {
                hull = ((Item)entity).CurrentHull;
            }

            if (FireSize > 0.0f)
            {
                var fire = new FireSource(entity.WorldPosition, hull);

                fire.Size = new Vector2(FireSize, fire.Size.Y);
            }

#if CLIENT
            foreach (ParticleEmitterPrefab emitter in particleEmitters)
            {
                emitter.Emit(entity.WorldPosition, hull);
            }
#endif
        }
Пример #29
0
        public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch, double deltaTime)
        {
            foreach (Submarine sub in Submarine.Loaded)
            {
                sub.UpdateTransform();
            }

            GameMain.ParticleManager.UpdateTransforms();

            GameMain.LightManager.ObstructVision =
                Character.Controlled != null &&
                Character.Controlled.ObstructVision &&
                (Character.Controlled.ViewTarget == Character.Controlled || Character.Controlled.ViewTarget == null);

            GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled?.CursorWorldPosition ?? Vector2.Zero);

            //------------------------------------------------------------------------
            graphics.SetRenderTarget(renderTarget);
            graphics.Clear(Color.Transparent);
            //Draw background structures and wall background sprites
            //(= the background texture that's revealed when a wall is destroyed) into the background render target
            //These will be visible through the LOS effect.
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null));
            Submarine.DrawPaintedColors(spriteBatch, false);
            spriteBatch.End();

            graphics.SetRenderTarget(null);
            GameMain.LightManager.RenderLightMap(graphics, spriteBatch, cam, renderTarget);

            //------------------------------------------------------------------------
            graphics.SetRenderTarget(renderTargetBackground);
            if (Level.Loaded == null)
            {
                graphics.Clear(new Color(11, 18, 26, 255));
            }
            else
            {
                //graphics.Clear(new Color(255, 255, 255, 255));
                Level.Loaded.DrawBack(graphics, spriteBatch, cam);
            }

            //draw alpha blended particles that are in water and behind subs
#if LINUX || OSX
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
#else
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
#endif
            GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            //draw additive particles that are in water and behind subs
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.Additive);
            spriteBatch.End();
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None);
            spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
            spriteBatch.End();

            //----------------------------------------------------------------------------

            //Start drawing to the normal render target (stuff that can't be seen through the LOS effect)
            graphics.SetRenderTarget(renderTarget);

            graphics.BlendState       = BlendState.NonPremultiplied;
            graphics.SamplerStates[0] = SamplerState.LinearWrap;
            Quad.UseBasicEffect(renderTargetBackground);
            Quad.Render();

            //Draw the rest of the structures, characters and front structures
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawBack(spriteBatch, false, e => !(e is Structure) || e.SpriteDepth < 0.9f);
            foreach (Character c in Character.CharacterList)
            {
                if (!c.IsVisible || c.AnimController.Limbs.Any(l => l.DeformSprite != null))
                {
                    continue;
                }
                c.Draw(spriteBatch, Cam);
            }
            spriteBatch.End();

            //draw characters with deformable limbs last, because they can't be batched into SpriteBatch
            //pretty hacky way of preventing draw order issues between normal and deformable sprites
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
            //backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth)
            for (int i = Character.CharacterList.Count - 1; i >= 0; i--)
            {
                Character c = Character.CharacterList[i];
                if (!c.IsVisible || c.AnimController.Limbs.All(l => l.DeformSprite == null))
                {
                    continue;
                }
                c.Draw(spriteBatch, Cam);
            }
            spriteBatch.End();

            Level.Loaded?.DrawFront(spriteBatch, cam);

            //draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
            graphics.SetRenderTarget(renderTargetWater);

            graphics.BlendState       = BlendState.Opaque;
            graphics.SamplerStates[0] = SamplerState.LinearWrap;
            Quad.UseBasicEffect(renderTarget);
            Quad.Render();

            //draw alpha blended particles that are inside a sub
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            graphics.SetRenderTarget(renderTarget);

            //draw alpha blended particles that are not in water
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.AlphaBlend);
            spriteBatch.End();

            //draw additive particles that are not in water
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
            spriteBatch.End();

            graphics.DepthStencilState = DepthStencilState.DepthRead;
            graphics.SetRenderTarget(renderTargetFinal);

            WaterRenderer.Instance.ResetBuffers();
            Hull.UpdateVertices(cam, WaterRenderer.Instance);
            WaterRenderer.Instance.RenderWater(spriteBatch, renderTargetWater, cam);
            WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform);
            graphics.DepthStencilState = DepthStencilState.None;

            spriteBatch.Begin(SpriteSortMode.Immediate,
                              BlendState.NonPremultiplied, SamplerState.LinearWrap,
                              null, null,
                              damageEffect,
                              cam.Transform);
            Submarine.DrawDamageable(spriteBatch, damageEffect, false);
            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
            Submarine.DrawFront(spriteBatch, false, null);
            spriteBatch.End();

            //draw additive particles that are inside a sub
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform);
            GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive);
            foreach (var discharger in Items.Components.ElectricalDischarger.List)
            {
                discharger.DrawElectricity(spriteBatch);
            }
            spriteBatch.End();
            if (GameMain.LightManager.LightingEnabled)
            {
                graphics.DepthStencilState = DepthStencilState.None;
                graphics.SamplerStates[0]  = SamplerState.LinearWrap;
                graphics.BlendState        = Lights.CustomBlendStates.Multiplicative;
                Quad.UseBasicEffect(GameMain.LightManager.LightMap);
                Quad.Render();
            }

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform);
            foreach (Character c in Character.CharacterList)
            {
                c.DrawFront(spriteBatch, cam);
            }

            Level.Loaded?.DrawDebugOverlay(spriteBatch, cam);
            if (GameMain.DebugDraw)
            {
                MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch));
                Character.CharacterList.ForEach(c => c.AiTarget?.Draw(spriteBatch));
                if (GameMain.GameSession?.EventManager != null)
                {
                    GameMain.GameSession.EventManager.DebugDraw(spriteBatch);
                }
            }
            spriteBatch.End();

            if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Lights.LightManager.ViewTarget != null)
            {
                GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];

                GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground);
                GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture);
                GameMain.LightManager.LosEffect.Parameters["xLosAlpha"].SetValue(GameMain.LightManager.LosAlpha);

                Color losColor;
                if (GameMain.LightManager.LosMode == LosMode.Transparent)
                {
                    //convert the los color to HLS and make sure the luminance of the color is always the same
                    //as the luminance of the ambient light color
                    float r = Character.Controlled?.CharacterHealth == null ?
                              0.0f : Math.Min(Character.Controlled.CharacterHealth.DamageOverlayTimer * 0.5f, 0.5f);
                    Vector3 ambientLightHls = GameMain.LightManager.AmbientLight.RgbToHLS();
                    Vector3 losColorHls     = Color.Lerp(GameMain.LightManager.AmbientLight, Color.Red, r).RgbToHLS();
                    losColorHls.Y = ambientLightHls.Y;
                    losColor      = ToolBox.HLSToRGB(losColorHls);
                }
                else
                {
                    losColor = Color.Black;
                }

                GameMain.LightManager.LosEffect.Parameters["xColor"].SetValue(losColor.ToVector4());

                graphics.BlendState       = BlendState.NonPremultiplied;
                graphics.SamplerStates[0] = SamplerState.PointClamp;
                GameMain.LightManager.LosEffect.CurrentTechnique.Passes[0].Apply();
                Quad.Render();
            }

            float grainStrength = Character.Controlled?.GrainStrength ?? 0;
            if (grainStrength > 0)
            {
                Rectangle screenRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: GrainEffect);
                GUI.DrawRectangle(spriteBatch, screenRect, Color.White * grainStrength, isFilled: true);
                GrainEffect.Parameters["seed"].SetValue(Rand.Range(0f, 1f, Rand.RandSync.Unsynced));
                spriteBatch.End();
            }

            graphics.SetRenderTarget(null);

            float   BlurStrength                = 0.0f;
            float   DistortStrength             = 0.0f;
            Vector3 chromaticAberrationStrength = GameMain.Config.ChromaticAberrationEnabled ?
                                                  new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero;

            if (Character.Controlled != null)
            {
                BlurStrength    = Character.Controlled.BlurStrength * 0.005f;
                DistortStrength = Character.Controlled.DistortStrength;
                if (GameMain.Config.EnableRadialDistortion)
                {
                    chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
                }
                chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
            }
            else
            {
                BlurStrength    = 0.0f;
                DistortStrength = 0.0f;
            }

            string postProcessTechnique = "";
            if (BlurStrength > 0.0f)
            {
                postProcessTechnique += "Blur";
                PostProcessEffect.Parameters["blurDistance"].SetValue(BlurStrength);
            }
            if (chromaticAberrationStrength != Vector3.Zero)
            {
                postProcessTechnique += "ChromaticAberration";
                PostProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(chromaticAberrationStrength);
            }
            if (DistortStrength > 0.0f)
            {
                postProcessTechnique += "Distort";
                PostProcessEffect.Parameters["distortScale"].SetValue(Vector2.One * DistortStrength);
                PostProcessEffect.Parameters["distortUvOffset"].SetValue(WaterRenderer.Instance.WavePos * 0.001f);
            }

            graphics.BlendState        = BlendState.Opaque;
            graphics.SamplerStates[0]  = SamplerState.LinearClamp;
            graphics.DepthStencilState = DepthStencilState.None;
            if (string.IsNullOrEmpty(postProcessTechnique))
            {
                Quad.UseBasicEffect(renderTargetFinal);
            }
            else
            {
                PostProcessEffect.Parameters["MatrixTransform"].SetValue(Matrix.Identity);
                PostProcessEffect.Parameters["xTexture"].SetValue(renderTargetFinal);
                PostProcessEffect.CurrentTechnique = PostProcessEffect.Techniques[postProcessTechnique];
                PostProcessEffect.CurrentTechnique.Passes[0].Apply();
            }
            Quad.Render();

            if (fadeToBlackState > 0.0f)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred);
                GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Lerp(Color.TransparentBlack, Color.Black, fadeToBlackState), isFilled: true);
                spriteBatch.End();
            }
        }
Пример #30
0
        public static void CreateItems(List <PurchasedItem> itemsToSpawn)
        {
            if (itemsToSpawn.Count == 0)
            {
                return;
            }

            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

#if CLIENT
            new GUIMessageBox("", TextManager.Get("CargoSpawnNotification").Replace("[roomname]", cargoRoom.DisplayName));
#endif

            Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>();
            ItemPrefab containerPrefab = null;
            foreach (PurchasedItem pi in itemsToSpawn)
            {
                Vector2 position = new Vector2(
                    Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20),
                    cargoRoom.Rect.Y - cargoRoom.Rect.Height + pi.ItemPrefab.Size.Y / 2);

                ItemContainer itemContainer = null;
                if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier))
                {
                    itemContainer = availableContainers.Keys.ToList().Find(ac =>
                                                                           ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                           ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()));

                    if (itemContainer == null)
                    {
                        containerPrefab = MapEntityPrefab.List.Find(ep =>
                                                                    ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                    (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))) as ItemPrefab;

                        if (containerPrefab == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!");
                            continue;
                        }

                        Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItem.GetComponent <ItemContainer>();
                        if (itemContainer == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                            continue;
                        }
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }
                }
                for (int i = 0; i < pi.Quantity; i++)
                {
                    if (itemContainer == null)
                    {
                        //no container, place at the waypoint
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine);
                        }
                        else
                        {
#endif
                        new Item(pi.ItemPrefab, position, wp.Submarine);
#if SERVER
                    }
#endif
                        continue;
                    }
                    //if the intial container has been removed due to it running out of space, add a new container
                    //of the same type and begin filling it
                    if (!availableContainers.ContainsKey(itemContainer))
                    {
                        Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItemOverFlow.GetComponent <ItemContainer>();
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }

                    //place in the container
#if SERVER
                    if (GameMain.Server != null)
                    {
                        Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory);
                    }
                    else
                    {
#endif
                    var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                    itemContainer.Inventory.TryPutItem(item, null);
#if SERVER
                }
#endif

                    //reduce the number of available slots in the container
                    //if there is a container
                    if (availableContainers.ContainsKey(itemContainer))
                    {
                        availableContainers[itemContainer]--;
                    }
                    if (availableContainers.ContainsKey(itemContainer) && availableContainers[itemContainer] <= 0)
                    {
                        availableContainers.Remove(itemContainer);
                    }
                }
            }
            itemsToSpawn.Clear();
        }