Ejemplo n.º 1
0
        /// <summary>
        /// Do 3 or 4 damage for high-ammo weapons, and ammo-damage + 1 for the others
        /// Time Stopper will always do 1 damage.
        /// </summary>
        /// <param name="weapon"></param>
        /// <returns></returns>
        private static byte GetRoboDamagePrimary(Random r, EDmgVsBoss weapon)
        {
            // Flat 25% chance to do 2 extra damage
            byte   damage    = 0;
            double rExtraDmg = r.NextDouble();

            if (rExtraDmg > 0.75)
            {
                damage = 2;
            }

            if (weapon == EDmgVsBoss.U_DamageH)
            {
                damage += (byte)(RWeaponBehavior.AmmoUsage[1] + 1);
            }
            else if (weapon == EDmgVsBoss.U_DamageA)
            {
                damage += (byte)(RWeaponBehavior.AmmoUsage[2] + 1);
            }
            else if (weapon == EDmgVsBoss.U_DamageW)
            {
                damage += (byte)(RWeaponBehavior.AmmoUsage[3] + 1);
            }
            else if (weapon == EDmgVsBoss.U_DamageF)
            {
                return(1);
            }
            else if (weapon == EDmgVsBoss.U_DamageC)
            {
                damage += (byte)(RWeaponBehavior.AmmoUsage[7] + 1);
            }

            // 50% chance to cap the minimum damage at 4, else cap minimum damage at 3
            rExtraDmg = r.NextDouble();
            if (rExtraDmg > 0.5)
            {
                if (damage < 4)
                {
                    damage = 4;
                }
            }
            else
            {
                if (damage < 3)
                {
                    damage = 3;
                }
            }

            return(damage);
        }
