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); } }
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)); }
protected void WriteEnvelope(int value) { VolumeSet = (value >> 4); EnvelopeAdd = Bitwise.IsBitOn(value, 3); EnvelopeTimeSet = value & 0x07; DAC = (value & 0xF8) != 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 } }
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); } }
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); } }
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; }
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!"); } }
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); } } } } }
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); } }
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; } }
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)); }
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(); } } }
/// <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; } } }
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)); }
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; } }
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; } } } }
private void IncreaseStrength() { strength = Bitwise.IsBitOn(types, (int)Enums.Arrows.RapidFire)? MAX_STRENGTH : Mathf.Min(MAX_STRENGTH, strength + (Time.deltaTime / 2f)); }
/// <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)); }
// 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); } } }