Beispiel #1
0
        public void UpdateCGB(MMU mmu, int value)
        {
            int  register  = mmu.ReadByte(PaletteIndexAddress);
            bool increment = Bitwise.IsBitOn(register, 7);
            int  index     = register & 0x3F;

            int colorToModify = (index % 8) / 2;

            if ((index % 8) % 2 == 0)
            {
                red[colorToModify]   = value & 0x1F;
                green[colorToModify] = (green[colorToModify] & 0x18) | (value >> 5);
            }
            else
            {
                green[colorToModify] = (green[colorToModify] & 0x07) | ((value & 0x03) << 3);
                blue[colorToModify]  = (value >> 2) & 0x1F;
            }

            Colors[colorToModify].R = (int)((red[colorToModify] / 31.0) * 255);
            Colors[colorToModify].G = (int)((green[colorToModify] / 31.0) * 255);
            Colors[colorToModify].B = (int)((blue[colorToModify] / 31.0) * 255);

            if (increment)
            {
                index = (index + 1) % 64;
                mmu.WriteByte(index | (0x80), PaletteIndexAddress);
            }
        }
Beispiel #2
0
        internal override void WriteByte(int address, int value)
        {
            switch (address)
            {
                case 0xFF20:
                    LengthSet = (value & 0x3F);
                    return;

                case 0xFF21:
                    WriteEnvelope(value);
                    return;

                case 0xFF22:
                    DividingRatio = value & 0x07;
                    ShiftWidth = Bitwise.IsBitOn(value, 3);
                    ShiftFrequency = (value >> 4) & 0xF;
                    return;

                case 0xFF23:
                    LengthEnabled = Bitwise.IsBitOn(value, 6);
                    if (Bitwise.IsBitOn(value, 7)) Enable();
                    return;
            }

            throw new InvalidOperationException(String.Format("Cannot write to memory address 0x{0:X4}", address));
        }
Beispiel #3
0
 protected void WriteEnvelope(int value)
 {
     VolumeSet       = (value >> 4);
     EnvelopeAdd     = Bitwise.IsBitOn(value, 3);
     EnvelopeTimeSet = value & 0x07;
     DAC             = (value & 0xF8) != 0;
 }
Beispiel #4
0
        internal void CheckIfLCDOff(int value)
        {
            bool lcdIsOn     = Bitwise.IsBitOn(_gameboy.Mmu.LCDC, 7);
            bool newLCDState = Bitwise.IsBitOn(value, 7);

            if (lcdIsOn && !newLCDState)
            {
                _gameboy.Mmu.LY    = 0;
                clocksCount        = 0;
                _gameboy.Mmu.STAT &= ~0x03; // Reset mode to 0 if screen is off
            }
        }
Beispiel #5
0
        public void WriteByte(int address, int value)
        {
            if (address == 0xFF26)
            {
                On = Bitwise.IsBitOn(value, 7);
            }
            if (!On)
            {
                return;
            }

            if (address <= 0xFF14)
            {
                squareChannel.WriteByte(address, value);
            }
            else if (address <= 0xFF19)
            {
                squareChannel2.WriteByte(address, value);
            }
            else if (address <= 0xFF1E)
            {
                waveChannel.WriteByte(address, value);
            }
            else if (address >= 0xFF20 && address <= 0xFF23)
            {
                noiseChannel.WriteByte(address, value);
            }
            else if (address <= 0xFF26)
            {
                switch (address)
                {
                case 0xFF24:
                    VolumeLeft   = (value >> 4) & 0x07;
                    VolumeRight  = value & 0x07;
                    OutputVinSO2 = Bitwise.IsBitOn(value, 7);
                    OutputVinSO1 = Bitwise.IsBitOn(value, 3);
                    break;

                case 0xFF25:
                    for (int i = 0; i < 8; i++)
                    {
                        OutputSound[i / 4, i % 4] = Bitwise.IsBitOn(value, i);
                    }
                    break;
                }
            }
            else if (address >= 0xFF30 && address <= 0xFF3F)
            {
                waveChannel.WriteByte(address, value);
            }
        }
Beispiel #6
0
 private void CheckLYC()
 {
     if (_gameboy.Mmu.LY == _gameboy.Mmu.LYC)
     {
         _gameboy.Mmu.STAT = Bitwise.SetBit(_gameboy.Mmu.STAT, 2);
         if (Bitwise.IsBitOn(_gameboy.Mmu.STAT, 6))
         {
             _gameboy.Mmu.SetInterrupt(Interrupts.LCDStat);
         }
     }
     else
     {
         _gameboy.Mmu.STAT = Bitwise.ClearBit(_gameboy.Mmu.STAT, 2);
     }
 }