Ejemplo n.º 2
0
 private static int GetWeaponIndexFromAddress(EDmgVsBoss weaponAddress)
 {
     if (weaponAddress == EDmgVsBoss.U_DamageP)
     {
         return(0);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageH)
     {
         return(1);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageA)
     {
         return(2);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageW)
     {
         return(3);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageB)
     {
         return(4);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageQ)
     {
         return(5);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageF)
     {
         return(6);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageM)
     {
         return(7);
     }
     else if (weaponAddress == EDmgVsBoss.U_DamageC)
     {
         return(8);
     }
     else
     {
         return(-1);
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// TODO
        /// </summary>
        private void RandomizeWilyUJ(Patch Patch, Random r)
        {
            if (IsChaos)
            {
                // List of special weapon damage tables for enemies
                List <EDmgVsEnemy> dmgPtrEnemies = EDmgVsEnemy.GetTables(false);
                EDmgVsEnemy        enemyWeak1;
                EDmgVsEnemy        enemyWeak2;
                EDmgVsEnemy        enemyWeak3;

                // List of special weapon damage tables for bosses (no flash or buster)
                List <EDmgVsBoss> dmgPtrBosses = EDmgVsBoss.GetTables(false, false);
                EDmgVsBoss        bossWeak1;
                EDmgVsBoss        bossWeak2;
                EDmgVsBoss        bossWeak3;
                EDmgVsBoss        bossWeak4;

                #region Dragon

                // Dragon
                // 25% chance to have a buster vulnerability
                double rBuster   = r.NextDouble();
                byte   busterDmg = 0x00;
                if (rBuster > 0.75)
                {
                    busterDmg = 0x01;
                }
                Patch.Add(EDmgVsBoss.U_DamageP + EDmgVsBoss.Offset.Dragon, busterDmg, "Buster Damage to Dragon");
                WilyWeaknesses[0, 0] = busterDmg;

                // Choose 2 special weapon weaknesses
                List <EDmgVsBoss> dragon = new List <EDmgVsBoss>(dmgPtrBosses);
                int rInt = r.Next(dragon.Count);
                bossWeak1 = dragon[rInt];
                dragon.RemoveAt(rInt);
                rInt      = r.Next(dragon.Count);
                bossWeak2 = dragon[rInt];

                // For each weapon, apply the weaknesses and immunities
                for (int i = 0; i < dmgPtrBosses.Count; i++)
                {
                    EDmgVsBoss weapon = dmgPtrBosses[i];

                    // Dragon weak
                    if (weapon == bossWeak1 || weapon == bossWeak2)
                    {
                        // Deal 1 damage with weapons that cost 1 or less ammo
                        byte damage = 0x01;

                        // Deal damage = ammoUsage - 1, minimum 2 damage
                        if (RWeaponBehavior.AmmoUsage[i + 1] > 1)
                        {
                            int tryDamage = (int)RWeaponBehavior.AmmoUsage[i + 1] - 0x01;
                            damage = (tryDamage < 2) ? (byte)0x02 : (byte)tryDamage;
                        }
                        Patch.Add(weapon + EDmgVsBoss.Offset.Dragon, damage, String.Format("{0} Damage to Dragon", weapon.WeaponName));
                        WilyWeaknesses[0, i + 1] = damage;
                    }
                    // Dragon immune
                    else
                    {
                        Patch.Add(weapon + EDmgVsBoss.Offset.Dragon, 0x00, String.Format("{0} Damage to Dragon", weapon.WeaponName));
                        WilyWeaknesses[0, i + 1] = 0x00;
                    }
                }

                #endregion

                #region Picopico-kun

                // Picopico-kun
                // 20 HP each
                // 25% chance for buster to deal 3-7 damage
                rBuster   = r.NextDouble();
                busterDmg = 0x00;
                if (rBuster > 0.75)
                {
                    busterDmg = (byte)(r.Next(5) + 3);
                }
                Patch.Add(EDmgVsEnemy.DamageP + EDmgVsEnemy.Offset.PicopicoKun, busterDmg, String.Format("Buster Damage to Picopico-Kun"));
                WilyWeaknesses[1, 0] = busterDmg;

                // Deal ammoUse x 10 for the main weakness
                // Deal ammoUse x 6 for another
                // Deal ammoUse x 3 for another
                List <EDmgVsEnemy> pico = new List <EDmgVsEnemy>(dmgPtrEnemies);
                rInt       = r.Next(pico.Count);
                enemyWeak1 = pico[rInt];
                pico.RemoveAt(rInt);
                rInt       = r.Next(pico.Count);
                enemyWeak2 = pico[rInt];
                pico.RemoveAt(rInt);
                rInt       = r.Next(pico.Count);
                enemyWeak3 = pico[rInt];
                for (int i = 0; i < dmgPtrEnemies.Count; i++)
                {
                    EDmgVsEnemy weapon = dmgPtrEnemies[i];
                    byte        damage = 0x00;
                    char        level  = ' ';

                    if (weapon == enemyWeak1)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 10);
                        if (damage < 2)
                        {
                            damage = 3;
                        }
                        level = '^';
                    }
                    else if (weapon == enemyWeak2)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 6);
                        if (damage < 2)
                        {
                            damage = 2;
                        }
                        level = '*';
                    }
                    else if (weapon == enemyWeak3)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 3);
                        if (damage < 2)
                        {
                            damage = 2;
                        }
                    }

                    // If any weakness is Atomic Fire, deal 20 damage
                    //if (weapon == EDmgVsEnemy.DamageH && (enemyWeak1 == weapon || enemyWeak2 == weapon || enemyWeak3 == weapon))
                    //{
                    //    damage = 20;
                    //}

                    // Bump up already high damage values to 20
                    if (damage >= 14)
                    {
                        damage = 20;
                    }
                    Patch.Add(weapon + EDmgVsEnemy.Offset.PicopicoKun, damage, String.Format("{0} Damage to Picopico-Kun{1}", weapon.WeaponName, level));
                    WilyWeaknesses[1, i + 1]   = damage;
                    WilyWeaknessInfo[1, i + 1] = level;
                }

                #endregion

                #region Guts

                // Guts
                // 25% chance to have a buster vulnerability
                rBuster   = r.NextDouble();
                busterDmg = 0x00;
                if (rBuster > 0.75)
                {
                    busterDmg = 0x01;
                }
                Patch.Add(EDmgVsBoss.U_DamageP + EDmgVsBoss.Offset.Guts, busterDmg, String.Format("Buster Damage to Guts Tank"));
                WilyWeaknesses[2, 0] = busterDmg;

                // Choose 2 special weapon weaknesses
                List <EDmgVsBoss> guts = new List <EDmgVsBoss>(dmgPtrBosses);
                rInt      = r.Next(guts.Count);
                bossWeak1 = guts[rInt];
                guts.RemoveAt(rInt);
                rInt      = r.Next(guts.Count);
                bossWeak2 = guts[rInt];

                for (int i = 0; i < dmgPtrBosses.Count; i++)
                {
                    EDmgVsBoss weapon = dmgPtrBosses[i];

                    // Guts weak
                    if (weapon == bossWeak1 || weapon == bossWeak2)
                    {
                        // Deal 1 damage with weapons that cost 1 or less ammo
                        byte damage = 0x01;

                        // Deal damage = ammoUsage - 1, minimum 2 damage
                        if (RWeaponBehavior.AmmoUsage[i + 1] > 1)
                        {
                            int tryDamage = (int)RWeaponBehavior.AmmoUsage[i + 1] - 0x01;
                            damage = (tryDamage < 2) ? (byte)0x02 : (byte)tryDamage;
                        }
                        Patch.Add(weapon + EDmgVsBoss.Offset.Guts, damage, String.Format("{0} Damage to Guts Tank", weapon.WeaponName));
                        WilyWeaknesses[2, i + 1] = damage;
                    }
                    // Guts immune
                    else
                    {
                        Patch.Add(weapon + EDmgVsBoss.Offset.Guts, 0x00, String.Format("{0} Damage to Guts Tank", weapon.WeaponName));
                        WilyWeaknesses[2, i + 1] = 0x00;
                    }
                }

                #endregion

                #region Buebeam Trap

                // Buebeam
                // 5 Orbs + 3 Required Barriers (5 total barriers, 4 in speedrun route)
                // Choose a weakness for both Barriers and Orbs, scale damage to have plenty of energy
                // If the same weakness for both, scale damage further
                // If any weakness is Atomic Fire, ensure that there's enough ammo

                // Randomize Crash Barrier weakness
                List <EDmgVsEnemy> dmgBarrierList = EDmgVsEnemy.GetTables(true);

                // Remove Heat as possibility if it costs too much ammo
                if (RWeaponBehavior.AmmoUsage[1] > 5)
                {
                    dmgBarrierList.RemoveAt(1);
                    WilyWeaknesses[3, 1] = 0;
                }

                // Get Barrier weakness
                int         rBarrierWeakness = r.Next(dmgBarrierList.Count);
                EDmgVsEnemy wpnBarrier       = dmgBarrierList[rBarrierWeakness];

                // Scale damage to be slightly more capable than killing 5 barriers at full ammo
                int dmgW4 = 0x01;
                if (wpnBarrier != EDmgVsEnemy.DamageP)
                {
                    int totalShots        = (int)(28 / RWeaponBehavior.GetAmmoUsage(wpnBarrier));
                    int numHitsPerBarrier = (int)(totalShots / 5);
                    if (numHitsPerBarrier > 1)
                    {
                        numHitsPerBarrier--;
                    }
                    if (numHitsPerBarrier > 8)
                    {
                        numHitsPerBarrier = 8;
                    }
                    dmgW4 = (int)Math.Ceiling(20d / numHitsPerBarrier);
                }
                for (int i = 0; i < dmgBarrierList.Count; i++)
                {
                    // Deal damage with weakness, and 0 for everything else
                    byte        damage = (byte)dmgW4;
                    EDmgVsEnemy wpn    = dmgBarrierList[i];
                    if (wpn != wpnBarrier)
                    {
                        damage = 0;
                    }
                    Patch.Add(wpn.Address + EDmgVsEnemy.Offset.ClashBarrier_W4, damage, String.Format("{0} Damage to Clash Barrier 1", wpn.WeaponName));
                    Patch.Add(wpn.Address + EDmgVsEnemy.Offset.ClashBarrier_Other, damage, String.Format("{0} Damage to Clash Barrier 2", wpn.WeaponName));
                }

                // Remove Barrier weakness from list first (therefore, different Buebeam weakness)
                dmgBarrierList.RemoveAt(rBarrierWeakness);

                // Get Buebeam weakness
                rInt = r.Next(dmgBarrierList.Count);
                EDmgVsEnemy wpnBuebeam = dmgBarrierList[rInt];

                // Add Barrier weakness back to list for counting later
                dmgBarrierList.Insert(rBarrierWeakness, wpnBarrier);

                // Scale damage to be slightly more capable than killing 5 buebeams at full ammo
                dmgW4 = 0x01;
                if (wpnBuebeam != EDmgVsEnemy.DamageP)
                {
                    int totalShots        = (int)(28 / RWeaponBehavior.GetAmmoUsage(wpnBuebeam));
                    int numHitsPerBuebeam = (int)(totalShots / 5);
                    if (numHitsPerBuebeam > 1)
                    {
                        numHitsPerBuebeam--;
                    }
                    if (numHitsPerBuebeam > 8)
                    {
                        numHitsPerBuebeam = 8;
                    }
                    dmgW4 = (int)Math.Ceiling(20d / numHitsPerBuebeam);
                }

                // Add Buebeam damage values to patch, as well as array for use by Text and other modules later
                for (int i = 0; i < dmgBarrierList.Count; i++)
                {
                    byte        damage = (byte)dmgW4;
                    EDmgVsEnemy wpn    = dmgBarrierList[i];
                    if (wpn != wpnBuebeam)
                    {
                        damage = 0;
                    }
                    Patch.Add(wpn.Address + EDmgVsEnemy.Offset.Buebeam, damage, String.Format("{0} Damage to Buebeam Trap", wpnBuebeam.WeaponName));

                    // Add to damage table (skipping heat if necessary)
                    if (RWeaponBehavior.AmmoUsage[1] > 5 && i >= 1)
                    {
                        WilyWeaknesses[3, i + 1] = damage;
                    }
                    else
                    {
                        WilyWeaknesses[3, i] = damage;
                    }
                }

                #endregion

                #region Wily Machine

                // Machine
                // Will have 4 weaknesses and potentially a Buster weakness
                // Phase 1 will disable 2 of the weaknesses, taking no damage
                // Phase 2 will re-enable them, but disable 1 other weakness
                // Mega Man 2 behaves in a similar fashion, disabling Q and A in phase 1, but only disabling H in phase 2

                // 75% chance to have a buster vulnerability
                rBuster   = r.NextDouble();
                busterDmg = 0x00;
                if (rBuster > 0.25)
                {
                    busterDmg = 0x01;
                }
                Patch.Add(EDmgVsBoss.U_DamageP + EDmgVsBoss.Offset.Machine, busterDmg, String.Format("Buster Damage to Wily Machine"));
                WilyWeaknesses[4, 0] = busterDmg;

                // Choose 4 special weapon weaknesses
                List <EDmgVsBoss> machine = new List <EDmgVsBoss>(dmgPtrBosses);
                rInt      = r.Next(machine.Count);
                bossWeak1 = machine[rInt];
                machine.RemoveAt(rInt);
                rInt      = r.Next(machine.Count);
                bossWeak2 = machine[rInt];
                machine.RemoveAt(rInt);
                rInt      = r.Next(machine.Count);
                bossWeak3 = machine[rInt];
                machine.RemoveAt(rInt);
                rInt      = r.Next(machine.Count);
                bossWeak4 = machine[rInt];

                for (int i = 0; i < dmgPtrBosses.Count; i++)
                {
                    EDmgVsBoss weapon = dmgPtrBosses[i];

                    // Machine weak
                    if (weapon == bossWeak1 || weapon == bossWeak2 || weapon == bossWeak3 || weapon == bossWeak4)
                    {
                        // Deal 1 damage with weapons that cost 1 or less ammo
                        byte damage = 0x01;

                        // Deal damage = ammoUsage
                        if (RWeaponBehavior.AmmoUsage[i + 1] > 1)
                        {
                            damage = (byte)RWeaponBehavior.AmmoUsage[i + 1];
                        }
                        Patch.Add(weapon + EDmgVsBoss.Offset.Machine, damage, String.Format("{0} Damage to Wily Machine", weapon.WeaponName));
                        WilyWeaknesses[4, i + 1] = damage;
                    }
                    // Machine immune
                    else
                    {
                        Patch.Add(weapon + EDmgVsBoss.Offset.Machine, 0x00, String.Format("{0} Damage to Wily Machine", weapon.WeaponName));
                        WilyWeaknesses[4, i + 1] = 0x00;
                    }

                    // Get index of this weapon out of all weapons 0-8;
                    byte wIndex = (byte)(i + 1);
                    if (weapon == EDmgVsBoss.ClashBomber || weapon == EDmgVsBoss.MetalBlade)
                    {
                        wIndex++;
                    }

                    // Disable weakness 1 and 2 on Wily Machine Phase 1
                    if (weapon == bossWeak1)
                    {
                        Patch.Add(0x02DA2E, wIndex, String.Format("Wily Machine Phase 1 Resistance 1 ({0})", weapon.WeaponName));
                    }
                    if (weapon == bossWeak2)
                    {
                        Patch.Add(0x02DA32, wIndex, String.Format("Wily Machine Phase 1 Resistance 2 ({0})", weapon.WeaponName));
                    }
                    // Disable weakness 3 on Wily Machine Phase 2
                    if (weapon == bossWeak3)
                    {
                        Patch.Add(0x02DA3A, wIndex, String.Format("Wily Machine Phase 2 Resistance ({0})", weapon.WeaponName));
                    }
                }

                #endregion

                #region Alien

                // Alien
                // Buster Heat Air Wood Bubble Quick Clash Metal
                byte alienDamage = 1;
                List <EDmgVsBoss> alienWeapons = EDmgVsBoss.GetTables(true, false);
                int rWeaponIndex = r.Next(alienWeapons.Count);

                // Deal two damage for 1-ammo weapons (or buster)
                if (RWeaponBehavior.AmmoUsage[rWeaponIndex] == 1)
                {
                    alienDamage = 2;
                }
                // For 2+ ammo use weapons, deal 20% more than that in damage, rounded up
                else if (RWeaponBehavior.AmmoUsage[rWeaponIndex] > 1)
                {
                    alienDamage = (byte)Math.Ceiling(RWeaponBehavior.AmmoUsage[rWeaponIndex] * 1.2);
                }

                // Apply weakness and erase others (flash will remain 0xFF)
                for (int i = 0; i < alienWeapons.Count; i++)
                {
                    EDmgVsBoss weapon = alienWeapons[i];

                    if (i == rWeaponIndex)
                    {
                        Patch.Add(weapon + EDmgVsBoss.Offset.Alien, alienDamage, String.Format("{0} Damage to Alien", weapon.WeaponName));
                        WilyWeaknesses[5, i] = alienDamage;
                    }
                    else
                    {
                        Patch.Add(weapon + EDmgVsBoss.Offset.Alien, 0xFF, String.Format("{0} Damage to Alien", weapon.WeaponName));
                        WilyWeaknesses[5, i] = 0xFF;
                    }
                }

                #endregion

                debug.AppendLine("Wily Boss Weaknesses:");
                debug.AppendLine("P\tH\tA\tW\tB\tQ\tF\tM\tC:");
                debug.AppendLine("--------------------------------------------");
                for (int i = 0; i < WilyWeaknesses.GetLength(0); i++)
                {
                    for (int j = 0; j < WilyWeaknesses.GetLength(1); j++)
                    {
                        debug.Append(String.Format("{0}\t", WilyWeaknesses[i, j]));
                        if (j == 5)
                        {
                            debug.Append("X\t");         // skip flash
                        }
                    }
                    string bossName = "";
                    switch (i)
                    {
                    case 0:
                        bossName = "dragon";
                        break;

                    case 1:
                        bossName = "picopico-kun";
                        break;

                    case 2:
                        bossName = "guts";
                        break;

                    case 3:
                        bossName = "boobeam";
                        break;

                    case 4:
                        bossName = "machine";
                        break;

                    case 5:
                        bossName = "alien";
                        break;

                    default: break;
                    }
                    debug.AppendLine("< " + bossName);
                }
                debug.Append(Environment.NewLine);
            } // end if

            #region Easy Weakness

            else
            {
                // First address for damage (buster v heatman)
                int address = (RandomMM2.Settings.IsJapanese) ? (int)EDmgVsBoss.Buster : (int)EDmgVsBoss.U_DamageP;

                // Skip Time Stopper
                // Buster Air Wood Bubble Quick Clash Metal
                byte[] dragon  = new byte[] { 1, 0, 0, 0, 1, 0, 1 };
                byte[] guts    = new byte[] { 1, 0, 0, 1, 2, 0, 1 };
                byte[] machine = new byte[] { 1, 1, 0, 0, 1, 1, 4 };
                byte[] alien   = new byte[] { 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff };

                // TODO: Scale damage based on ammo count w/ weapon class instead of this hard-coded table
                // Buster Air Wood Bubble Quick Clash Metal
                //double[] ammoUsed = new double[] { 0, 2, 3, 0.5, 0.25, 4, 0.25 };

                dragon.Shuffle(r);
                guts.Shuffle(r);
                machine.Shuffle(r);
                alien.Shuffle(r);

                int j = 0;
                for (int i = 0; i < 8; i++) // i = Buster plus 7 weapons, Time Stopper damage is located in another table (going to ignore it anyways)
                {
                    //// Skip Atomic Fire
                    //if (i == 1) continue;

                    int posDragon = address + 14 * i + 8;

                    Patch.Add(posDragon, dragon[j], String.Format("Easy Weakness: ? against Dragon"));
                    Patch.Add(posDragon + 2, guts[j], String.Format("Easy Weakness: ? against Guts"));
                    Patch.Add(posDragon + 4, machine[j], String.Format("Easy Weakness: ? against Wily Machine"));

                    // Scale damage against alien if using a high ammo usage weapon
                    if (alien[j] == 1)
                    {
                        if (RWeaponBehavior.AmmoUsage[j] >= 1)
                        {
                            alien[j] = (byte)((double)RWeaponBehavior.AmmoUsage[j] * 1.3);
                        }
                    }
                    Patch.Add(posDragon + 5, alien[j], String.Format("Easy Weakness: ? against Alien"));
                    j++;
                }
            }
            #endregion
        } // End method RandomizeWilyUJ
