private void UpdateInvaders(UpdateParams uparams)
 {
     for (int i = mInvaders.Count - 1; i > -1; --i)
     {
         Invader entity = mInvaders[i];
         entity.Update(uparams.Elapsed);
         if (entity.State != InvaderState.Alive)
         {
             mInvaders.RemoveAt(i);
             if (entity.State == InvaderState.MadeIt)
             {
                 Player.InvaderGotThrough(entity);
                 if (!Player.IsAlive)
                 {
                     GameOver = true;
                     i        = -1;
                 }
             }
             else
             {
                 Player.CollectSpoils(entity);
             }
         }
     }
 }
        private void ProcessInput(UpdateParams uparams)
        {
            // if the user selects a group of cells
            if (uparams.Input.SelectObject)
            {
                // process the selection click
                OnSelectClick(uparams);
            }

            bool selectedPieceValid = mSelectedPiece != null && mSelectedPiece.Selected;

            if (uparams.Input.SellRequested && selectedPieceValid)
            {
                mSelectedPiece.Sell();
            }
            if (uparams.Input.UpgradeRequested && selectedPieceValid)
            {
                mSelectedPiece.Upgrade();
            }
            if (uparams.Input.ClearSelections)
            {
                lstPieces.SelectedIndex = -1;
                ClearSelection();
            }
            if (uparams.Input.EctoplasTransmaterPort)
            {
                Player.TimeUntilInvadersArrive = TimeSpan.Zero;
            }
        }
        private void OnSelectClick(UpdateParams uparams)
        {
            // ignore this function if the buttons have the mouse
            if (btnSell.MouseCaptured || btnUpgrade.MouseCaptured)
            {
                return;
            }

            // always clear the current selection
            ClearSelection();

            // if the user has no selection, then select the piece
            if (lstPieces.SelectedIndex == -1)
            {
                // the piece is invalid. Find the piece that they clicked on.
                bool found = false;
                for (int i = 0; !found && i < mPieces.Count; ++i)
                {
                    Piece       piece = mPieces[i];
                    GsRectangle box   = new GsRectangle(piece.Position + uparams.Offset, piece.Size);
                    if (box.Contains(uparams.Input.CursorPosition))
                    {
                        // set selection
                        found = true;
                        SetSelection(piece);
                    }
                }
            }
        }
        private Invader RetrieveCurrentSelectedInvader(UpdateParams uparams)
        {
            Invader retval = mSelectedInvader;

            if (retval != null && retval.State != InvaderState.Alive)
            {
                retval = null;
            }

            if (uparams.Input.SelectObject)
            {
                // if they click, then reset the selection
                retval = null;
                for (int i = mInvaders.Count - 1; i > -1; --i)
                {
                    Invader invader = mInvaders[i];
                    if (invader.State == InvaderState.Alive)
                    {
                        GsRectangle box = invader.GetBoundingBox(uparams.Offset);
                        if (box.Contains(uparams.Input.CursorPosition))
                        {
                            retval = invader;
                            i      = -1;
                        }
                    }
                }
            }

            mSelectedInvader = retval;
            return(retval);
        }
        private void UpdateSelection(UpdateParams uparams)
        {
            // the user has something selected in the list. Our goal is to show the user the
            // available places where their selection can be set.

            // update the current piece selection
            UpdatePiecePlacement(uparams);

            // update the flashing cells
            UpdateFlashingCells(uparams);
        }
        private Piece RetrieveCurrentHoveredPiece(UpdateParams uparams)
        {
            Piece piece = null;

            if (lstPieces.HoverIndex > -1)
            {
                // set the hovered piece
                piece = lstPieces.Items[lstPieces.HoverIndex].Value as Piece;
            }
            return(piece);
        }
 private void UpdateSelectionList(UpdateParams uparams)
 {
     // show the list and see if we can select a piece
     lstPieces.Visible = true;
     foreach (ListBoxItem item in lstPieces.Items)
     {
         Piece piece = item.Value as Piece;
         if (piece != null)
         {
             // this item can only be selected if the player has enough cash for it
             item.CanSelect = Player.EnoughCashFor(piece);
         }
     }
 }
        private void UpdateSelectedPieceRadius(UpdateParams uparams)
        {
            Piece piece = RetrieveCurrentSelectedPiece(uparams);

            currentArea = GsRectangle.Empty;

            bool validPiece = (piece != null) && (piece.State == PieceState.Idle);

            if (validPiece && !piece.Size.IsEmpty)
            {
                float dx = piece.Width * .5f;
                float dy = piece.Height * .5f;
                currentArea = new GsRectangle(piece.X + dx, piece.Y + dy, piece.Radius, piece.Radius);
            }
        }
        private void UpdateFlashingCells(UpdateParams uparams)
        {
            List <GridCell> keys = cellsToFlash.Keys.ToList();

            foreach (GridCell cell in keys)
            {
                double amount = cellsToFlash[cell];
                amount            -= uparams.Elapsed.TotalSeconds;
                cellsToFlash[cell] = amount;
                if (amount <= 0)
                {
                    // remove the cell so it doesn't get drawn OR updated
                    cellsToFlash.Remove(cell);
                }
            }
        }
        private void UpdateDescriptionText(UpdateParams uparams)
        {
            Piece   piece   = RetrieveCurrentInformationPiece(uparams);
            Invader invader = RetrieveCurrentSelectedInvader(uparams);

            txtDescription.Visible = false;
            btnSell.Visible        = (piece != null & mSelectedPiece != null && mSelectedPiece.Equals(piece));
            btnUpgrade.Visible     = btnSell.Visible;
            btnUpgrade.Enabled     = btnSell.Visible && piece.CanUpgrade;

            if (piece != null || invader != null)
            {
                txtDescription.Visible = true;
                ITextDisplay provider = (piece != null ? (ITextDisplay)piece : (ITextDisplay)invader);
                DisplayDescriptionForTextProvider(provider);
                DisplayCaptionForTextProvider(provider);
            }
        }
        public void Update(GuiInputState state, TimeSpan span)
        {
            // update the visible pieces so they get updated right away
            UpdateVisiblePieces();

            // immediately add the waves of invaders (if necessary)
            AddInvaders();

            // update the gui
            mGui.Update(state, span);

            // construct new updata parameters for the functions
            UpdateParams uparams = new UpdateParams(span, InputProvider.GetState(), MiddleOffset + Position);

            // update the list
            UpdateSelectionList(uparams);

            // update the selection the user has made
            UpdateSelection(uparams);

            // process any requests from the user for a piece
            ProcessInput(uparams);

            // update the description text that is displayed
            UpdateDescriptionText(uparams);

            // update the radius around the selected piece
            UpdateSelectedPieceRadius(uparams);

            // update all pieces
            UpdatePieces(uparams);

            // update all invaliders
            UpdateInvaders(uparams);

            // update the piece targets
            UpdatePieceTargets(uparams);

            // update all projectiles
            UpdateProjectiles(uparams);

            // finally, update the time
            Player.TimeUntilInvadersArrive -= span;
        }
        private Piece RetrieveCurrentSelectedPiece(UpdateParams uparams)
        {
            Piece piece = null;

            bool validSelection = lstPieces.SelectedIndex > -1 || mSelectedPiece != null;

            if (validSelection)
            {
                piece = mSelectedPiece;
                if (piece == null)
                {
                    piece = lstPieces.Items[lstPieces.SelectedIndex].Value as Piece;
                    if (mSelection != null)
                    {
                        piece.Bounds = mSelection.Bounds;
                    }
                }
            }

            return(piece);
        }
        private void UpdateProjectiles(UpdateParams uparams)
        {
            float dx = CellWidth * 2f;
            float dy = CellHeight * 2f;

            GsRectangle viewport = new GsRectangle(X - dx, Y - dy, Width + dx, Height + dy);

            for (int i = mProjectiles.Count - 1; i > -1; --i)
            {
                // get the projectile
                Projectile projectile = mProjectiles[i];

                // update the projectile data
                projectile.Update(uparams.Elapsed);

                // get the polygon data
                GsPolygon polygon = projectile.GetHull(uparams.Offset);

                // if the projectile is still alive, check to see if it went out of bounds
                if (projectile.IsAlive)
                {
                    bool projectileIntersectsWithBounds = viewport.IntersectsWith(projectile.Bounds);
                    bool projectileInsideBounds         = viewport.Contains(projectile.Bounds);
                    projectile.IsAlive = projectile.StayAlive || (projectileInsideBounds || projectileIntersectsWithBounds);
                }

                // if the projectile is still alive, check to see if it hit anything
                if (projectile.IsAlive)
                {
                    CheckCollisions(projectile, polygon, uparams);
                }

                // if the projectile is dead, then remove it from the list
                if (!projectile.IsAlive)
                {
                    mProjectiles.RemoveAt(i);
                    OnProjectileRemoved(projectile);
                }
            }
        }
        private Piece RetrieveCurrentInformationPiece(UpdateParams uparams)
        {
            Piece retval = null;

            // The hovered piece information is NOT saved, so we only care about which
            // piece is being hovered over before displaying text. Note that the hovered piece will
            // take precendence over the selected invader. If an invader is selected,
            // and we hover over a piece, then the piece will display it's information.
            // once the player hovers out of the piece, the selected invader's information
            // will come back. Also note that the hovered piece takes precedence over the currently selected
            // piece.

            // get the piece that's currently being hovered over
            retval = RetrieveCurrentHoveredPiece(uparams);
            if (retval == null)
            {
                // if it's null, then get the selected piece
                retval = RetrieveCurrentSelectedPiece(uparams);
            }

            // return whichever piece. If this is null, it means no piece is hovered or selected
            return(retval);
        }
        private void UpdatePieces(UpdateParams uparams)
        {
            bool resolve = false;

            for (int i = mPieces.Count - 1; i > -1; --i)
            {
                Piece piece = mPieces[i];
                piece.Update(uparams.Elapsed);

                if (piece.State == PieceState.Sold)
                {
                    // remove the piece
                    mPieces.RemoveAt(i);

                    // if the currently selected piece is this piece, then set it to null
                    if (piece.Equals(mSelectedPiece))
                    {
                        mSelectedPiece = null;
                    }

                    // if we remove a piece the grid needs to be re-solved
                    resolve = true;
                }

                Projectile[] projectiles = piece.PopProjectiles();
                if (piece.State == PieceState.Idle)
                {
                    mProjectiles.AddRange(projectiles);
                }
            }

            if (resolve)
            {
                SolveGrid();
            }
        }
        private void UpdatePiecePlacement(UpdateParams uparams)
        {
            // set the chunk to null
            mSelection.Chunk = null;

            // don't place any towers if no towers are selected
            if (lstPieces.SelectedIndex == -1)
            {
                // end any edits that are in place
                mSelection.EndPlaceEdits();
                return;
            }

            // get the mouse point
            GsVector mousePt = uparams.Input.CursorPosition - uparams.Offset;

            // get the current chunk
            Piece piece       = lstPieces.Items[lstPieces.SelectedIndex].Value as Piece;
            int   cellsNeeded = (int)piece.Grouping;
            float width       = CellWidth * cellsNeeded;
            float height      = CellHeight * cellsNeeded;

            // compute the data needed
            GsVector    offset    = GsVector.Zero;
            GsRectangle cursorBox = Calculator.CreateBoxAroundPoint(mousePt, offset, width, height);

            GridCell[] cells = GetCellsWithCenterContainedIn(Grid, cursorBox, offset);

            if (cells.Length > 0)
            {
                GsRectangle bounds = ComputeBounds(cells, CellWidth, CellHeight);
                mSelection.Chunk = new GridCellChunk
                {
                    Bounds = bounds,
                    Cells  = cells,
                    Valid  = (cells.Length == (cellsNeeded * cellsNeeded)) && Array.TrueForAll <GridCell>(cells, GridCell.CellIsAvailable),
                };
            }

            // set the bounds of the selection to be the bounds of the chunk
            mSelection.Bounds = GsRectangle.Empty;
            if (mSelection.Chunk != null)
            {
                mSelection.Bounds = mSelection.Chunk.Bounds;
            }

            // if the mouse is down and we haven't added any chunks, then make this the starting chunk
            if (uparams.Input.SelectPressed)
            {
                // if we don't have a starting chunk, then start it
                if (mSelection.StartingChunk == null)
                {
                    mSelection.StartingChunk = mSelection.Chunk;
                }

                // clear the bounds
                mSelection.Bounds = GsRectangle.Empty;

                // get the starting chunk for easy access
                GridCellChunk startingChunk = mSelection.StartingChunk;

                // if the starting chunk is null, or invalid, then don't do this
                if (startingChunk != null && startingChunk.Valid)
                {
                    // basically, we need to determine how many chunks to add to the chunks currently being
                    // edited. We can do this by first determining where the cursor box is. If it is below us
                    // (meaning the top of the cursor box is greater than the bottom of the starting chunk
                    // box), then we just need to count and see how many cells away the [0,0] cell from the cursor
                    // box is away from the starting chunk box. So, "int countNeeded = cellsAwayFromStartingBox -
                    // (cellsAwayFromStartingBox % cellsNeeded". This will tell us how many cells we should collect
                    // in each direction (horz and vert). Then, we divide that number by cellsNeeded to get the number
                    // of chunks. Then, we simply assemble the chunks and add them to a collection. The same logic is
                    // done if the cursor box is horizontally away.

                    // clear away the chunks being edited
                    mSelection.ClearEdits();

                    // figure out if the cursor is in the vert plane, or the horz plane
                    var rect   = startingChunk.Bounds;
                    var center = rect.Location;
                    center.X += rect.Width / 2;
                    center.Y += rect.Height / 2;

                    float dy  = mousePt.Y - center.Y;
                    float dx  = mousePt.X - center.X;
                    float aDy = Math.Abs(dy);
                    float aDx = Math.Abs(dx);

                    if (aDy > aDx)
                    {
                        // the difference in the y direction is greater. If dy > 0, this means that the cursor is BELOW the starting chunk.
                        // If dy < 0, this means that the cursor is ABOVE the starting chunk. If dy == 0, then we don't care
                        if (dy != 0)
                        {
                            AddChunksVert(offset, mousePt, cellsNeeded, dy < 0);
                        }
                    }
                    else
                    {
                        // the difference in the x direction is greater. If dx > 0, this means that the cursor is RIGHT of the starting chunk.
                        // If dx < 0, this means that the cursor is LEFT of the starting chunk. Again, dx == 0, we don't care
                        if (dx != 0)
                        {
                            AddChunksHorz(offset, mousePt, cellsNeeded, dx < 0);
                        }
                    }

                    // make sure that the chunk we're drawing is the starting chunk
                    mSelection.Chunk = startingChunk;
                }
            }
            else
            {
                // if we have a starting chunk
                if (mSelection.StartingChunk != null)
                {
                    // add all the towers
                    foreach (GridCellChunk editedChunk in mSelection.Edits)
                    {
                        // see if we have enough funds
                        bool enoughFunds = Player.EnoughCashFor(piece);

                        // create a default invalid message
                        string invalidMessage = enoughFunds ? "Cell(s) not available" : "Not enough funds";

                        // update the validity of the chunk
                        editedChunk.Valid &= enoughFunds;

                        // if the chunk is valid, then attempt to place it.
                        if (editedChunk.Valid)
                        {
                            // build the piece in the location
                            Piece tower = piece.BuildFromChunk(gridBounds, editedChunk);
                            mPieces.Add(tower);

                            // if we can't get through
                            if (!AssertCanGetThrough(tower))
                            {
                                // remove the piece
                                int last = mPieces.Count - 1;
                                tower.SellInstant();
                                mPieces.RemoveAt(last);

                                // re-solve the grid
                                SolveGrid();

                                // the piece is no longer valid
                                editedChunk.Valid = false;

                                // blocking
                                invalidMessage = "Blocking Invaders";
                            }
                        }

                        if (!editedChunk.Valid)
                        {
                            // add a quick message
                            //MessageComponent.AddMessage(invalidMessage,
                            //    Position + new GsVector((Width / 2f), (Height / 2f)),
                            //    800,
                            //    true);

                            // a chunk can be invalid if all the cells don't have towers.
                            // Find any cells that have towers, and flash them red
                            foreach (GridCell cell in editedChunk.Cells)
                            {
                                if (cell.IsWalkable)
                                {
                                    // we use a dictionary so we don't add the same cell twice. We also
                                    // reset the time that the cell is flashing.
                                    cellsToFlash[cell] = SecondsToFlashCell;
                                }
                            }
                        }
                    }
                }

                mSelection.EndPlaceEdits();
            }
        }
        private void UpdatePieceTargets(UpdateParams uparams)
        {
            var offset = MiddleOffset + Position;

            mPieces.ForEach(piece => piece.ChooseTarget(mInvaders, offset));
        }
        private void CheckCollisions(Projectile projectile, GsPolygon projectilePolygon, UpdateParams uparams)
        {
            // if the projectile parent is null, then don't worry about it
            if (projectile.Parent == null)
            {
                return;
            }

            // cycle through all of the entities
            for (int i = mInvaders.Count - 1; i > -1; --i)
            {
                // get the entity
                Invader invader = mInvaders[i];

                // if this invader isn't the type of invader that the projectile can hit, then keep going
                if (!projectile.CanHit(invader))
                {
                    continue;
                }

                // get the entity polygon
                GsPolygon entityPolygon = invader.GetHull(uparams.Offset);

                // let the entity and polygon know they were attacked
                if (entityPolygon.IntersectsWith(projectilePolygon))
                {
                    // let the projectile know it collided
                    projectile.OnCollidedWithInvader(invader);

                    // let the entity know it was attacked
                    invader.OnAttackedByProjectile(projectile);
                }
            }
        }