예제 #1
0
        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");
            }
        }
예제 #2
0
        public void RandomizeRom(Config config, string path)
        {
            InitRNG();

            RomPatcher patcher = new RomPatcher(path);

            randomizers = new List <IRandomizationStrategy>();
            if (config.RandomizeEnemies)
            {
                randomizers.Add(new NormalEnemyRandomizer());
            }

            if (config.RandomizeWeaponRewards)
            {
                randomizers.Add(new WeaponGetRandomizer());
            }

            if (config.RandomizeVulnerability)
            {
                randomizers.Add(new WeaknessRandomizer());
            }

            if (config.RandomizeBosses)
            {
                randomizers.Add(new BossRandomizer());
            }

            RunRandomizers(patcher, config);

            patcher.ApplyRomPatch();
        }
 public void Randomize(Random random, RomPatcher patcher, Config config)
 {
     InitializeSpecialStageScreens();
     Levels.LevelData.ForEach(level => {
         ReplaceEnemiesRandomly(level, random, patcher);
     });
 }
예제 #4
0
        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 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);
        }
예제 #6
0
 /// <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);
         });
     });
 }
예제 #7
0
        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);
                });
            });
        }
예제 #8
0
        public void Randomize(Random random, RomPatcher patcher, Config config)
        {
            List <GameObject> bosses = new List <GameObject>(BossObjects.ObjectData);

            if (config.ChaosMode)
            {
                DoChaosBossRandomization(bosses, random, patcher);
            }
            else
            {
                DoRegularBossRandomization(bosses, random, patcher);
            }
        }
예제 #9
0
        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);
        }
예제 #10
0
        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");
        }
예제 #11
0
        void ReplaceWeaponsRandomly(Random random, RomPatcher patcher)
        {
            // First select the ROCKMANV weapon
            letterRewardWeapon = remainingWeapons[random.Next(remainingWeapons.Count)];
            remainingWeapons.Remove(letterRewardWeapon);

            // Select weapons for each stage
            List <Level>  remainingRegularStages = new List <Level>(Levels.LevelData.Where(level => !level.Name.Contains("Wily") && !level.Name.Contains("Protoman")));
            List <Weapon> eightWeaponsToSprinkle = remainingWeapons.OrderBy(x => random.Next()).Take(8).ToList();

            eightWeaponsToSprinkle.ForEach(weapon => {
                Level stageToInsert = remainingRegularStages[random.Next(remainingRegularStages.Count)];
                weaponRewards.Add(stageToInsert, new List <Weapon>()
                {
                    weapon
                });
                remainingWeapons.Remove(weapon);
                remainingRegularStages.Remove(stageToInsert);
            });

            // Pick two stages for a bonus weapon
            remainingRegularStages = new List <Level>(Levels.LevelData.Where(level => !level.Name.Contains("Wily") && !level.Name.Contains("Protoman")));
            remainingWeapons.ForEach(weapon => {
                Level stageToInsert = remainingRegularStages[random.Next(remainingRegularStages.Count)];
                weaponRewards[stageToInsert].Add(weapon);
                remainingRegularStages.Remove(stageToInsert);
            });
            remainingWeapons.Clear();

            foreach (var kvp in weaponRewards)
            {
                string weapons = "";
                kvp.Value.ForEach(weapon => weapons += ", " + weapon.Name);
                Console.WriteLine("Stage: " + kvp.Key.Name + " got weapons: " + weapons);
            }

            WriteRockmanVRewardWeapon(letterRewardWeapon, patcher);
            WriteBossRewards(patcher);
        }
예제 #12
0
 void RunRandomizers(RomPatcher patcher, Config config)
 {
     randomizers.ForEach(randomizer => {
         randomizer.Randomize(RNG, patcher, config);
     });
 }
예제 #13
0
 public void Randomize(Random random, RomPatcher patcher, Config config)
 {
     ReplaceWeaponsRandomly(random, patcher);
 }
        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++;
                }
            }
        }