Beispiel #7
0
        internal void Tick(int clocks)
        {
            if (timaWritten && cycles < 4)
            {
                timaWritten = false;
                cycles      = 0;
                overflow    = false;
            }

            while (clocks-- > 0)
            {
                internalDiv = Bitwise.Wrap16(internalDiv + 1);
                if (overflow)
                {
                    cycles++;
                }

                if (!checkingLow)
                {
                    checkingLow = timerEnabled && Bitwise.IsBitOn(internalDiv, timerBit);
                }
                else
                {
                    checkingLow = timerEnabled && Bitwise.IsBitOn(internalDiv, timerBit);
                    if (!checkingLow)
                    {
                        _gameboy.Mmu.TIMA = Bitwise.Wrap8(_gameboy.Mmu.TIMA + 1);
                        if (_gameboy.Mmu.TIMA == 0)
                        {
                            overflow = true;
                        }
                    }
                }

                if (cycles == 4)
                {
                    _gameboy.Mmu.SetInterrupt(Interrupts.Timer);
                    cycles            = 0;
                    overflow          = false;
                    _gameboy.Mmu.TIMA = _gameboy.Mmu.TMA;
                    timaWritten       = false;
                }
            }



            _gameboy.Mmu.DIV = (internalDiv & 0xFF00) >> 8;
        }
Beispiel #8
0
        internal void Update()
        {
            timerEnabled = Bitwise.IsBitOn(_gameboy.Mmu.TAC, 2);

            switch (_gameboy.Mmu.TAC & 0x03)
            {
            case 0: timerBit = 9; break;

            case 1: timerBit = 3; break;

            case 2: timerBit = 5; break;

            case 3: timerBit = 7; break;

            default: throw new Exception("Invalid timer setting!");
            }
        }
Beispiel #9
0
        internal void Tick(int clocks)
        {
            int mode = _gameboy.Mmu.STAT & 0x03;

            if (Bitwise.IsBitOn(_gameboy.Mmu.LCDC, 7))
            {
                clocksCount += clocks;

                if (clocksCount >= VBLANK_CLOCK_COUNT)
                {
                    _gameboy.Mmu.LY = (_gameboy.Mmu.LY + 1) % 154;
                    clocksCount    -= VBLANK_CLOCK_COUNT;
                    CheckLYC();
                    if (_gameboy.Mmu.LY >= 144 && mode != 1)
                    {
                        ChangeMode(1);
                    }
                }

                if (_gameboy.Mmu.LY < 144)
                {
                    if (clocksCount <= OAM_CLOCK_COUNT)
                    {
                        if (mode != 2)
                        {
                            ChangeMode(2);
                        }
                    }
                    else if (clocksCount <= OAM_CLOCK_COUNT + VRAM_CLOCK_COUNT)
                    {
                        if (mode != 3)
                        {
                            ChangeMode(3);
                        }
                    }
                    else
                    {
                        if (mode != 0)
                        {
                            ChangeMode(0);
                        }
                    }
                }
            }
        }
Beispiel #10
0
        void Start()
        {
            damage = 0f;

            fromController = GameManager.instance.GetPlayer(fromPlayer);
            hitController  = GameManager.instance.GetPlayer(hitPlayer);

            transform.position = hitController.transform.position + fromUp;

            lights = new Dictionary <Enums.Arrows, GameObject>();
            for (int i = 1; i < (int)Enums.Arrows.NumTypes; i++)
            {
                if (Bitwise.IsBitOn(hitController.ArcheryComponent.ArrowTypes, i))
                {
                    //hitController.ArcheryComponent.RemoveArrowType((Enums.Arrows) i);

                    GameObject light;
                    if (lights.Count > transform.childCount)
                    {
                        light = (GameObject)Instantiate(transform.GetChild(0).gameObject);
                    }
                    else
                    {
                        light = transform.GetChild(0).gameObject;
                    }

                    float r = ((float)i / ((float)Enums.Arrows.NumTypes - 1)) % 1f;
                    float g = (0.33f + (float)i / ((float)Enums.Arrows.NumTypes - 1)) % 1f;
                    float b = (0.67f + (float)i / ((float)Enums.Arrows.NumTypes - 1)) % 1f;
                    light.GetComponent <Light>().color = new Color(r, g, b);

                    light.transform.SetParent(transform);
                    light.transform.localPosition = Vector3.zero;
                    light.GetComponent <Rigidbody>().AddForce(randomInSemicircle(hitUp) * explodeForce, ForceMode.Impulse);
                    lights.Add((Enums.Arrows)i, light);
                }
            }

            hitController.ArcheryComponent.ArrowTypes = hitController.ArcheryComponent.PermanentArrowTypes;

            if (lights.Count == 0)
            {
                Destroy(gameObject);
            }
        }
