private void SetListOverrideInfo(SquareProperties squareValue)
        {
            var backgroundOverrideList = squareValue.GeneratedBackground.Result & 0x3f;

            if (backgroundOverrideList >= 0x9)
            {
                // ReSharper disable once LocalizableElement
                this.txtListOverrideInfo.Text = "No override";
            }
            else
            {
                var listOverride =
                    $"Override list: {backgroundOverrideList}\r\n";
                if (squareValue.BackgroundObjectData.IsHashDefault)
                {
                    listOverride +=
                        $"Default for list: {squareValue.BackgroundObjectData.Result:X2}\r\n";
                }
                else
                {
                    Debug.Assert(squareValue.BackgroundObjectData.Number.HasValue);
                    listOverride +=
                        $"Background object number: {squareValue.BackgroundObjectData.Number.Value:X2}\r\n" +
                        $"Value from list: {squareValue.BackgroundObjectData.Result:x2}\r\n";
                }

                byte contents    = (byte)(squareValue.BackgroundObjectData.Result & 0x3f);
                byte orientation = (byte)(squareValue.BackgroundObjectData.Result & 0xc0);
                listOverride +=
                    $"{(contents <= 0xf ? "Handler" : "Appearance")}: {contents:X2}, \r\n" +
                    $"Orientation: {orientation:X2} ({DescribeOrientation(orientation)})";
                this.txtListOverrideInfo.Text = listOverride;
            }
            SetTextBoxHeight(this.txtListOverrideInfo);
        }
        private void SetSpriteInfo(SquareProperties squareValue)
        {
            byte   sprite     = (byte)(SpriteBuilder.BackgroundSpriteLookup[squareValue.Background & 0x3f] & 0x7f);
            string spriteInfo =
                $"Sprite number: {sprite:X2}\r\n" +
                "Orientation on sprite sheet: ";
            var isSpriteFlippedHorizontally = SpriteBuilder.FlipSpriteHorizontally[sprite];
            var isSpriteFlippedVertically   = SpriteBuilder.FlipSpriteVertically[sprite];

            if (isSpriteFlippedHorizontally && isSpriteFlippedVertically)
            {
                spriteInfo += "flipped both ways";
            }
            else if (isSpriteFlippedHorizontally)
            {
                spriteInfo += "flipped horizontally";
            }
            else if (isSpriteFlippedVertically)
            {
                spriteInfo += "flipped vertically";
            }
            else
            {
                spriteInfo += "not flipped";
            }
            byte offsetAlongY = (byte)(SpriteBuilder.BackgroundYOffsetLookup[squareValue.Background & 0x3f] & 0xf0);

            spriteInfo += "\r\n" +
                          $"Y offset: {offsetAlongY:X2}\r\n";

            bool rightAlign            = (squareValue.Background & 0x80) != 0;
            bool bottomAlign           = (squareValue.Background & 0x40) != 0;
            var  isFlippedHorizontally = isSpriteFlippedHorizontally ^ rightAlign;
            var  isFlippedVertically   = isSpriteFlippedVertically ^ bottomAlign;

            spriteInfo +=
                "Final orientation: ";
            if (isFlippedHorizontally && isFlippedVertically)
            {
                spriteInfo += "flipped both ways";
            }
            else if (isFlippedHorizontally)
            {
                spriteInfo += "flipped horizontally";
            }
            else if (isFlippedVertically)
            {
                spriteInfo += "flipped vertically";
            }
            else
            {
                spriteInfo += "not flipped";
            }

            spriteInfo += "\r\n" +
                          $"Alignment: {(bottomAlign ? "bottom" : "top")} {(rightAlign ? "right" : "left")}";

            this.txtSpriteInfo.Text = spriteInfo;
            SetTextBoxHeight(this.txtSpriteInfo);
        }
        private void SetPaletteInfo(SquareProperties squareValue)
        {
            string paletteInfo;

            if (squareValue.PaletteData.BackgroundPalette > 6)
            {
                Debug.Assert(squareValue.PaletteData.BackgroundPalette == squareValue.PaletteData.Palette.Palette);
                paletteInfo =
                    $"Invariable palette for background: {squareValue.PaletteData.Palette}";
            }
            else
            {
                paletteInfo =
                    $"Palette algorithm for background: {squareValue.PaletteData.BackgroundPalette:X2} \r\n" +
                    $"Derived palette: {squareValue.PaletteData.Palette}";
            }

            if (squareValue.BackgroundObjectData.Result != squareValue.Background)
            {
                paletteInfo +=
                    $"\r\nRevised background: {squareValue.Background:x2}\r\n" +
                    $"Appearance: {squareValue.Background & 0x3f:X2}, " +
                    $"Orientation: {squareValue.Background & 0xc0:X2} " +
                    $"({DescribeOrientation(squareValue.Background)})";
            }

            this.txtPaletteInfo.Text = paletteInfo;
            SetTextBoxHeight(this.txtPaletteInfo);
        }
        private void AdvanceAnimation(SquareProperties squareProperties, TimeSpan timeElapsed)
        {
            TimeSpan frameLength = TimeSpan.FromMilliseconds(100);

            if (squareProperties.NextAnimationFrame.HasValue)
            {
                TimeSpan elapsed     = timeElapsed - squareProperties.NextAnimationFrame.Value;
                int      framesMoved = (int)elapsed.TotalMilliseconds / (int)frameLength.TotalMilliseconds;
                squareProperties.AnimationFrame = (squareProperties.AnimationFrame + framesMoved) % 5;
                if (this._highlightMappedDataSquares || this._highlightBackgroundObjects || this._highlightDisplayElement)
                {
                    TimeSpan timeToNextFrame = TimeSpan.FromMilliseconds(framesMoved * frameLength.TotalMilliseconds);
                    squareProperties.NextAnimationFrame = squareProperties.NextAnimationFrame.Value + timeToNextFrame;
                }
                else
                {
                    squareProperties.NextAnimationFrame = null;
                }
            }
            else
            {
                squareProperties.AnimationFrame     = 0;
                squareProperties.NextAnimationFrame = timeElapsed + frameLength;
            }
        }
        private bool DoesSquareMatchBackgroundObjectCriteria(SquareProperties squareProperties)
        {
            var type = (byte)(squareProperties.Background & 0x3f);

            if (type > 0xf || !this._selectedBackgroundObjectTypes.Contains(type))
            {
                return(false);
            }

            var result = type > 0xc || squareProperties.BackgroundObjectData.Number.HasValue;

            return(result);
        }
        private void SetMappedOrGeneratedInfo(SquareProperties squareValue)
        {
            var mappedGeneratedInfo =
                squareValue.GeneratedBackground.IsMappedData
                    ? $"Mapped location index: {squareValue.GeneratedBackground.PositionInMappedData}\r\n"
                    : string.Empty;
            byte calculatedBackground = squareValue.GeneratedBackground.Result;

            mappedGeneratedInfo +=
                $"{(squareValue.GeneratedBackground.IsMappedData ? "Explicit" : "Generated")} background {calculatedBackground:X2}\r\n";
            mappedGeneratedInfo +=
                $"Appearance: {calculatedBackground & 0x3f:X2}, " +
                $"Orientation: {calculatedBackground & 0xc0:X2} " +
                $"({DescribeOrientation(calculatedBackground)})";
            this.txtMappedOrGeneratedInfo.Text = mappedGeneratedInfo;
            SetTextBoxHeight(this.txtMappedOrGeneratedInfo);
        }
        private void CalculateSquareContents(int squareCoordinates, ConcurrentBag <int> hashOfPositions)
        {
            byte y = (byte)(squareCoordinates >> 8);
            byte x = (byte)(squareCoordinates & 0xFF);

            var generatedBackground = CalculateBackground.GetBackground(x, y);
            var data = new SquareProperties {
                X = x, Y = y, GeneratedBackground = generatedBackground
            };

            if (generatedBackground.IsMappedData)
            {
                hashOfPositions.Add(generatedBackground.PositionInMappedData);
            }

            var backgroundProperties = CalculateBackgroundObjectData.GetBackgroundObjectData(generatedBackground.Result, x);

            data.BackgroundObjectData = backgroundProperties;

            byte background  = (byte)(data.BackgroundObjectData.Result & 0x3f);
            byte orientation = (byte)(data.BackgroundObjectData.Result & 0xc0);

            if (data.BackgroundObjectData.IsBackgroundEvent)
            {
                data.BackgroundHandlerType = BackgroundHandlerTypeList[background];
                if (backgroundProperties.Number.HasValue)
                {
                    data.BackgroundDescription = DescribeBackground((BackgroundObjectType)background, backgroundProperties.Type, backgroundProperties.Data, orientation);
                }
            }

            data.PaletteData = CalculatePalette.GetPalette(ref background, ref orientation, x, y);
            data.Background  = (byte)(background ^ orientation);

            var teleportDestination = TeleportDestinations.FindIndex(item => item == new Point(x, y));

            if (teleportDestination != -1)
            {
                data.BackgroundDescription = $"Teleport destination 0x{teleportDestination:X}\r\n" + (data.BackgroundDescription ?? string.Empty);
            }

            this._squareProperties[x, y] = data;
        }
        private void SetBackgroundObjectInfo(SquareProperties squareValue)
        {
            string backgroundObjectInfo;
            byte   background = (byte)(squareValue.Background & 0x3f);

            if (!squareValue.BackgroundObjectData.Id.HasValue)
            {
                if (background < 0x10)
                {
                    backgroundObjectInfo = $"Background event used as scenery: {squareValue.BackgroundHandlerType}";
                }
                else
                {
                    backgroundObjectInfo = $"Scenery only";
                }
                if (squareValue.BackgroundDescription != null)
                {
                    backgroundObjectInfo += "\r\n" + squareValue.BackgroundDescription;
                }
            }
            else
            {
                backgroundObjectInfo  = $"Background object id: {squareValue.BackgroundObjectData.Id:X2}";
                backgroundObjectInfo += $"\r\nBackground handler: {squareValue.BackgroundHandlerType}";
                backgroundObjectInfo += "\r\n" +
                                        $"Description: {squareValue.BackgroundDescription}";
                if (squareValue.BackgroundObjectData.Type.HasValue)
                {
                    backgroundObjectInfo += "\r\n" +
                                            $"Object type: {squareValue.BackgroundObjectData.Type.Value:X2}";
                }

                if (squareValue.BackgroundObjectData.Data.HasValue)
                {
                    backgroundObjectInfo += "\r\n" +
                                            $"Data: {squareValue.BackgroundObjectData.Data.Value:X2}";
                }
            }

            this.txtBackgroundObjectInfo.Text = backgroundObjectInfo;
            SetTextBoxHeight(txtBackgroundObjectInfo);
        }
 private bool DoesSquareRequireAnimating(SquareProperties squareProperties)
 {
     if (squareProperties.NextAnimationFrame.HasValue)
     {
         return(true);
     }
     if (this._highlightMappedDataSquares && squareProperties.GeneratedBackground.IsMappedData)
     {
         return(true);
     }
     if (this._highlightBackgroundObjects && DoesSquareMatchBackgroundObjectCriteria(squareProperties))
     {
         return(true);
     }
     if (this._highlightDisplayElement && (squareProperties.Background & 0x3f) == this._displayElementToHighlight)
     {
         return(true);
     }
     return(false);
 }