Exemple #1
0
 public static double GetAmmoUsage(EDmgVsEnemy weapon)
 {
     if (weapon == EDmgVsEnemy.DamageP)
     {
         return(AmmoUsage[0]);
     }
     else if (weapon == EDmgVsEnemy.DamageH)
     {
         return(AmmoUsage[1]);
     }
     else if (weapon == EDmgVsEnemy.DamageA)
     {
         return(AmmoUsage[2]);
     }
     else if (weapon == EDmgVsEnemy.DamageW)
     {
         return(AmmoUsage[3]);
     }
     else if (weapon == EDmgVsEnemy.DamageB)
     {
         return(AmmoUsage[4]);
     }
     else if (weapon == EDmgVsEnemy.DamageQ)
     {
         return(AmmoUsage[5]);
     }
     else if (weapon == EDmgVsEnemy.DamageM)
     {
         return(AmmoUsage[6]);
     }
     else if (weapon == EDmgVsEnemy.DamageC)
     {
         return(AmmoUsage[7]);
     }
     else
     {
         return(0);
     }
 }
Exemple #2
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