Beispiel #11
0
        private void ChangeMode(int mode)
        {
            _gameboy.Mmu.STAT = (_gameboy.Mmu.STAT & ~0x03) | (mode & 0x03);

            // Handle Interrupts
            switch (mode)
            {
            case 0:
                if (Bitwise.IsBitOn(_gameboy.Mmu.STAT, 3))
                {
                    _gameboy.Mmu.SetInterrupt(Interrupts.LCDStat);
                }
                RenderLine();
                break;

            case 1:
                if (Bitwise.IsBitOn(_gameboy.Mmu.STAT, 4))
                {
                    _gameboy.Mmu.SetInterrupt(Interrupts.LCDStat);
                }
                _gameboy.Mmu.SetInterrupt(Interrupts.VBlank);
                useFb1 = !useFb1;
                if (useFb1)
                {
                    FrameBuffer = fb1;
                }
                else
                {
                    FrameBuffer = fb2;
                }

                _gameboy.EnqeueFrameBuffer(FrameBuffer);

                break;

            case 2:
                if (Bitwise.IsBitOn(_gameboy.Mmu.STAT, 5))
                {
                    _gameboy.Mmu.SetInterrupt(Interrupts.LCDStat);
                }
                break;
            }
        }
Beispiel #12
0
        internal override void WriteByte(int address, int value)
        {
            switch (address)
            {
            case 0xFF10:
                SweepShift    = value & 0x07;
                SweepDecrease = Bitwise.IsBitOn(value, 3);
                SweepTimeSet  = (value & 0x70) >> 4;
                return;

            case 0xFF11:
            case 0xFF16:
                Duty      = (value >> 6);
                LengthSet = 64 - (value & 0x3F);
                return;

            case 0xFF12:
            case 0xFF17:
                WriteEnvelope(value);
                return;

            case 0xFF13:
            case 0xFF18:
                Frequency = (Frequency & 0x700) | value;
                return;

            case 0xFF14:
            case 0xFF19:
                Frequency     = ((value & 0x7) << 8) | (Frequency & 0xFF);
                LengthEnabled = Bitwise.IsBitOn(value, 6);
                if (Bitwise.IsBitOn(value, 7))
                {
                    Enable();
                }
                return;

            case 0xFF15:
                return;
            }

            throw new InvalidOperationException(String.Format("Cannot write to memory address 0x{0:X4}", address));
        }
Beispiel #13
0
 private void RenderLine()
 {
     if (Bitwise.IsBitOn(_gameboy.Mmu.LCDC, 7))
     {
         if (Bitwise.IsBitOn(_gameboy.Mmu.LCDC, 0))
         {
             DrawBackground();
         }
         else
         {
             for (int i = 0; i < SCREEN_WIDTH; i++)
             {
                 BGPriority[i] = 0;
             }
         }
         if (Bitwise.IsBitOn(_gameboy.Mmu.LCDC, 1))
         {
             DrawSprites();
         }
     }
 }
Beispiel #14
0
 /// <summary>
 /// Add all the arrow types and setup the appropriate delegates.
 /// </summary>
 /// <param name="types">The types of components to initialize.</param>
 private void GenerateArrowProperties(int types)
 {
     // Somehow the arrow is comprised of nothing
     if (types == 0)
     {
         return;
     }
     for (int i = 0; i < (int)Enums.Arrows.NumTypes; i++)
     {
         // Check to see if the type exists in the current arrow
         if (Bitwise.IsBitOn(types, i))
         {
             // Add an arrow property and update the delegates
             ArrowProperty temp = GetArrowProperty((Enums.Arrows)i);
             temp.Type       = (Enums.Arrows)i;
             temp.FromPlayer = fromPlayer;
             Init           += temp.Init;
             Effect         += temp.Effect;
         }
     }
 }
