private void UpdateBossSprite(Level level, GameObject bossObject, RomPatcher patcher) { Enemy bossEnemy = RobotMasterEnemies.EnemyData.Where(enemy => enemy.Name == bossObject.Name).First(); for (int addr = level.EnemyDataAddress; addr <= level.EnemyDataAddressEnd; addr++) { int enemyId = patcher.GetByteAtAddress(addr); if (enemyId == (int)level.BossEnemy) { patcher.AddRomModification(addr, (byte)bossEnemy.EnemyNameId); Console.Out.WriteLine("Replacing enemy at " + addr + " with new boss sprite"); return; } } Console.Out.WriteLine("Orphaned robot master: " + bossObject.Name); }
void ReplaceEnemiesRandomly(Level level, Random random, RomPatcher patcher) { int enemyIndex = 0; byte currentScreen = 1; List <int> addressesToShuffle = new List <int>(); for (int address = level.EnemyDataAddress; address <= level.EnemyDataAddressEnd; address++) { byte screenValue = patcher.GetByteAtAddress(level.ScreenNumberStart + enemyIndex); if (screenValue != currentScreen) { List <int> shuffledAddresses = addressesToShuffle.OrderBy((item) => random.Next()).ToList(); List <KeyValuePair <Enemy, byte> > addedEnemiesToXPos = new List <KeyValuePair <Enemy, byte> >(); shuffledAddresses.ForEach(currentAddress => { byte enemyIDValue = patcher.GetByteAtAddress(currentAddress); int yPosLocation = currentAddress - Level.Y_POS_OFFSET_BASE; byte yPos = patcher.GetByteAtAddress(yPosLocation); int xPosLocation = currentAddress - Level.X_POS_OFFSET_BASE; byte xPos = patcher.GetByteAtAddress(xPosLocation); if (Enemies.EnemyData.Exists(enemy => enemy.Value == enemyIDValue)) { var enemyToReplace = Enemies.EnemyData.Where(enemy => enemy.Value == enemyIDValue).First(); List <Enemy> validEnemies = null; var specialEnemyOffsets = level.OffsetToSpecialEnemyList; if (specialEnemyOffsets.ContainsKey(currentAddress)) { validEnemies = Enemies.EnemyData.Where(enemy => specialEnemyOffsets[currentAddress].Contains(enemy.EnemyNameId)).ToList(); } else if (enemyToReplace.IsFlying) { validEnemies = Enemies.EnemyData.Where(enemy => enemy.IsFlying || enemy.CanReplaceFliers).ToList(); } else if (enemyToReplace.IsInverted) { validEnemies = Enemies.EnemyData.Where(enemy => enemy.IsInverted || enemy.IsFlying || enemy.CanReplaceFliers).ToList(); } else if (enemyToReplace.IsJetSkiOnly) { validEnemies = Enemies.EnemyData.Where(enemy => !enemy.IsBigBoy && !enemy.IsInverted).ToList(); } else if (enemyToReplace.IsUnderwaterOnly) { validEnemies = Enemies.EnemyData.Where(enemy => enemy.IsUnderwaterOnly || enemy.IsFlying || enemy.CanReplaceFliers).ToList(); } else if (enemyToReplace.IsBigBoy) { validEnemies = Enemies.EnemyData.Where(enemy => enemy.IsBigBoy).ToList(); } else { validEnemies = Enemies.EnemyData.Where(enemy => !enemy.IsInverted && !enemy.IsJetSkiOnly && !enemy.IsUnderwaterOnly && !enemy.IsBigBoy && (!enemy.Name.ToLower().Contains("spikewheel") || random.Next(0, 5) == 1)).ToList(); // Too many spike wheels, weed them out a bit } // Remove conflicting enemies foreach (var kvp in addedEnemiesToXPos) { var enemyToCompare = kvp.Key; if (enemyToCompare.EnemyNameId != EnemyNameId.NullEnemy) { validEnemies.RemoveAll(enemy => { bool conflict = false; if (enemy.SpriteBank == enemyToCompare.SpriteBank && enemy.EnemyNameId != enemyToCompare.EnemyNameId) { conflict = true; EnemyCompatabilityGroupings.SameSpriteGroupings.ForEach(grouping => conflict &= !(grouping.Contains(enemy.EnemyNameId) && grouping.Contains(enemyToCompare.EnemyNameId))); } EnemyExclusionGroupings.ExclusionGroupings.ForEach(grouping => conflict |= (grouping.Contains(enemy.EnemyNameId) && grouping.Contains(enemyToCompare.EnemyNameId))); return(conflict); }); } } Enemy selectedEnemy = null; if (validEnemies.Count == 0) { selectedEnemy = new Enemy(EnemyNameId.NullEnemy, 0, false, false, false, false, false, false, 0); } else { selectedEnemy = validEnemies[random.Next(0, validEnemies.Count)]; } byte newYPos = (byte)(yPos + selectedEnemy.YOffset - enemyToReplace.YOffset); patcher.AddRomModification(currentAddress, selectedEnemy.Value, selectedEnemy.Name); patcher.AddRomModification(yPosLocation, newYPos, selectedEnemy.Name); addedEnemiesToXPos.Add(new KeyValuePair <Enemy, byte>(selectedEnemy, xPos)); } else if (IrreplaceableEnemies.EnemyData.Exists(enemy => enemy.Value == enemyIDValue)) // If this is an enemy we don't want to replace, store it for sprite bank reasons { Enemy existingEnemy = IrreplaceableEnemies.EnemyData.Where(enemy => enemy.Value == enemyIDValue).First(); addedEnemiesToXPos.Add(new KeyValuePair <Enemy, byte>(existingEnemy, 0)); } }); currentScreen = screenValue; // Advance to next screen address--; // Reset back one address so we can re-process this enemy addressesToShuffle.Clear(); } else { addressesToShuffle.Add(address); enemyIndex++; } } }