Ejemplo n.º 4
0
        /// <summary>
        /// Identical to RandomWeaknesses() but using Mega Man 2 (U).nes offsets
        /// </summary>
        private void RandomizeU(Patch Patch, Random r)
        {
            // Chaos Mode Weaknesses
            if (IsChaos)
            {
                List <EDmgVsBoss> bossPrimaryWeaknessAddresses = EDmgVsBoss.GetTables(false, true);
                List <EDmgVsBoss> bossWeaknessShuffled         = new List <EDmgVsBoss>(bossPrimaryWeaknessAddresses);
                bossWeaknessShuffled.Shuffle(r);

                // Preparation: Disable redundant Atomic Fire healing code
                // (Note that 0xFF in any weakness table is sufficient to heal a boss)
                Patch.Add(0x02E66D, 0xFF, "Atomic Fire Boss To Heal");  // Normally "00" to indicate Heatman.

                // Select 2 robots to be weak against Buster
                List <int> busterList = new List <int>(new List <int> {
                    0, 1, 2, 3, 4, 5, 6, 7
                }.Shuffle(r)).GetRange(0, 4);

                // Foreach boss
                for (int i = 0; i < 8; i++)
                {
                    // First, fill in special weapon tables with a 50% chance to block or do 1 damage
                    for (int j = 0; j < bossPrimaryWeaknessAddresses.Count; j++)
                    {
                        double rTestImmune = r.NextDouble();
                        byte   damage      = 0;
                        if (rTestImmune > 0.5)
                        {
                            if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageH)
                            {
                                // ...except for Atomic Fire, which will do some more damage
                                damage = (byte)(RWeaponBehavior.AmmoUsage[1] / 2);
                            }
                            else if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageF)
                            {
                                damage = 0x00;
                            }
                            else
                            {
                                damage = 0x01;
                            }
                        }
                        Patch.Add(bossPrimaryWeaknessAddresses[j] + i, damage, String.Format("{0} Damage to {1}", bossPrimaryWeaknessAddresses[j].WeaponName, (EDmgVsBoss.Offset)i));
                        BotWeaknesses[i, j + 1] = damage;
                    }

                    // Write the primary weakness for this boss
                    byte dmgPrimary = GetRoboDamagePrimary(r, bossWeaknessShuffled[i]);
                    Patch.Add(bossWeaknessShuffled[i] + i, dmgPrimary, String.Format("{0} Damage to {1} (Primary)", bossWeaknessShuffled[i].WeaponName, (EDmgVsBoss.Offset)i));

                    // Write the secondary weakness for this boss (next element in list)
                    // Secondary weakness will either do 2 damage or 4 if it is Atomic Fire
                    // Time Stopper cannot be a secondary weakness. Instead it will heal that boss.
                    // As a result, one Robot Master will not have a secondary weakness
                    int        i2           = (i + 1 >= 8) ? 0 : i + 1;
                    EDmgVsBoss weakWeap2    = bossWeaknessShuffled[i2];
                    byte       dmgSecondary = 0x02;
                    if (weakWeap2 == EDmgVsBoss.U_DamageH)
                    {
                        dmgSecondary = 0x04;
                    }
                    else if (weakWeap2 == EDmgVsBoss.U_DamageF)
                    {
                        dmgSecondary = 0x00;

                        // Address in Time-Stopper code that normally heals Flashman, change to heal this boss instead
                        Patch.Add(0x02C08F, (byte)i, String.Format("Time-Stopper Heals {0} (Special Code)", (EDmgVsBoss.Offset)i));
                    }
                    Patch.Add(weakWeap2 + i, dmgSecondary, String.Format("{0} Damage to {1} (Secondary)", weakWeap2.WeaponName, (EDmgVsBoss.Offset)i));

                    // Add buster damage
                    if (busterList.Contains(i))
                    {
                        Patch.Add(EDmgVsBoss.U_DamageP + i, 0x02, String.Format("Buster Damage to {0}", (EDmgVsBoss.Offset)i));
                        BotWeaknesses[i, 0] = 0x02;
                    }
                    else
                    {
                        Patch.Add(EDmgVsBoss.U_DamageP + i, 0x01, String.Format("Buster Damage to {0}", (EDmgVsBoss.Offset)i));
                        BotWeaknesses[i, 0] = 0x01;
                    }

                    // Save info
                    int weapIndexPrimary = GetWeaponIndexFromAddress(bossWeaknessShuffled[i]);
                    BotWeaknesses[i, weapIndexPrimary] = dmgPrimary;
                    int weapIndexSecondary = GetWeaponIndexFromAddress(weakWeap2);
                    BotWeaknesses[i, weapIndexSecondary] = dmgSecondary;
                }

                debug.AppendLine("Robot Master Weaknesses:");
                debug.AppendLine("P\tH\tA\tW\tB\tQ\tF\tM\tC:");
                debug.AppendLine("--------------------------------------------");
                for (int i = 0; i < 8; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        debug.Append(String.Format("{0}\t", BotWeaknesses[i, j]));
                    }
                    debug.AppendLine("< " + ((EDmgVsBoss.Offset)i).ToString());
                }
                debug.Append(Environment.NewLine);
            }

            // Easy Mode Weaknesses
            else
            {
                List <WeaponTable> Weapons = new List <WeaponTable>();

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Buster",
                    ID           = 0,
                    Address      = EDmgVsBoss.U_DamageP,
                    RobotMasters = new int[8] {
                        2, 2, 1, 1, 2, 2, 1, 1
                    }
                    // Heat = 2,
                    // Air = 2,
                    // Wood = 1,
                    // Bubble = 1,
                    // Quick = 2,
                    // Flash = 2,
                    // Metal = 1,
                    // Clash = 1,
                    // Dragon = 1
                    // Byte Unused = 0
                    // Gutsdozer = 1
                    // Unused = 0
                });

                Weapons.Add(new WeaponTable()
                {
                    Name    = "Atomic Fire",
                    ID      = 1,
                    Address = EDmgVsBoss.U_DamageH,
                    // Note: These values only affect a fully charged shot.  Partially charged shots use the Buster table.
                    RobotMasters = new int[8] {
                        0xFF, 6, 0x0E, 0, 0x0A, 6, 4, 6
                    }
                    // Dragon = 8
                    // Gutsdozer = 8
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Air Shooter",
                    ID           = 2,
                    Address      = EDmgVsBoss.U_DamageA,
                    RobotMasters = new int[8] {
                        2, 0, 4, 0, 2, 0, 0, 0x0A
                    }
                    // Dragon = 0
                    // Gutsdozer = 0
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Leaf Shield",
                    ID           = 3,
                    Address      = EDmgVsBoss.U_DamageW,
                    RobotMasters = new int[8] {
                        0, 8, 0xFF, 0, 0, 0, 0, 0
                    }
                    // Dragon = 0
                    // Unused = 0
                    // Gutsdozer = 0
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Bubble Lead",
                    ID           = 4,
                    Address      = EDmgVsBoss.U_DamageB,
                    RobotMasters = new int[8] {
                        6, 0, 0, 0xFF, 0, 2, 0, 1
                    }
                    // Dragon = 0
                    // Unused = 0
                    // Gutsdozer = 1
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Quick Boomerang",
                    ID           = 5,
                    Address      = EDmgVsBoss.U_DamageQ,
                    RobotMasters = new int[8] {
                        2, 2, 0, 2, 0, 0, 4, 1
                    }
                    // Dragon = 1
                    // Unused = 0
                    // Gutsdozer = 2
                });

                Weapons.Add(new WeaponTable()
                {
                    Name    = "Time Stopper",
                    ID      = 6,
                    Address = EDmgVsBoss.U_DamageF,
                    // NOTE: These values affect damage per tick
                    // NOTE: This table only has robot masters, no wily bosses
                    RobotMasters = new int[8] {
                        0, 0, 0, 0, 1, 0, 0, 0
                    }
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Metal Blade",
                    ID           = 7,
                    Address      = EDmgVsBoss.U_DamageM,
                    RobotMasters = new int[8] {
                        1, 0, 2, 4, 0, 4, 0x0E, 0
                    }
                    // Dragon = 0
                    // Unused = 0
                    // Gutsdozer = 0
                });

                Weapons.Add(new WeaponTable()
                {
                    Name         = "Clash Bomber",
                    ID           = 8,
                    Address      = EDmgVsBoss.U_DamageC,
                    RobotMasters = new int[8] {
                        0xFF, 0, 2, 2, 4, 3, 0, 0
                    }
                    // Dragon = 1
                    // Unused = 0
                    // Gutsdozer = 1
                });

                foreach (WeaponTable weapon in Weapons)
                {
                    weapon.RobotMasters.Shuffle(r);
                }

                foreach (WeaponTable weapon in Weapons)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        Patch.Add(weapon.Address + i, (byte)weapon.RobotMasters[i], String.Format("Easy Weakness: {0} against {1}", weapon.Name, ((EDmgVsBoss.Offset)i).ToString()));
                    }
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Identical to RandomWeaknesses() but using Mega Man 2 (U).nes offsets
        /// </summary>
        private void RandomizeU(Patch Patch, Random r)
        {
            List <EDmgVsBoss> bossPrimaryWeaknessAddresses = EDmgVsBoss.GetTables(false, true);
            List <EDmgVsBoss> bossWeaknessShuffled         = new List <EDmgVsBoss>(bossPrimaryWeaknessAddresses);

            bossWeaknessShuffled.Shuffle(r);

            // Preparation: Disable redundant Atomic Fire healing code
            // (Note that 0xFF in any weakness table is sufficient to heal a boss)
            Patch.Add(0x02E66D, 0xFF, "Atomic Fire Boss To Heal");  // Normally "00" to indicate Heatman.

            // Select 2 robots to be weak against Buster
            List <int> busterList = new List <int>(new List <int> {
                0, 1, 2, 3, 4, 5, 6, 7
            }.Shuffle(r)).GetRange(0, 4);

            // Foreach boss
            for (int i = 0; i < 8; i++)
            {
                // First, fill in special weapon tables with a 50% chance to block or do 1 damage
                for (int j = 0; j < bossPrimaryWeaknessAddresses.Count; j++)
                {
                    double rTestImmune = r.NextDouble();
                    byte   damage      = 0;
                    if (rTestImmune > 0.5)
                    {
                        if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageH)
                        {
                            // ...except for Atomic Fire, which will do some more damage
                            damage = (byte)(RWeaponBehavior.AmmoUsage[1] / 2);
                        }
                        else if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageF)
                        {
                            damage = 0x00;
                        }
                        else
                        {
                            damage = 0x01;
                        }
                    }
                    Patch.Add(bossPrimaryWeaknessAddresses[j] + i, damage, String.Format("{0} Damage to {1}", bossPrimaryWeaknessAddresses[j].WeaponName, (EDmgVsBoss.Offset)i));
                    BotWeaknesses[i, j + 1] = damage;
                }

                // Write the primary weakness for this boss
                byte dmgPrimary = GetRoboDamagePrimary(r, bossWeaknessShuffled[i]);
                Patch.Add(bossWeaknessShuffled[i] + i, dmgPrimary, String.Format("{0} Damage to {1} (Primary)", bossWeaknessShuffled[i].WeaponName, (EDmgVsBoss.Offset)i));

                // Write the secondary weakness for this boss (next element in list)
                // Secondary weakness will either do 2 damage or 4 if it is Atomic Fire
                // Time Stopper cannot be a secondary weakness. Instead it will heal that boss.
                // As a result, one Robot Master will not have a secondary weakness
                int        i2           = (i + 1 >= 8) ? 0 : i + 1;
                EDmgVsBoss weakWeap2    = bossWeaknessShuffled[i2];
                byte       dmgSecondary = 0x02;
                if (weakWeap2 == EDmgVsBoss.U_DamageH)
                {
                    dmgSecondary = 0x04;
                }
                else if (weakWeap2 == EDmgVsBoss.U_DamageF)
                {
                    dmgSecondary = 0x00;

                    // Address in Time-Stopper code that normally heals Flashman, change to heal this boss instead
                    Patch.Add(0x02C08F, (byte)i, String.Format("Time-Stopper Heals {0} (Special Code)", (EDmgVsBoss.Offset)i));
                }
                Patch.Add(weakWeap2 + i, dmgSecondary, String.Format("{0} Damage to {1} (Secondary)", weakWeap2.WeaponName, (EDmgVsBoss.Offset)i));

                // Add buster damage
                if (busterList.Contains(i))
                {
                    Patch.Add(EDmgVsBoss.U_DamageP + i, 0x02, String.Format("Buster Damage to {0}", (EDmgVsBoss.Offset)i));
                    BotWeaknesses[i, 0] = 0x02;
                }
                else
                {
                    Patch.Add(EDmgVsBoss.U_DamageP + i, 0x01, String.Format("Buster Damage to {0}", (EDmgVsBoss.Offset)i));
                    BotWeaknesses[i, 0] = 0x01;
                }

                // Save info
                int weapIndexPrimary = GetWeaponIndexFromAddress(bossWeaknessShuffled[i]);
                BotWeaknesses[i, weapIndexPrimary] = dmgPrimary;
                int weapIndexSecondary = GetWeaponIndexFromAddress(weakWeap2);
                BotWeaknesses[i, weapIndexSecondary] = dmgSecondary;
            }

            debug.AppendLine("Robot Master Weaknesses:");
            debug.AppendLine("P\tH\tA\tW\tB\tQ\tF\tM\tC:");
            debug.AppendLine("--------------------------------------------");
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    debug.Append(String.Format("{0}\t", BotWeaknesses[i, j]));
                }
                debug.AppendLine("< " + ((EDmgVsBoss.Offset)i).ToString());
            }
            debug.Append(Environment.NewLine);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Identical to RandomWeaknesses() but using Mega Man 2 (U).nes offsets
        /// </summary>
        private void RandomizeU(Patch Patch, Random r)
        {
            List <EDmgVsBoss> bossPrimaryWeaknessAddresses = EDmgVsBoss.GetTables(false, true);
            List <EDmgVsBoss> bossWeaknessShuffled         = new List <EDmgVsBoss>(bossPrimaryWeaknessAddresses);

            bossWeaknessShuffled.Shuffle(r);

            // Preparation: Disable redundant Atomic Fire healing code
            // (Note that 0xFF in any weakness table is sufficient to heal a boss)
            Patch.Add(0x02E66D, 0xFF, "Atomic Fire Boss To Heal");  // Normally "00" to indicate Heatman.

            // Select 4 robots to be weak against Buster
            List <int> busterList = new List <int>(new List <int> {
                0, 1, 2, 3, 4, 5, 6, 7
            }.Shuffle(r)).GetRange(0, 4);

            // Select 2 robots to be very weak to some weapon
            List <int> veryWeakBots = new List <int>(new List <int> {
                0, 1, 2, 3, 4, 5, 6, 7
            }.Shuffle(r)).GetRange(0, 2);
            int bossWithGreatWeakness    = veryWeakBots[0];
            int bossWithUltimateWeakness = veryWeakBots[1];
            // Select 2 weapons to deal great damage to the 2 bosses above (exclude buster, flash)
            List <int> greatWeaknessWeapons = new List <int>(new List <int> {
                0, 1, 2, 3, 4, 5, 6,
            }.Shuffle(r)).GetRange(0, 2);
            int weaponGreatWeakness    = greatWeaknessWeapons[0];
            int weaponUltimateWeakness = greatWeaknessWeapons[1];


            // Foreach boss
            for (int i = 0; i < 8; i++)
            {
                // First, fill in special weapon tables with a 50% chance to block or do 1 damage
                for (int j = 0; j < bossPrimaryWeaknessAddresses.Count; j++)
                {
                    double rTestImmune = r.NextDouble();
                    byte   damage      = 0;
                    if (rTestImmune > 0.5)
                    {
                        if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageH)
                        {
                            // ...except for Atomic Fire, which will do some more damage
                            damage = (byte)(RWeaponBehavior.AmmoUsage[1] / 2);
                        }
                        else if (bossPrimaryWeaknessAddresses[j] == EDmgVsBoss.U_DamageF)
                        {
                            damage = 0x00;
                        }
                        else
                        {
                            damage = 0x01;
                        }
                    }
                    Patch.Add(bossPrimaryWeaknessAddresses[j] + i, damage, String.Format("{0} Damage to {1}", bossPrimaryWeaknessAddresses[j].WeaponName, (EDmgVsBoss.Offset)i));
                    BotWeaknesses[i, j + 1] = damage;
                }

                // Write the primary weakness for this boss
                byte dmgPrimary = GetRoboDamagePrimary(r, bossWeaknessShuffled[i]);
                Patch.Add(bossWeaknessShuffled[i] + i, dmgPrimary, $"{bossWeaknessShuffled[i].WeaponName} Damage to {(EDmgVsBoss.Offset)i} (Primary)");

                // Write the secondary weakness for this boss (next element in list)
                // Secondary weakness will either do 2 damage or 4 if it is Atomic Fire
                // Time Stopper cannot be a secondary weakness. Instead it will heal that boss.
                // As a result, one Robot Master will not have a secondary weakness
                int        i2           = (i + 1 >= 8) ? 0 : i + 1;
                EDmgVsBoss weakWeap2    = bossWeaknessShuffled[i2];
                byte       dmgSecondary = 0x02;
                if (weakWeap2 == EDmgVsBoss.U_DamageH)
                {
                    dmgSecondary = 0x04;
                }
                else if (weakWeap2 == EDmgVsBoss.U_DamageF)
                {
                    dmgSecondary = 0x00;

                    // Address in Time-Stopper code that normally heals Flashman, change to heal this boss instead
                    Patch.Add(0x02C08F, (byte)i, $"Time-Stopper Heals {(EDmgVsBoss.Offset)i} (Special Code)");
                }
                Patch.Add(weakWeap2 + i, dmgSecondary, $"{weakWeap2.WeaponName} Damage to {(EDmgVsBoss.Offset)i} (Secondary)");

                // Add buster damage
                if (busterList.Contains(i))
                {
                    Patch.Add(EDmgVsBoss.U_DamageP + i, 0x02, $"Buster Damage to {(EDmgVsBoss.Offset)i}");
                    BotWeaknesses[i, 0] = 0x02;
                }
                else
                {
                    Patch.Add(EDmgVsBoss.U_DamageP + i, 0x01, $"Buster Damage to {(EDmgVsBoss.Offset)i}");
                    BotWeaknesses[i, 0] = 0x01;
                }

                // Save info
                int weapIndexPrimary = GetWeaponIndexFromAddress(bossWeaknessShuffled[i]);
                BotWeaknesses[i, weapIndexPrimary] = dmgPrimary;
                int weapIndexSecondary = GetWeaponIndexFromAddress(weakWeap2);
                BotWeaknesses[i, weapIndexSecondary] = dmgSecondary;

                // Independently, apply a great weakness and an ultimate weakness (potentially overriding a previous weakness)
                if (bossWithGreatWeakness == i)
                {
                    // Great weakness. Can't be Buster or Flash. Deal 7 damage.
                    EDmgVsBoss wpn = EDmgVsBoss.GetTables(false, false)[weaponGreatWeakness];
                    Patch.Add(wpn.Address + i, 0x07, $"{wpn.WeaponName} Damage to {(EDmgVsBoss.Offset)i} (Great)");
                    BotWeaknesses[i, wpn.Index] = 0x07;
                }
                else if (bossWithUltimateWeakness == i)
                {
                    // Ultimate weakness. Can't be Buster or Flash. Deal 10 damage.
                    EDmgVsBoss wpn = EDmgVsBoss.GetTables(false, false)[weaponUltimateWeakness];
                    Patch.Add(wpn.Address + i, 0x0A, $"{wpn.WeaponName} Damage to {(EDmgVsBoss.Offset)i} (Ultimate)");
                    BotWeaknesses[i, wpn.Index] = 0x0A;
                }
            }

            // TODO: Fix this debug output, it's incorrect. It corresponds to the stages, not bosses. Needs
            // to be permuted based on random bosses in boss room.
            debug.AppendLine("Robot Master Weaknesses:");
            debug.AppendLine("P\tH\tA\tW\tB\tQ\tF\tM\tC:");
            debug.AppendLine("--------------------------------------------");
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    debug.Append(String.Format("{0}\t", BotWeaknesses[i, j]));
                }
                debug.AppendLine("< " + ((EDmgVsBoss.Offset)i).ToString());
            }
            debug.Append(Environment.NewLine);
        }