public void Randomize(Random random, RomPatcher patcher, Config config) { List <GameObject> bossObjects = new List <GameObject>(RobotMasterObjects.ObjectData); List <Level> bossLevels = new List <Level>(Levels.LevelData.GetRange(0, 8)); Dictionary <Level, GameObject> bossSlots = new Dictionary <Level, GameObject>(); bossObjects.ForEach(bossObject => { Level levelToOccupy = bossLevels[random.Next(bossLevels.Count - 1)]; bossSlots.Add(levelToOccupy, bossObject); bossLevels.Remove(levelToOccupy); }); bossSlots.Keys.ToList().ForEach(bossLevel => { Console.Out.WriteLine("Replacing boss of " + bossLevel.Name + " with " + bossSlots[bossLevel].Name); patcher.AddRomModification(bossLevel.BossAILoaderIndex, (byte)bossSlots[bossLevel].ObjectId, bossSlots[bossLevel].Name); UpdateBossSprite(bossLevel, bossSlots[bossLevel], patcher); UpdateTauntFrames(bossLevel, bossSlots[bossLevel], patcher); UpdateAnimationReference(bossLevel, bossSlots[bossLevel], patcher); }); // Remove Gravity Man's Gimmick if necessary if (bossSlots[bossSlots.Keys.Where(slot => slot.Name == "Gravity Man Stage").First()].ObjectId != 0x81) { patcher.AddRomModification(GRAVITY_MAN_GIMMICK, 0xA9, "Removing Gravity Man boss door gimmick"); patcher.AddRomModification(GRAVITY_MAN_SWITCHER, 0xBF, "Removing Gravity Man switcher"); } }
void WriteRockmanVRewardWeapon(Weapon weapon, RomPatcher patcher) { // Patch the actual reward byte valueToWrite = InMemoryWeapon.WeaponData.Where(inMemWeapon => inMemWeapon.Name == weapon.Name).First().Value; patcher.AddRomModification(ROCKMANV_WEAPON_REWARD_ADDRESS, valueToWrite, weapon.Name); patcher.AddRomModification(ROCKMANV_MENU_DISPLAY_LETTERS_ADDRESS, valueToWrite, weapon.Name); Console.Out.WriteLine("Wrote weapon to ROCKMANV reward: " + weapon.Name); }
void DoRegularBossRandomization(List <GameObject> bosses, Random random, RomPatcher patcher) { List <VulnerabilityTable> usableWeapons = new List <VulnerabilityTable>(VulnerabilityTables.EnemyData); usableWeapons.RemoveAll(vulnerability => vulnerability.Name == "Rush Coil" || vulnerability.Name == "Rush Jet"); // On regular mode, lets be nice // Pick unique weaknesses for each robot master List <GameObject> mastersWithoutWeakness = new List <GameObject>(RobotMasterObjects.ObjectData); List <GameObject> otherBosses = new List <GameObject>(RobotMasterObjects.ObjectData); usableWeapons.ForEach(weapon => { // First pick someone to be weak GameObject weakMaster = null; if (mastersWithoutWeakness.Count > 0) { weakMaster = mastersWithoutWeakness[random.Next(mastersWithoutWeakness.Count)]; int bossOffset = weapon.VulnerabilityTableOffset + weakMaster.ObjectId; patcher.AddRomModification(bossOffset, 0x04, "Vuln for: " + weakMaster.Name + " for weapon type: " + weapon.Name); // Weak bosses take 4 damage //Console.Out.WriteLine("Robot Master: " + weakMaster.Name + " now weak to: " + weapon.Name); mastersWithoutWeakness.Remove(weakMaster); } otherBosses.ForEach(boss => { if (weakMaster == null || boss.Name != weakMaster.Name) { int offset = weapon.VulnerabilityTableOffset + boss.ObjectId; patcher.AddRomModification(offset, (byte)random.Next(0, 2), "Vuln for: " + boss.Name + " for weapon type: " + weapon.Name); // Strong bosses take 0 or 1 damage //Console.Out.WriteLine("Robot Master: " + boss.Name + " now strong to: " + weapon.Name); } }); }); // Randomize Wily Boss Weaknesses usableWeapons.ForEach(weapon => { WilyBosses.ObjectData.ForEach(wilyBoss => { int bossOffset = weapon.VulnerabilityTableOffset + wilyBoss.ObjectId; int randomRoll = random.Next(0, 3); byte vulnAmount = 0x00; if (randomRoll == 1) { vulnAmount = 0x01; } else if (randomRoll == 2) { vulnAmount = 0x04; } patcher.AddRomModification(bossOffset, vulnAmount, "Vuln for: " + wilyBoss.Name + " for weapon type: " + wilyBoss.Name); Console.Out.WriteLine("Wily Boss: " + wilyBoss.Name + " now modified to: " + vulnAmount + " for weapon type: " + weapon.Name); }); }); }
private void UpdateAnimationReference(Level level, GameObject bossObject, RomPatcher patcher) { List <Level> bossLevels = new List <Level>(Levels.LevelData.GetRange(0, 8)); Enemy bossEnemy = RobotMasterEnemies.EnemyData.Where(enemy => enemy.Name == bossObject.Name).First(); int levelIndex = bossLevels.IndexOf(level); patcher.AddRomModification(ANIMATION_MAP + levelIndex, (byte)bossEnemy.TauntFrames); }
void WriteBossRewards(RomPatcher patcher) { int totalOffset = 0; // Need to keep track of how far we've gone weaponRewards.Keys.OrderBy(x => x.WeaponGetIndex); foreach (var kvp in weaponRewards) { Level level = kvp.Key; List <Weapon> rewards = kvp.Value; // Write the offset map for this level int offsetToWriteTo = WEAPON_GET_MAP_BASE + level.WeaponGetIndex; patcher.AddRomModification(offsetToWriteTo, (byte)totalOffset, "Offset write for: " + level.Name); string weaponGetString = String.Empty; if (rewards.Count == 1) { Weapon reward = rewards[0]; weaponGetString = string.Format(WEAPON_GET_SINGLE_FORMAT, reward.Name.ToUpper()); } else { weaponGetString = string.Format(WEAPON_GET_DOUBLE_FORMAT, rewards[0].Name.ToUpper(), rewards[1].Name.ToUpper()); } List <byte> byteEncodedWeaponGetString = TextMapper.StringToHexValues(weaponGetString); int currentLocation = WEAPON_GET_OFFSET_BASE + totalOffset; // First write the "WEAPON GET" text byteEncodedWeaponGetString.ForEach(letter => { patcher.AddRomModification(currentLocation, letter, "Weapon get: " + letter); currentLocation++; totalOffset++; }); // Now write the weapons themselves patcher.AddRomModification(currentLocation, rewards[0].Value, "Weapon get weapon: " + rewards[0].Value); patcher.AddRomModification(currentLocation + 1, rewards.Count == 1 ? (byte)0x00 : rewards[1].Value, "Bonus weapon"); totalOffset += 2; } Console.Write("Foo"); }
/// <summary> /// Literally just makes every boss take random damage from weapons, including rush coil and rush jet. Good luck! /// </summary> /// <param name="bosses"></param> /// <param name="random"></param> /// <param name="patcher"></param> void DoChaosBossRandomization(List <GameObject> bosses, Random random, RomPatcher patcher) { bosses.ForEach(boss => { VulnerabilityTables.EnemyData.ForEach(vulnerability => { int bossOffset = vulnerability.VulnerabilityTableOffset + boss.ObjectId; // Locate the entry in the vulnerability table int vulnerabilityAmount = random.Next(0, 5); // 0 = no damage, 4 = big weakness patcher.AddRomModification(bossOffset, (byte)vulnerabilityAmount, "Vuln for: " + boss.Name + " for weapon type: " + vulnerability.Name); }); }); }
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++; } } }