Beispiel #15
0
        internal override void WriteByte(int address, int value)
        {
            switch (address)
            {
            case 0xFF1A:
                DAC = Bitwise.IsBitOn(value, 7);
                return;

            case 0xFF1B:
                LengthSet = value;
                return;

            case 0xFF1C:
                Volume = (value >> 5) & 0x03;
                return;

            case 0xFF1D:
                Frequency = (Frequency & 0x700) | value;
                return;

            case 0xFF1E:
                Frequency     = ((value & 0x7) << 8) | (Frequency & 0xFF);
                LengthEnabled = Bitwise.IsBitOn(value, 6);
                if (Bitwise.IsBitOn(value, 7))
                {
                    Enable();
                }
                return;

            case int _ when address >= 0xFF30 && address <= 0xFF3f:
                Samples[address - 0xFF30] = value;
                return;
            }

            throw new InvalidOperationException(String.Format("Cannot write to memory address 0x{0:X4}", address));
        }
Beispiel #16
0
        private void DrawBackground()
        {
            int sx   = _gameboy.Mmu.SCX;
            int sy   = _gameboy.Mmu.SCY;
            int lcdc = _gameboy.Mmu.LCDC;
            int ly   = _gameboy.Mmu.LY;
            int wx   = _gameboy.Mmu.WX - 7;
            int wy   = _gameboy.Mmu.WY;

            bool windowEnabled = Bitwise.IsBitOn(lcdc, 5);

            bool inWindowY = windowEnabled && ly >= wy;

            int y       = (Bitwise.Wrap8(ly + sy) / 8) * 32;
            int windowY = (((ly - wy) / 8) * 32 + 1024) % 1024;

            int bgTileMapLocation     = Bitwise.IsBitOn(lcdc, 3) ? 0x9C00 : 0x9800;
            int windowTileMapLocation = Bitwise.IsBitOn(lcdc, 6) ? 0x9C00 : 0x9800;

            int startingIndex = ly * SCREEN_WIDTH * 4;

            bool shouldValueBeSigned = !Bitwise.IsBitOn(lcdc, 4);
            int  tileInitLocation    = shouldValueBeSigned ? 256 : 0;
            bool bgPriority;

            for (int xx = 0; xx < SCREEN_WIDTH; xx++)
            {
                bool hFlip = false, vFlip = false;
                int  paletteNumber = 0, vramBank = 0;

                bool isInWindow = (inWindowY && xx >= wx);

                int x       = isInWindow ? (xx - wx) / 8 : Bitwise.Wrap8(xx + sx) / 8;
                int actualY = isInWindow ? windowY : y;

                int tile;// = _gameboy.Mmu.LoadVRAM(0x9800 + y + x);
                int mapLocation = isInWindow ? windowTileMapLocation : bgTileMapLocation;

                if (shouldValueBeSigned)
                {
                    tile = (sbyte)_gameboy.Mmu.LoadVRAM0(mapLocation + actualY + x);
                }
                else
                {
                    tile = (byte)_gameboy.Mmu.LoadVRAM0(mapLocation + actualY + x);
                }

                if (_gameboy.IsCGB)
                {
                    int value;
                    if (shouldValueBeSigned)
                    {
                        value = (sbyte)_gameboy.Mmu.LoadVRAM1(mapLocation + actualY + x);
                    }
                    else
                    {
                        value = (byte)_gameboy.Mmu.LoadVRAM1(mapLocation + actualY + x);
                    }

                    hFlip         = Bitwise.IsBitOn(value, 5);
                    vFlip         = Bitwise.IsBitOn(value, 6);
                    paletteNumber = value & 0x07;
                    vramBank      = (value >> 3) & 0x01;
                    bgPriority    = Bitwise.IsBitOn(value, 7);
                }
                else
                {
                    bgPriority = false;
                }

                int drawX = hFlip ? 7 - (xx % 8) : xx;
                int drawY = vFlip ? 7 - (ly % 8) : ly;

                if (isInWindow)
                {
                    drawX = hFlip ? 7 - ((xx - wx) % 8) : (xx - wx);
                    drawY = vFlip ? 7 - ((ly - wy) % 8) : (ly - wy);

                    drawX %= 8;
                    drawY %= 8;
                }
                else
                {
                    if (hFlip)
                    {
                        drawX = 7 - ((xx + sx) % 8);
                    }
                    else
                    {
                        drawX = (drawX + sx) % 8;
                    }

                    if (vFlip)
                    {
                        drawY = 7 - ((ly + sy) % 8);
                    }
                    else
                    {
                        drawY = (drawY + sy) % 8;
                    }
                }

                int pixel = _tileset[vramBank, tileInitLocation + tile, drawY, drawX];

                if (!bgPriority)
                {
                    BGPriority[xx] = (pixel != 0) ? 1 : 0;
                }
                else
                {
                    BGPriority[xx] = (pixel != 0) ? 2: 3;
                }

                GBColor color = _bgPalettes[paletteNumber].Colors[pixel];
                FrameBuffer[startingIndex]     = color.R;
                FrameBuffer[startingIndex + 1] = color.G;
                FrameBuffer[startingIndex + 2] = color.B;
                FrameBuffer[startingIndex + 3] = 255;
                startingIndex += 4;
            }
        }
