Esempio n. 1
0
        /// <summary>
        /// Update the selection logic in submarine editor
        /// </summary>
        public static void UpdateSelecting(Camera cam)
        {
            if (resizing)
            {
                if (selectedList.Count == 0)
                {
                    resizing = false;
                }
                return;
            }

            foreach (MapEntity e in mapEntityList)
            {
                e.isHighlighted = false;
            }

            if (DisableSelect)
            {
                DisableSelect = false;
                return;
            }

            if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow)
            {
                if (highlightedListBox == null ||
                    (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
                {
                    UpdateHighlightedListBox(null, false);
                    return;
                }
            }

            if (MapEntityPrefab.Selected != null)
            {
                selectionPos = Vector2.Zero;
                selectedList.Clear();
                return;
            }
            if (GUI.KeyboardDispatcher.Subscriber == null)
            {
                if (PlayerInput.KeyDown(Keys.Delete))
                {
                    selectedList.ForEach(e =>
                    {
                        //orphaned wires may already have been removed
                        if (!e.Removed)
                        {
                            e.Remove();
                        }
                    });
                    selectedList.Clear();
                }

                if (PlayerInput.IsCtrlDown())
                {
                    if (PlayerInput.KeyHit(Keys.C))
                    {
                        Copy(selectedList);
                    }
                    else if (PlayerInput.KeyHit(Keys.X))
                    {
                        Cut(selectedList);
                    }
                    else if (PlayerInput.KeyHit(Keys.V))
                    {
                        Paste(cam.WorldViewCenter);
                    }
                    else if (PlayerInput.KeyHit(Keys.G))
                    {
                        if (selectedList.Any())
                        {
                            if (SelectionGroups.ContainsKey(selectedList.Last()))
                            {
                                // Ungroup all selected
                                selectedList.ForEach(e => SelectionGroups.Remove(e));
                            }
                            else
                            {
                                foreach (var entity in selectedList)
                                {
                                    // Remove the old group, if any
                                    SelectionGroups.Remove(entity);
                                    // Create a group that can be accessed with any member
                                    SelectionGroups.Add(entity, selectedList);
                                }
                            }
                        }
                    }
                    else if (PlayerInput.KeyHit(Keys.Z))
                    {
                        SetPreviousRects(e => e.rectMemento.Undo());
                    }
                    else if (PlayerInput.KeyHit(Keys.R))
                    {
                        SetPreviousRects(e => e.rectMemento.Redo());
                    }

                    void SetPreviousRects(Func <MapEntity, Rectangle> memoryMethod)
                    {
                        foreach (var e in SelectedList)
                        {
                            if (e.rectMemento != null)
                            {
                                Point diff = memoryMethod(e).Location - e.Rect.Location;
                                // We have to call the move method, because there's a lot more than just storing the rect (in some cases)
                                // We also have to reassign the rect, because the move method does not set the width and height. They might have changed too.
                                // The Rect property is virtual and it's overridden for structs. Setting the rect via the property should automatically recreate the sections for resizable structures.
                                e.Move(diff.ToVector2());
                                e.Rect = e.rectMemento.Current;
                            }
                        }
                    }
                }
            }

            Vector2   position          = cam.ScreenToWorld(PlayerInput.MousePosition);
            MapEntity highLightedEntity = null;

            if (startMovingPos == Vector2.Zero)
            {
                List <MapEntity> highlightedEntities = new List <MapEntity>();
                if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn))
                {
                    highLightedEntity = GUI.MouseOn.UserData as MapEntity;
                }
                else
                {
                    foreach (MapEntity e in mapEntityList)
                    {
                        if (!e.SelectableInEditor)
                        {
                            continue;
                        }

                        if (e.IsMouseOn(position))
                        {
                            int i = 0;
                            while (i < highlightedEntities.Count &&
                                   e.Sprite != null &&
                                   (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth))
                            {
                                i++;
                            }

                            highlightedEntities.Insert(i, e);

                            if (i == 0)
                            {
                                highLightedEntity = e;
                            }
                        }
                    }

                    UpdateHighlighting(highlightedEntities);
                }

                if (highLightedEntity != null)
                {
                    highLightedEntity.isHighlighted = true;
                }
            }

            if (GUI.KeyboardDispatcher.Subscriber == null)
            {
                int up    = PlayerInput.KeyDown(Keys.Up) ? 1 : 0,
                    down  = PlayerInput.KeyDown(Keys.Down) ? -1 : 0,
                    left  = PlayerInput.KeyDown(Keys.Left) ? -1 : 0,
                    right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0;

                int xKeysDown = (left + right);
                int yKeysDown = (up + down);

                if (xKeysDown != 0 || yKeysDown != 0)
                {
                    keyDelay += (float)Timing.Step;
                }
                else
                {
                    keyDelay = 0;
                }

                Vector2 nudgeAmount = Vector2.Zero;

                if (keyDelay >= 0.5f)
                {
                    nudgeAmount.Y = yKeysDown;
                    nudgeAmount.X = xKeysDown;
                }

                if (PlayerInput.KeyHit(Keys.Up))
                {
                    nudgeAmount.Y = 1f;
                }
                if (PlayerInput.KeyHit(Keys.Down))
                {
                    nudgeAmount.Y = -1f;
                }
                if (PlayerInput.KeyHit(Keys.Left))
                {
                    nudgeAmount.X = -1f;
                }
                if (PlayerInput.KeyHit(Keys.Right))
                {
                    nudgeAmount.X = 1f;
                }
                if (nudgeAmount != Vector2.Zero)
                {
                    foreach (MapEntity entityToNudge in selectedList)
                    {
                        entityToNudge.Move(nudgeAmount);
                    }
                }
            }
            else
            {
                keyDelay = 0;
            }

            bool isShiftDown = PlayerInput.IsShiftDown();

            //started moving selected entities
            if (startMovingPos != Vector2.Zero)
            {
                Item targetContainer = GetPotentialContainer(position, selectedList);

                if (targetContainer != null)
                {
                    targetContainer.IsHighlighted = true;
                }

                if (PlayerInput.PrimaryMouseButtonReleased())
                {
                    //mouse released -> move the entities to the new position of the mouse

                    Vector2 moveAmount = position - startMovingPos;

                    if (!isShiftDown)
                    {
                        moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
                        moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
                    }

                    if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
                    {
                        if (!isShiftDown)
                        {
                            moveAmount = Submarine.VectorToWorldGrid(moveAmount);
                        }

                        //clone
                        if (PlayerInput.IsCtrlDown())
                        {
                            var clones = Clone(selectedList);
                            selectedList = clones;
                            selectedList.ForEach(c => c.Move(moveAmount));
                        }
                        else // move
                        {
                            List <MapEntity> deposited = new List <MapEntity>();
                            foreach (MapEntity e in selectedList)
                            {
                                if (e.rectMemento == null)
                                {
                                    e.rectMemento = new Memento <Rectangle>();
                                    e.rectMemento.Store(e.Rect);
                                }
                                e.Move(moveAmount);

                                if (isShiftDown && e is Item item && targetContainer != null)
                                {
                                    if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled))
                                    {
                                        GUI.PlayUISound(GUISoundType.DropItem);
                                        deposited.Add(item);
                                    }
                                    else
                                    {
                                        GUI.PlayUISound(GUISoundType.PickItemFail);
                                    }
                                }
                                e.rectMemento.Store(e.Rect);
                            }

                            deposited.ForEach(entity => { selectedList.Remove(entity); });
                        }
                    }
                    startMovingPos = Vector2.Zero;
                }
            }
            //started dragging a "selection rectangle"
            else if (selectionPos != Vector2.Zero)
            {
                selectionSize.X = position.X - selectionPos.X;
                selectionSize.Y = selectionPos.Y - position.Y;

                List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
                if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y)
                {
                    newSelection = FindSelectedEntities(selectionPos, selectionSize);
                }
                else
                {
                    if (highLightedEntity != null)
                    {
                        if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group))
                        {
                            newSelection.AddRange(group);
                        }
                        else
                        {
                            newSelection.Add(highLightedEntity);
                        }
                    }
                }

                if (PlayerInput.PrimaryMouseButtonReleased())
                {
                    if (PlayerInput.IsCtrlDown())
                    {
                        foreach (MapEntity e in newSelection)
                        {
                            if (selectedList.Contains(e))
                            {
                                RemoveSelection(e);
                            }
                            else
                            {
                                AddSelection(e);
                            }
                        }
                    }
                    else
                    {
                        selectedList = new List <MapEntity>(newSelection);
                        //selectedList.Clear();
                        //newSelection.ForEach(e => AddSelection(e));
                        foreach (var entity in newSelection)
                        {
                            HandleDoorGapLinks(entity,
                                               onGapFound: (door, gap) =>
                            {
                                door.RefreshLinkedGap();
                                if (!selectedList.Contains(gap))
                                {
                                    selectedList.Add(gap);
                                }
                            },
                                               onDoorFound: (door, gap) =>
                            {
                                if (!selectedList.Contains(door.Item))
                                {
                                    selectedList.Add(door.Item);
                                }
                            });
                        }
                    }

                    //select wire if both items it's connected to are selected
                    var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList();
                    foreach (Item item in selectedItems)
                    {
                        if (item.Connections == null)
                        {
                            continue;
                        }
                        foreach (Connection c in item.Connections)
                        {
                            foreach (Wire w in c.Wires)
                            {
                                if (w == null || selectedList.Contains(w.Item))
                                {
                                    continue;
                                }

                                if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item))
                                {
                                    selectedList.Add(w.Item);
                                }
                            }
                        }
                    }

                    selectionPos  = Vector2.Zero;
                    selectionSize = Vector2.Zero;
                }
            }
            //default, not doing anything specific yet
            else
            {
                if (PlayerInput.PrimaryMouseButtonHeld() &&
                    PlayerInput.KeyUp(Keys.Space) &&
                    (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
                {
                    //if clicking a selected entity, start moving it
                    foreach (MapEntity e in selectedList)
                    {
                        if (e.IsMouseOn(position))
                        {
                            startMovingPos = position;
                        }
                    }
                    selectionPos = position;

                    //stop camera movement to prevent accidental dragging or rect selection
                    Screen.Selected.Cam.StopMovement();
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Update the selection logic in submarine editor
        /// </summary>
        public static void UpdateSelecting(Camera cam)
        {
            if (resizing)
            {
                if (selectedList.Count == 0)
                {
                    resizing = false;
                }
                return;
            }

            foreach (MapEntity e in mapEntityList)
            {
                e.isHighlighted = false;
            }

            if (DisableSelect)
            {
                DisableSelect = false;
                return;
            }

            if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow)
            {
                if (highlightedListBox == null ||
                    (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
                {
                    UpdateHighlightedListBox(null);
                    return;
                }
            }

            if (MapEntityPrefab.Selected != null)
            {
                selectionPos = Vector2.Zero;
                selectedList.Clear();
                return;
            }

            if (PlayerInput.KeyDown(Keys.Delete))
            {
                selectedList.ForEach(e => e.Remove());
                selectedList.Clear();
            }

            if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
            {
                if (PlayerInput.KeyHit(Keys.C))
                {
                    CopyEntities(selectedList);
                }
                else if (PlayerInput.KeyHit(Keys.X))
                {
                    CopyEntities(selectedList);

                    selectedList.ForEach(e => e.Remove());
                    selectedList.Clear();
                }
                else if (copiedList.Count > 0 && PlayerInput.KeyHit(Keys.V))
                {
                    List <MapEntity> prevEntities = new List <MapEntity>(mapEntityList);
                    Clone(copiedList);

                    var clones = mapEntityList.Except(prevEntities).ToList();

                    Vector2 center = Vector2.Zero;
                    clones.ForEach(c => center += c.WorldPosition);
                    center = Submarine.VectorToWorldGrid(center / clones.Count);

                    Vector2 moveAmount = Submarine.VectorToWorldGrid(cam.WorldViewCenter - center);

                    selectedList = new List <MapEntity>(clones);
                    foreach (MapEntity clone in selectedList)
                    {
                        clone.Move(moveAmount);
                        clone.Submarine = Submarine.MainSub;
                    }
                }
                else if (PlayerInput.KeyHit(Keys.G))
                {
                    if (selectedList.Any())
                    {
                        if (SelectionGroups.ContainsKey(selectedList.Last()))
                        {
                            // Ungroup all selected
                            selectedList.ForEach(e => SelectionGroups.Remove(e));
                        }
                        else
                        {
                            foreach (var entity in selectedList)
                            {
                                // Remove the old group, if any
                                SelectionGroups.Remove(entity);
                                // Create a group that can be accessed with any member
                                SelectionGroups.Add(entity, selectedList);
                            }
                        }
                    }
                }
                else if (PlayerInput.KeyHit(Keys.Z))
                {
                    SetPreviousRects(e => e.rectMemento.Undo());
                }
                else if (PlayerInput.KeyHit(Keys.R))
                {
                    SetPreviousRects(e => e.rectMemento.Redo());
                }
                void SetPreviousRects(Func <MapEntity, Rectangle> memoryMethod)
                {
                    foreach (var e in SelectedList)
                    {
                        if (e.rectMemento != null)
                        {
                            Point diff = memoryMethod(e).Location - e.Rect.Location;
                            // We have to call the move method, because there's a lot more than just storing the rect (in some cases)
                            // We also have to reassign the rect, because the move method does not set the width and height. They might have changed too.
                            // The Rect property is virtual and it's overridden for structs. Setting the rect via the property should automatically recreate the sections for resizable structures.
                            e.Move(diff.ToVector2());
                            e.Rect = e.rectMemento.Current;
                        }
                    }
                }
            }

            Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);

            MapEntity highLightedEntity = null;

            if (startMovingPos == Vector2.Zero)
            {
                List <MapEntity> highlightedEntities = new List <MapEntity>();
                if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn))
                {
                    highLightedEntity = GUI.MouseOn.UserData as MapEntity;
                }
                else
                {
                    foreach (MapEntity e in mapEntityList)
                    {
                        if (!e.SelectableInEditor)
                        {
                            continue;
                        }

                        if (e.IsMouseOn(position))
                        {
                            int i = 0;
                            while (i < highlightedEntities.Count &&
                                   e.Sprite != null &&
                                   (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth))
                            {
                                i++;
                            }

                            highlightedEntities.Insert(i, e);

                            if (i == 0)
                            {
                                highLightedEntity = e;
                            }
                        }
                    }

                    if (PlayerInput.MouseSpeed.LengthSquared() > 10)
                    {
                        highlightTimer = 0.0f;
                    }
                    else
                    {
                        bool mouseNearHighlightBox = false;

                        if (highlightedListBox != null)
                        {
                            Rectangle expandedRect = highlightedListBox.Rect;
                            expandedRect.Inflate(20, 20);
                            mouseNearHighlightBox = expandedRect.Contains(PlayerInput.MousePosition);
                            if (!mouseNearHighlightBox)
                            {
                                highlightedListBox = null;
                            }
                        }

                        highlightTimer += (float)Timing.Step;
                        if (highlightTimer > 1.0f)
                        {
                            if (!mouseNearHighlightBox)
                            {
                                UpdateHighlightedListBox(highlightedEntities);
                                highlightTimer = 0.0f;
                            }
                        }
                    }
                }

                if (highLightedEntity != null)
                {
                    highLightedEntity.isHighlighted = true;
                }
            }

            Vector2 nudgeAmount = Vector2.Zero;

            if (PlayerInput.KeyHit(Keys.Up))
            {
                nudgeAmount.Y = 1f;
            }
            if (PlayerInput.KeyHit(Keys.Down))
            {
                nudgeAmount.Y = -1f;
            }
            if (PlayerInput.KeyHit(Keys.Left))
            {
                nudgeAmount.X = -1f;
            }
            if (PlayerInput.KeyHit(Keys.Right))
            {
                nudgeAmount.X = 1f;
            }
            if (nudgeAmount != Vector2.Zero)
            {
                foreach (MapEntity entityToNudge in selectedList)
                {
                    entityToNudge.Move(nudgeAmount);
                }
            }

            //started moving selected entities
            if (startMovingPos != Vector2.Zero)
            {
                if (PlayerInput.LeftButtonReleased())
                {
                    //mouse released -> move the entities to the new position of the mouse

                    Vector2 moveAmount = position - startMovingPos;
                    moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
                    moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
                    if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y)
                    {
                        moveAmount = Submarine.VectorToWorldGrid(moveAmount);
                        //clone
                        if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
                        {
                            var clones = Clone(selectedList);
                            selectedList = clones;
                            selectedList.ForEach(c => c.Move(moveAmount));
                        }
                        else // move
                        {
                            foreach (MapEntity e in selectedList)
                            {
                                if (e.rectMemento == null)
                                {
                                    e.rectMemento = new Memento <Rectangle>();
                                    e.rectMemento.Store(e.Rect);
                                }
                                e.Move(moveAmount);
                                e.rectMemento.Store(e.Rect);
                            }
                        }
                    }
                    startMovingPos = Vector2.Zero;
                }
            }
            //started dragging a "selection rectangle"
            else if (selectionPos != Vector2.Zero)
            {
                selectionSize.X = position.X - selectionPos.X;
                selectionSize.Y = selectionPos.Y - position.Y;

                List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
                if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y)
                {
                    newSelection = FindSelectedEntities(selectionPos, selectionSize);
                }
                else
                {
                    if (highLightedEntity != null)
                    {
                        if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group))
                        {
                            newSelection.AddRange(group);
                        }
                        else
                        {
                            newSelection.Add(highLightedEntity);
                        }
                    }
                }

                if (PlayerInput.LeftButtonReleased())
                {
                    if (PlayerInput.KeyDown(Keys.LeftControl) ||
                        PlayerInput.KeyDown(Keys.RightControl))
                    {
                        foreach (MapEntity e in newSelection)
                        {
                            if (selectedList.Contains(e))
                            {
                                selectedList.Remove(e);
                            }
                            else
                            {
                                selectedList.Add(e);
                            }
                        }
                    }
                    else
                    {
                        selectedList = newSelection;
                    }

                    //select wire if both items it's connected to are selected
                    var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList();
                    foreach (Item item in selectedItems)
                    {
                        if (item.Connections == null)
                        {
                            continue;
                        }
                        foreach (Connection c in item.Connections)
                        {
                            foreach (Wire w in c.Wires)
                            {
                                if (w == null || selectedList.Contains(w.Item))
                                {
                                    continue;
                                }

                                if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item))
                                {
                                    selectedList.Add(w.Item);
                                }
                            }
                        }
                    }

                    selectionPos  = Vector2.Zero;
                    selectionSize = Vector2.Zero;
                }
            }
            //default, not doing anything specific yet
            else
            {
                if (PlayerInput.LeftButtonHeld() &&
                    PlayerInput.KeyUp(Keys.Space) &&
                    (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
                {
                    //if clicking a selected entity, start moving it
                    foreach (MapEntity e in selectedList)
                    {
                        if (e.IsMouseOn(position))
                        {
                            startMovingPos = position;
                        }
                    }
                    selectionPos = position;

                    //stop camera movement to prevent accidental dragging or rect selection
                    Screen.Selected.Cam.StopMovement();
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Update the selection logic in submarine editor
        /// </summary>
        public static void UpdateSelecting(Camera cam)
        {
            if (resizing)
            {
                if (selectedList.Count == 0)
                {
                    resizing = false;
                }
                return;
            }

            foreach (MapEntity e in mapEntityList)
            {
                e.isHighlighted = false;
            }

            if (DisableSelect)
            {
                DisableSelect = false;
                return;
            }

            if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow)
            {
                if (highlightedListBox == null ||
                    (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
                {
                    UpdateHighlightedListBox(null, false);
                    return;
                }
            }

            if (MapEntityPrefab.Selected != null)
            {
                selectionPos = Vector2.Zero;
                selectedList.Clear();
                return;
            }
            if (GUI.KeyboardDispatcher.Subscriber == null)
            {
                if (PlayerInput.KeyHit(Keys.Delete))
                {
                    if (selectedList.Any())
                    {
                        SubEditorScreen.StoreCommand(new AddOrDeleteCommand(selectedList, true));
                    }
                    selectedList.ForEach(e => { if (!e.Removed)
                                                {
                                                    e.Remove();
                                                }
                                         });
                    selectedList.Clear();
                }

                if (PlayerInput.IsCtrlDown())
                {
#if DEBUG
                    if (PlayerInput.KeyHit(Keys.D))
                    {
                        bool terminate = false;
                        foreach (MapEntity entity in selectedList)
                        {
                            if (entity is Item item && item.GetComponent <Planter>() is { } planter)
                            {
                                planter.Update(1.0f, cam);
                                for (var i = 0; i < planter.GrowableSeeds.Length; i++)
                                {
                                    Growable  seed = planter.GrowableSeeds[i];
                                    PlantSlot slot = planter.PlantSlots.ContainsKey(i) ? planter.PlantSlots[i] : Planter.NullSlot;
                                    if (seed == null)
                                    {
                                        continue;
                                    }

                                    seed.CreateDebugHUD(planter, slot);
                                    terminate = true;
                                    break;
                                }
                            }

                            if (terminate)
                            {
                                break;
                            }
                        }
                    }
#endif
                    if (PlayerInput.KeyHit(Keys.C))
                    {
                        Copy(selectedList);
                    }
                    else if (PlayerInput.KeyHit(Keys.X))
                    {
                        Cut(selectedList);
                    }
                    else if (PlayerInput.KeyHit(Keys.V))
                    {
                        Paste(cam.WorldViewCenter);
                    }
                    else if (PlayerInput.KeyHit(Keys.G))
                    {
                        if (selectedList.Any())
                        {
                            if (SelectionGroups.ContainsKey(selectedList.Last()))
                            {
                                // Ungroup all selected
                                selectedList.ForEach(e => SelectionGroups.Remove(e));
                            }
                            else
                            {
                                foreach (var entity in selectedList)
                                {
                                    // Remove the old group, if any
                                    SelectionGroups.Remove(entity);
                                    // Create a group that can be accessed with any member
                                    SelectionGroups.Add(entity, selectedList);
                                }
                            }
                        }
                    }
                }
            }

            Vector2   position          = cam.ScreenToWorld(PlayerInput.MousePosition);
            MapEntity highLightedEntity = null;
            if (startMovingPos == Vector2.Zero)
            {
                List <MapEntity> highlightedEntities = new List <MapEntity>();
                if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn))
                {
                    highLightedEntity = GUI.MouseOn.UserData as MapEntity;
                }
                else
                {
                    foreach (MapEntity e in mapEntityList)
                    {
                        if (!e.SelectableInEditor)
                        {
                            continue;
                        }

                        if (e.IsMouseOn(position))
                        {
                            int i = 0;
                            while (i < highlightedEntities.Count &&
                                   e.Sprite != null &&
                                   (highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth))
                            {
                                i++;
                            }

                            highlightedEntities.Insert(i, e);

                            if (i == 0)
                            {
                                highLightedEntity = e;
                            }
                        }
                    }

                    UpdateHighlighting(highlightedEntities);
                }

                if (highLightedEntity != null)
                {
                    highLightedEntity.isHighlighted = true;
                }
            }

            if (GUI.KeyboardDispatcher.Subscriber == null)
            {
                int up    = PlayerInput.KeyDown(Keys.Up) ? 1 : 0,
                    down  = PlayerInput.KeyDown(Keys.Down) ? -1 : 0,
                    left  = PlayerInput.KeyDown(Keys.Left) ? -1 : 0,
                    right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0;

                int xKeysDown = (left + right);
                int yKeysDown = (up + down);

                if (xKeysDown != 0 || yKeysDown != 0)
                {
                    keyDelay += (float)Timing.Step;
                }
                else
                {
                    keyDelay = 0;
                }

                Vector2 nudgeAmount = Vector2.Zero;

                if (keyDelay >= 0.5f)
                {
                    nudgeAmount.Y = yKeysDown;
                    nudgeAmount.X = xKeysDown;
                }

                if (PlayerInput.KeyHit(Keys.Up))
                {
                    nudgeAmount.Y = 1f;
                }
                if (PlayerInput.KeyHit(Keys.Down))
                {
                    nudgeAmount.Y = -1f;
                }
                if (PlayerInput.KeyHit(Keys.Left))
                {
                    nudgeAmount.X = -1f;
                }
                if (PlayerInput.KeyHit(Keys.Right))
                {
                    nudgeAmount.X = 1f;
                }
                if (nudgeAmount != Vector2.Zero)
                {
                    foreach (MapEntity entityToNudge in selectedList)
                    {
                        entityToNudge.Move(nudgeAmount);
                    }
                }
            }
            else
            {
                keyDelay = 0;
            }

            bool isShiftDown = PlayerInput.IsShiftDown();

            //started moving selected entities
            if (startMovingPos != Vector2.Zero)
            {
                Item targetContainer = GetPotentialContainer(position, selectedList);

                if (targetContainer != null)
                {
                    targetContainer.IsHighlighted = true;
                }

                if (PlayerInput.PrimaryMouseButtonReleased())
                {
                    //mouse released -> move the entities to the new position of the mouse

                    Vector2 moveAmount = position - startMovingPos;

                    if (!isShiftDown)
                    {
                        moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
                        moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
                    }

                    if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
                    {
                        if (!isShiftDown)
                        {
                            moveAmount = Submarine.VectorToWorldGrid(moveAmount);
                        }

                        //clone
                        if (PlayerInput.IsCtrlDown())
                        {
                            var clones = Clone(selectedList).Where(c => c != null).ToList();
                            selectedList = clones;
                            SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false));
                            selectedList.ForEach(c => c.Move(moveAmount));
                        }
                        else // move
                        {
                            var oldRects = selectedList.Select(e => e.Rect).ToList();
                            List <MapEntity> deposited = new List <MapEntity>();
                            foreach (MapEntity e in selectedList)
                            {
                                e.Move(moveAmount);

                                if (isShiftDown && e is Item item && targetContainer != null)
                                {
                                    if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled))
                                    {
                                        SoundPlayer.PlayUISound(GUISoundType.DropItem);
                                        deposited.Add(item);
                                    }
                                    else
                                    {
                                        SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
                                    }
                                }
                            }

                            SubEditorScreen.StoreCommand(new TransformCommand(new List <MapEntity>(selectedList), selectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
                            if (deposited.Any() && deposited.Any(entity => entity is Item))
                            {
                                var depositedItems = deposited.Where(entity => entity is Item).Cast <Item>().ToList();
                                SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false));
                            }

                            deposited.ForEach(entity => { selectedList.Remove(entity); });
                        }
                    }
                    startMovingPos = Vector2.Zero;
                }
            }
            //started dragging a "selection rectangle"
            else if (selectionPos != Vector2.Zero)
            {
                selectionSize.X = position.X - selectionPos.X;
                selectionSize.Y = selectionPos.Y - position.Y;

                List <MapEntity> newSelection = new List <MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
                if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y)
                {
                    newSelection = FindSelectedEntities(selectionPos, selectionSize);
                }
                else
                {
                    if (highLightedEntity != null)
                    {
                        if (SelectionGroups.TryGetValue(highLightedEntity, out List <MapEntity> group))
                        {
                            newSelection.AddRange(group);
                        }
                        else
                        {
                            newSelection.Add(highLightedEntity);
                        }
                    }
                }

                if (PlayerInput.PrimaryMouseButtonReleased())
                {
                    if (PlayerInput.IsCtrlDown())
                    {
                        foreach (MapEntity e in newSelection)
                        {
                            if (selectedList.Contains(e))
                            {
                                RemoveSelection(e);
                            }
                            else
                            {
                                AddSelection(e);
                            }
                        }
                    }
                    else
                    {
                        selectedList = new List <MapEntity>(newSelection);
                        //selectedList.Clear();
                        //newSelection.ForEach(e => AddSelection(e));
                        foreach (var entity in newSelection)
                        {
                            HandleDoorGapLinks(entity,
                                               onGapFound: (door, gap) =>
                            {
                                door.RefreshLinkedGap();
                                if (!selectedList.Contains(gap))
                                {
                                    selectedList.Add(gap);
                                }
                            },
                                               onDoorFound: (door, gap) =>
                            {
                                if (!selectedList.Contains(door.Item))
                                {
                                    selectedList.Add(door.Item);
                                }
                            });
                        }
                    }

                    //select wire if both items it's connected to are selected
                    var selectedItems = selectedList.Where(e => e is Item).Cast <Item>().ToList();
                    foreach (Item item in selectedItems)
                    {
                        if (item.Connections == null)
                        {
                            continue;
                        }
                        foreach (Connection c in item.Connections)
                        {
                            foreach (Wire w in c.Wires)
                            {
                                if (w == null || selectedList.Contains(w.Item))
                                {
                                    continue;
                                }

                                if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item))
                                {
                                    selectedList.Add(w.Item);
                                }
                            }
                        }
                    }

                    selectionPos  = Vector2.Zero;
                    selectionSize = Vector2.Zero;
                }
            }
            //default, not doing anything specific yet
            else
            {
                if (PlayerInput.PrimaryMouseButtonHeld() &&
                    PlayerInput.KeyUp(Keys.Space) &&
                    (highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
                {
                    //if clicking a selected entity, start moving it
                    foreach (MapEntity e in selectedList)
                    {
                        if (e.IsMouseOn(position))
                        {
                            startMovingPos = position;
                        }
                    }
                    selectionPos = position;

                    //stop camera movement to prevent accidental dragging or rect selection
                    Screen.Selected.Cam.StopMovement();
                }
            }
        }