Beispiel #17
0
        private void DrawSprites()
        {
            int  ly               = _gameboy.Mmu.LY;
            int  lcdc             = _gameboy.Mmu.LCDC;
            bool isSpriteHeight16 = Bitwise.IsBitOn(lcdc, 2);
            int  spriteHeight     = isSpriteHeight16 ? 16 : 8;
            int  spriteCount      = 0;

            for (int i = 0; i < OAM_SIZE; i += SPRITE_SIZE)
            {
                int spriteY = _gameboy.Mmu.LoadOAM(i) - 16;
                if (ly >= spriteY && ly < spriteY + spriteHeight)
                {
                    oamSprites[spriteCount++] = i;
                }
                if (spriteCount >= OAM_HORIZONTAL_LIMIT)
                {
                    break;
                }
            }

            for (int i = spriteCount - 1; i >= 0; i--)
            {
                int  index         = oamSprites[i];
                int  spriteY       = _gameboy.Mmu.LoadOAM(index) - 16;
                int  spriteX       = _gameboy.Mmu.LoadOAM(index + 1) - 8;
                int  tileNumber    = _gameboy.Mmu.LoadOAM(index + 2);
                int  upperTile     = tileNumber & 0xFE;
                int  lowerTile     = tileNumber | 0x01;
                int  attribs       = _gameboy.Mmu.LoadOAM(index + 3);
                bool objAboveBg    = !Bitwise.IsBitOn(attribs, 7);
                bool yFlip         = Bitwise.IsBitOn(attribs, 6);
                bool xFlip         = Bitwise.IsBitOn(attribs, 5);
                int  paletteNumber = Bitwise.IsBitOn(attribs, 4) ? 1 : 0;
                int  vramBank      = 0;

                if (_gameboy.IsCGB)
                {
                    vramBank      = Bitwise.IsBitOn(attribs, 3) ? 1 : 0;
                    paletteNumber = attribs & 0x07;
                }

                if (ly >= spriteY && ly < spriteY + spriteHeight)
                {
                    int writePosition = (ly * SCREEN_WIDTH * 4) + (spriteX * 4);
                    for (int x = 0; x < 8; x++)
                    {
                        if (spriteX + x >= 0 && spriteX + x < SCREEN_WIDTH)
                        {
                            int drawY = yFlip ? spriteHeight - 1 - (ly - spriteY) : ly - spriteY;
                            int drawX = xFlip ? 7 - x : x;

                            if (isSpriteHeight16)
                            {
                                if (drawY < 8)
                                {
                                    tileNumber = upperTile;
                                }
                                else
                                {
                                    tileNumber = lowerTile;
                                }
                            }
                            int pixel = _tileset[vramBank, tileNumber, drawY % 8, drawX];

                            //int colorIndex = GetSpriteColorIndexFromPalette(pixel, paletteNumber);
                            if (pixel != 0 && BGPriority[spriteX + x] != 2)
                            {
                                if (objAboveBg || BGPriority[spriteX + x] == 0 || (!objAboveBg && BGPriority[spriteX + x] == 3))
                                {
                                    GBColor color = _spPalettes[paletteNumber].Colors[pixel];
                                    FrameBuffer[writePosition]     = color.R;
                                    FrameBuffer[writePosition + 1] = color.G;
                                    FrameBuffer[writePosition + 2] = color.B;
                                    FrameBuffer[writePosition + 3] = 255;
                                }
                            }
                        }
                        writePosition += 4;
                    }
                }
            }
        }
Beispiel #18
0
 private void IncreaseStrength()
 {
     strength = Bitwise.IsBitOn(types, (int)Enums.Arrows.RapidFire)?
                MAX_STRENGTH : Mathf.Min(MAX_STRENGTH, strength + (Time.deltaTime / 2f));
 }
Beispiel #19
0
 /// <summary>
 /// Checks if there is an unobstructed shot between the ranger and a target.
 /// </summary>
 /// <returns>Whether there is an unobstructed shot between the ranger and a target.</returns>
 /// <param name="positionOffset">The vector from the ranger to its target.</param>
 /// <param name="hit">The raycast information for the shot.</param>
 internal bool HasClearShot(Vector3 positionOffset, out RaycastHit hit)
 {
     //Debug.DrawRay(transform.position + Vector3.up - Vector3.Normalize(positionOffset), positionOffset, Color.white);
     hit = new RaycastHit();
     return(Bitwise.IsBitOn(ArcheryComponent.ArrowTypes, (int)Enums.Arrows.Ghost) || !Physics.Raycast(transform.position + Vector3.up - Vector3.Normalize(positionOffset), positionOffset, out hit, Vector3.Magnitude(positionOffset) + 1, LAYERMASK));
 }
Beispiel #20
0
    // Update is called once per frame
    void Update()
    {
        if (crownIcon != null)
        {
            if (livesText)
            {
                livesText.text = GameManager.instance.GetPlayer(id).LifeComponent.Lives.ToString();
            }
            if (deathsText)
            {
                deathsText.text = GameManager.instance.GetPlayer(id).LifeComponent.Deaths.ToString();
            }
            if (killsText)
            {
                killsText.text = GameManager.instance.GetPlayer(id).LifeComponent.kills.ToString();
            }

            token1.sprite = null;
            token2.sprite = null;
            token3.sprite = null;

            token1.color = new Color(1, 1, 1, 0.5f);
            token2.color = new Color(1, 1, 1, 0.5f);
            token3.color = new Color(1, 1, 1, 0.5f);

            int numTypes = 0;
            int types    = GameManager.instance.GetPlayer(id).ArcheryComponent.ArrowTypes;
            for (int i = 0; i < (int)Enums.Arrows.NumTypes; i++)
            {
                // Check to see if the type exists in the current arrow
                if (Bitwise.IsBitOn(types, i) && ((Enums.Arrows)i) != Enums.Arrows.Normal)
                {
                    // Add an arrow property and update the delegates
                    if (numTypes == 0)
                    {
                        token1.sprite = TokenToSprite.instance.dict[(Enums.Arrows)i];
                        token1.color  = Color.white;
                        numTypes++;
                    }
                    else if (numTypes == 1)
                    {
                        token2.sprite = TokenToSprite.instance.dict[(Enums.Arrows)i];
                        token2.color  = Color.white;
                        numTypes++;
                    }
                    else if (numTypes == 2)
                    {
                        token3.sprite = TokenToSprite.instance.dict[(Enums.Arrows)i];
                        token3.color  = Color.white;
                        numTypes++;
                    }
                }
            }

            if (prevNumTypes != numTypes)
            {
                token1.transform.localScale        = Vector3.one * 2f;
                token2.transform.localScale        = Vector3.one * 2f;
                token3.transform.localScale        = Vector3.one * 2f;
                token1.transform.parent.localScale = Vector3.one * 2f;
                token2.transform.parent.localScale = Vector3.one * 2f;
                token3.transform.parent.localScale = Vector3.one * 2f;
            }
            else
            {
                token3.transform.localScale        = Vector3.MoveTowards(token3.transform.localScale, Vector3.one, Time.deltaTime);
                token3.transform.parent.localScale = Vector3.MoveTowards(token3.transform.parent.localScale, Vector3.one, Time.deltaTime * 3f);
                token2.transform.localScale        = Vector3.MoveTowards(token2.transform.localScale, Vector3.one, Time.deltaTime * 2f);
                token2.transform.parent.localScale = Vector3.MoveTowards(token2.transform.parent.localScale, Vector3.one, Time.deltaTime * 3f);
                token1.transform.localScale        = Vector3.MoveTowards(token1.transform.localScale, Vector3.one, Time.deltaTime * 3f);
                token1.transform.parent.localScale = Vector3.MoveTowards(token1.transform.parent.localScale, Vector3.one, Time.deltaTime * 3f);
            }

            prevNumTypes = numTypes;

            if (GameManager.instance.CurrentWinner == id)
            {
                crownIcon.SetActive(true);
            }
            else
            {
                crownIcon.SetActive(false);
            }
        }
    }