public void Randomize(Patch patch, Random r)
        {
            // Create list of default teleporter position values
            List <byte[]> coords = new List <byte[]>
            {
                new byte[] { 0x20, 0x3B }, // Teleporter X, Y (top-left)
                new byte[] { 0x20, 0x7B },
                new byte[] { 0x20, 0xBB },
                new byte[] { 0x70, 0xBB },
                new byte[] { 0x90, 0xBB },
                new byte[] { 0xE0, 0x3B },
                new byte[] { 0xE0, 0x7B },
                new byte[] { 0xE0, 0xBB }
            };

            // Randomize them
            coords.Shuffle(r);

            // Write the new x-coordinates
            for (int i = 0; i < coords.Count; i++)
            {
                byte[] location = coords[i];
                patch.Add((int)(EMiscAddresses.WarpXCoordinateStartAddress + i), location[0], String.Format("Teleporter {0} X-Pos", i));
            }

            // Write the new y-coordinates
            for (int i = 0; i < coords.Count; i++)
            {
                byte[] location = coords[i];
                patch.Add((int)(EMiscAddresses.WarpYCoordinateStartAddress + i), location[1], String.Format("Teleporter {0} Y-Pos", i));
            }

            // These values will be copied over to $04b0 (y) and $0470 (x), which will be checked
            // for in real time to determine where Mega will teleport to
        }
Beispiel #2
0
        protected void ChangeMetal(Patch in_Patch, ISeed in_Seed)
        {
            // Unused addresses
            //0x02CC2D - Projectile type
            //0x02CC29 - Metal Blade sound effect 0x20

            // Metalman AI

            //0x02CC3F - Speed of Metal blade 4, do 2 to 9
            in_Patch.Add(0x02CC3F, in_Seed.NextUInt8(2, 10), "Metalman Projectile Velocity Integer");

            //0x02CC1D - Odd change to attack behavior, 0x06, only if different than 6. Give 25% chance.
            if (in_Seed.NextDouble() > 0.75)
            {
                in_Patch.Add(0x02CC1D, 0x05, "Metalman Alternate Attack Behavior");
            }

            //0x02CBB5 - Jump Height 1 0x06, do from 03 - 07 ? higher than 7 bonks ceiling
            //0x02CBB6 - Jump Height 2 0x05
            //0x02CBB7 - Jump Height 3 0x04

            // Shuffle the list of jump heights to get three different heights
            List <Byte> jumpHeight = in_Seed.Shuffle(new Byte[] { 3, 4, 5, 6, 7 }).ToList();

            for (Int32 i = 0; i < 3; i++)
            {
                in_Patch.Add(0x02CBB5 + i, jumpHeight[i], String.Format("Metalman Jump {0} Y-Velocity Integer", i + 1));
            }
        }
Beispiel #3
0
        /// <summary>
        /// This method patches the third and fourth lines in the intro text.
        /// </summary>
        /// <remarks>
        /// Intro Screen Line 3: 0x036EE0 - 0x036EEA (11 chars)
        /// Intro Screen Line 4: 0x036EEE - 0x036F06 (25 chars)
        /// </remarks>
        public static void PatchForUse(Patch in_Patch, ISeed in_Seed)
        {
            const String INTRO_LINE3_PREFIX  = "FOR USE ";
            const Int32  INTRO_LINE3_ADDRESS = 0x036EE0;
            const Int32  INTRO_LINE4_ADDRESS = 0x036EEE;

            CountryNameSet            countryNameSet = Properties.Resources.CountryNameConfig.Deserialize <CountryNameSet>();
            IEnumerable <CountryName> countryNames   = countryNameSet.Where(x => true == x.Enabled);
            CountryName countryName = in_Seed.NextElement(countryNames);

            Int32 line3NextCharacterAddress = in_Patch.Add(
                INTRO_LINE3_ADDRESS,
                INTRO_LINE3_PREFIX.AsIntroString(),
                $"Splash Text: {INTRO_LINE3_PREFIX}");

            in_Patch.Add(
                line3NextCharacterAddress,
                countryName.GetFormattedPrefix(),
                $"Splash Text: {countryName.Prefix}");

            in_Patch.Add(
                INTRO_LINE4_ADDRESS,
                countryName.GetFormattedName(),
                $"Splash Text: {countryName.Name}");
        }
        public void Randomize(Patch in_Patch, ISeed in_Seed)
        {
            // Create list of default teleporter position values
            List <Position> DEFAULT_TELEPORTER_POSITIONS = new List <Position>
            {
                new Position(0x20, 0x3B), // Teleporter X, Y (top-left)
                new Position(0x20, 0x7B),
                new Position(0x20, 0xBB),
                new Position(0x70, 0xBB),
                new Position(0x90, 0xBB),
                new Position(0xE0, 0x3B),
                new Position(0xE0, 0x7B),
                new Position(0xE0, 0xBB),
            };

            IList <Position> newTeleporterPositions = in_Seed.Shuffle(DEFAULT_TELEPORTER_POSITIONS);

            // Write the new x-coordinates
            for (Int32 index = 0; index < newTeleporterPositions.Count; ++index)
            {
                in_Patch.Add(
                    (Int32)(EMiscAddresses.WarpXCoordinateStartAddress + index),
                    newTeleporterPositions[index].X,
                    String.Format("Teleporter {0} X-Pos", index));

                in_Patch.Add(
                    (Int32)(EMiscAddresses.WarpYCoordinateStartAddress + index),
                    newTeleporterPositions[index].Y,
                    String.Format("Teleporter {0} Y-Pos", index));
            }

            // These values will be copied over to $04b0 (y) and $0470 (x), which will be checked
            // for in real time to determine where Mega will teleport to
        }
Beispiel #5
0
 /// <summary>
 /// This method makes some preliminary modifications to the Mega Man 2 ROM to increase the enemy variety
 /// by changing the sprite banks used by certain rooms.
 /// </summary>
 public void ChangeRoomSpriteBankSlots(Patch p)
 {
     p.Add(0x00b444, 0x90, "Custom Sprite Bank: Wood 9th room: slot 3->? (0x90 special slot)");
     p.Add(0x00b445, 0xa2, "Custom Sprite Bank: Wood 10th room: slot 3->? (0xa2 special slot)");
     p.Add(0x00b446, 0x00, "Custom Sprite Bank: Wood 11th room: slot 3->0");
     p.Add(0x01743e, 0x24, "Custom Sprite Bank: Flash 3rd room: slot 0->2");
     p.Add(0x01f43d, 0x48, "Custom Sprite Bank: Clash 2nd room: slot 2->7");
 }
Beispiel #6
0
        public static void DrawTitleScreenChanges(Patch p, int seed, bool isTourney)
        {
            // Draw version number
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(RandomMM2));
            string version = assembly.GetName().Version.ToString();

            for (int i = 0; i < version.Length; i++)
            {
                byte value = TitleChars.GetChar(version[i]).ID;
                p.Add(0x0373C7 + i, value, "Title Screen Version Number");
            }

            // Draw seed
            string seedAlpha = SeedConvert.ConvertBase10To26(seed);

            for (int i = 0; i < seedAlpha.Length; i++)
            {
                char ch        = seedAlpha.ElementAt(i);
                byte charIndex = (byte)(Convert.ToByte(ch) - Convert.ToByte('A'));

                // 'A' starts at C1 in the pattern table
                p.Add(0x037387 + i, (byte)(0xC1 + charIndex), "Title Screen Seed");
            }

            // Draw flags

            // Draw tournament mode
            if (isTourney)
            {
                // 0x037367 = Start of row beneath "seed"
                string flagsAlpha = "TOURNAMENT";
                for (int i = 0; i < flagsAlpha.Length; i++)
                {
                    char ch        = flagsAlpha.ElementAt(i);
                    byte charIndex = (byte)(Convert.ToByte(ch) - Convert.ToByte('A'));

                    p.Add(0x037564 + i, (byte)(0xC1 + charIndex), "Title Screen Tournament Text");
                }

                string flags2Alpha = "MODE";
                for (int i = 0; i < flags2Alpha.Length; i++)
                {
                    char ch        = flags2Alpha.ElementAt(i);
                    byte charIndex = (byte)(Convert.ToByte(ch) - Convert.ToByte('A'));

                    p.Add(0x03756F + i, (byte)(0xC1 + charIndex), "Title Screen Tournament Text");
                }

                // Draw Hash symbols
                // Use $B8-$BF with custom gfx, previously unused tiles after converting from MM2U to RM2
                //p.Add(0x037367, (byte)(0xB0), "Title Screen Flags");
                //p.Add(0x037368, (byte)(0xB1), "Title Screen Flags");
                //p.Add(0x037369, (byte)(0xB2), "Title Screen Flags");
                //p.Add(0x03736A, (byte)(0xB3), "Title Screen Flags");
            }
        }
Beispiel #7
0
        protected void ChangeQuick(Patch in_Patch, ISeed in_Seed)
        {
            // Other addresses with potential:
            //0x02C872 - Projectile type, 0x59

            // Quickman's AI
            //0x02C86E - Number of Boomerangs, 3, do from 1 - 10
            in_Patch.Add(0x02C86E, in_Seed.NextUInt8(1, 11), "Quickman Number of Boomerangs");

            //0x02C882 - Boomerang: delay before arc 37. 0 for no arc, or above like 53. do from 5 to 53.
            in_Patch.Add(0x02C882, in_Seed.NextUInt8(5, 54), "Quickman Boomerang Delay 1");

            //0x02C887 - Boomerang speed when appearing, 4, do from 1 to 7
            in_Patch.Add(0x02C887, in_Seed.NextUInt8(1, 8), "Quickman Boomerang Velocity Integer 1");

            //0x03B726 - Boomerang speed secondary, 4, does this affect anything else?
            in_Patch.Add(0x03B726, in_Seed.NextUInt8(1, 8), "Quickman Boomerang Velocity Integer 2");

            // For all jumps, choose randomly from 2 to 10
            //0x02C8A3 - Middle jump, 7
            in_Patch.Add(0x02C8A3, in_Seed.NextUInt8(2, 11), "Quickman Jump Height 1 Integer");

            //0x02C8A4 - High jump, 8
            in_Patch.Add(0x02C8A4, in_Seed.NextUInt8(2, 11), "Quickman Jump Height 2 Integer");

            //0x02C8A5 - Low jump, 4
            in_Patch.Add(0x02C8A5, in_Seed.NextUInt8(2, 11), "Quickman Jump Height 3 Integer");

            //0x02C8E4 - Running time, 62, do from 24 to 80
            in_Patch.Add(0x02C8E4, in_Seed.NextUInt8(24, 81), "Quickman Running Time");

            //0x02C8DF - Running speed, 2, do from 1 to 5
            in_Patch.Add(0x02C8DF, in_Seed.NextUInt8(1, 6), "Quickman Running Velocity Integer");
        }
        /// <summary>
        /// Shuffle which Robot Master awards which weapon.
        /// </summary>
        public void Randomize(Patch in_Patch, ISeed in_Seed)
        {
            IList <BossRoomRandomComponent> bossRoomComponents = in_Seed.Shuffle(this.Components);

            //DEBUG test a boss in a particular boss room, also comment out the corresponding boss from the Components list above
            //Components.Insert(3, BubbleManComponent);

            // Write in new boss positions
            for (Int32 i = 0; i < 8; i++)
            {
                BossRoomRandomComponent bossroom = bossRoomComponents[i];
                in_Patch.Add(0x02C15E + i, bossroom.IntroValue, $"Boss Intro Value for Boss Room {i}");
                in_Patch.Add(0x02C057 + i, bossroom.AIPtrByte1, $"Boss AI Ptr Byte1 for Boss Room {i}");
                in_Patch.Add(0x02C065 + i, bossroom.AIPtrByte2, $"Boss AI Ptr Byte2 for Boss Room {i}");
                in_Patch.Add(0x02E4E9 + i, bossroom.GfxFix1, $"Boss GFX Fix 1 for Boss Room {i}");
                in_Patch.Add(0x02C166 + i, bossroom.GfxFix1, $"Boss GFX Fix 2 for Boss Room {i}");
                in_Patch.Add(0x02C14E + i, bossroom.YPosFix1, $"Boss Y-Pos Fix1 for Boss Room {i}");
                in_Patch.Add(0x02C156 + i, bossroom.YPosFix2, $"Boss Y-Pos Fix2 for Boss Room {i}");
            }

            // Adjust sprite banks for each boss room
            Int32[] spriteBankBossRoomAddresses =
            {
                0x0034A6, // Heat room
                0x0074A6, // Air room
                0x00B4DC, // Wood room
                0x00F4A6, // Bubble room
                0x0134B8, // Quick room
                0x0174A6, // Flash room
                0x01B494, // Metal room
                0x01F4DC, // Clash room
            };

            for (Int32 i = 0; i < spriteBankBossRoomAddresses.Length; i++)
            {
                for (Int32 j = 0; j < bossRoomComponents[i].SpriteBankSlotRowsBytes.Length; j++)
                {
                    in_Patch.Add(spriteBankBossRoomAddresses[i] + j,
                                 bossRoomComponents[i].SpriteBankSlotRowsBytes[j],
                                 $"Boss Room {i} Sprite Bank Swap {j}");
                }
            }

            // Undo shuffling of damage values for each boss room
            Int32 contactDmgTbl = 0x2E9C2;

            Byte[] originalDmgVals = new Byte[] { 08, 08, 08, 04, 04, 04, 06, 04 };
            Byte[] newDmgVals      = new Byte[8];

            for (Int32 i = 0; i < bossRoomComponents.Count; i++)
            {
                newDmgVals[i] = originalDmgVals[bossRoomComponents[i].OriginalBossIndex];
                in_Patch.Add(contactDmgTbl + i, newDmgVals[i]);
            }


            this.Components = bossRoomComponents;
        }
Beispiel #9
0
        /// <summary>
        /// Heatman AI 0x02C16E - 0x02C1FE
        /// </summary>
        protected void ChangeHeat(Patch in_Patch, ISeed in_Seed)
        {
            //
            // Projectile Y distances
            //

            //0x02C207 default 07, good from 03 - 08
            in_Patch.Add(0x02C207, in_Seed.NextUInt8(3, 9), "Heatman Projectile 1 Y-Distance");

            //0x02C208 default 05, good from 04 - 07
            in_Patch.Add(0x02C208, in_Seed.NextUInt8(4, 8), "Heatman Projectile 2 Y-Distance");

            //0x02C209 default 03, good from 03 - 05
            in_Patch.Add(0x02C209, in_Seed.NextUInt8(3, 6), "Heatman Projectile 3 Y-Distance");

            //
            // Projectile x distances, 0x3A 0x2E 0x1C
            //

            // The lower value, the faster speed. Different for each fireball.

            //0x02C20A - 1st value should be 71 to hit megaman, or, from 48 to 128
            in_Patch.Add(0x02C20A, in_Seed.NextUInt8(48, 129), "Heatman Projectile 1 X-Distance");

            //0x02C20B - 2nd value should be 46 to hit megaman, 0r, from 34 to 64
            in_Patch.Add(0x02C20B, in_Seed.NextUInt8(34, 65), "Heatman Projectile 2 X-Distance");

            //0x02C20C - 3rd value should be 23 to hit megaman, or, from 16 to 48
            in_Patch.Add(0x02C20C, in_Seed.NextUInt8(16, 49), "Heatman Projectile 3 X-Distance");


            //
            // 30/60/90 frame delay
            // Choose delay interval from 10-40 frames
            //

            Byte delay = in_Seed.NextUInt8(10, 41);

            //0x02C29D - Delay 1 0x1F
            in_Patch.Add(0x02C29D, delay, "Heatman Invuln Delay 1");
            //0x02C29E - Delay 2 0x3E
            in_Patch.Add(0x02C29E, (Byte)(delay * 2), "Heatman Invuln Delay 2");
            //0x02C29F - Delay 3 0x5D
            in_Patch.Add(0x02C29F, (Byte)(delay * 3), "Heatman Invuln Delay 3");

            //
            //0x02C253 - Charge velocity(0x04, 0x08 or more usually puts him on side of screen)
            //

            in_Patch.Add(0x02C253, in_Seed.NextUInt8(2, 6), "Heatman Charge Velocity");
        }
Beispiel #10
0
        protected void ChangeBubble(Patch Patch, Random r)
        {
            //0x03D4AB - B x - speed on shoot (0x01) (do 1-3)
            int xVelShoot = r.Next(0x03) + 0x01;

            Patch.Add(0x03D4AB, (byte)xVelShoot, "(B) | X-Velocity Shoot (Integer)");

            //0x03D4CF - B y - speed on shoot(0x02) (do 0-6)
            int yVelShoot = r.Next(0x06);

            Patch.Add(0x03D4CF, (byte)yVelShoot, "(B) | Y-Velocity Shoot (Integer)");

            //0x03DB21 - B max shots (0x03) (do 2-5, i.e. 1-4 total projectiles)
            //    Valid from 0x02 - 0x0F. Lags a bunch >= 0x06.
            int maxShots = r.Next(0x04) + 0x02;

            Patch.Add(0x03DB21, (byte)maxShots, "(B) | Max Shots");

            //0x03DB2F - B weapon type(0x04)
            // Don't do

            //0x03DB34 - B sound effect
            ESoundID sound = GetRandomSound(r);

            Patch.Add(0x03DB34, (byte)sound, "(B) | Sound");

            //0x03DB3D - B shots per ammo tick (0x02) (do 1-4)
            int magSize = r.Next(0x04) + 0x01;

            Patch.Add(0x03DB3D, (byte)magSize, "(B) | Shots Per Ammo Tick");
            AmmoUsage.Add(1d / (double)magSize);

            //0x03DFA4 - B y - pos to embed in surface(0xFF)
            // Dumb

            //0x03DFA9 - B x - speed on surface (0x02)
            //      0x01 - 0x04 ?
            int xVelRoll = r.Next(0x04) + 0x01;

            Patch.Add(0x03DFA9, (byte)xVelRoll, "(B) | X-Velocity Surface (Integer)");

            //0x03DFC0 - B x - speed after falling from ledge (0x00)
            //      Make 50% chance to be 0, or 1-5
            int    xVelFall        = 0x00;
            double rTestXFallSpeed = r.NextDouble();

            if (rTestXFallSpeed > 0.5)
            {
                xVelFall = r.Next(0x05) + 0x01;
            }
            Patch.Add(0x03DFC0, (byte)xVelFall, "(B) | X-Velocity Fall (Integer)");

            //0x03DFC8 - B y - speed after falling(0xFE)
            //      Either 0xFA - 0xFF or 0x01 - 0x06
            int[] yFallVels = new int[] { 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
            int   rIndex    = r.Next(yFallVels.Length);
            int   yFallVel  = yFallVels[rIndex];

            Patch.Add(0x03DFC8, (byte)yFallVel, "(B) | Y-Velocity Fall (Integer)");
        }
Beispiel #11
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="p"></param>
 /// <param name="jVersion"></param>
 public static void SetWily5NoMusicChange(Patch p)
 {
     p.Add(0x0383DA, 0xEA, "Disable Music on Boss Defeat 1");
     p.Add(0x0383DB, 0xEA, "Disable Music on Boss Defeat 2");
     p.Add(0x0383DC, 0xEA, "Disable Music on Boss Defeat 3");
     p.Add(0x03848A, 0xEA, "Disable Music on Boss Defeat 4");
     p.Add(0x03848B, 0xEA, "Disable Music on Boss Defeat 5");
     p.Add(0x03848C, 0xEA, "Disable Music on Boss Defeat 6");
     p.Add(0x02E070, 0xEA, "Disable Music on Boss Defeat 7");
     p.Add(0x02E071, 0xEA, "Disable Music on Boss Defeat 8");
     p.Add(0x02E072, 0xEA, "Disable Music on Boss Defeat 9");
 }
Beispiel #12
0
        /// <summary>
        /// Split an existing patch in two. That is, creates a new patch (k) based on an existing one (j)
        /// </summary>
        /// <param name="j">The j.</param>
        private void SplitPatch(int j)
        {
            // create new patch
            soilCNPatch newPatch = new soilCNPatch(this);

            Patch.Add(newPatch);
            int k = Patch.Count - 1;

            // set the size of arrays
            Patch[k].ResizeLayerArrays(dlayer.Length);

            // set C and N variables to the same state as the 'mother' patch
            for (int layer = 0; layer < dlayer.Length; layer++)
            {
                Patch[k].urea[layer]        = Patch[j].urea[layer];
                Patch[k].nh4[layer]         = Patch[j].nh4[layer];
                Patch[k].no3[layer]         = Patch[j].no3[layer];
                Patch[k].inert_c[layer]     = Patch[j].inert_c[layer];
                Patch[k].biom_c[layer]      = Patch[j].biom_c[layer];
                Patch[k].biom_n[layer]      = Patch[j].biom_n[layer];
                Patch[k].hum_c[layer]       = Patch[j].hum_c[layer];
                Patch[k].hum_n[layer]       = Patch[j].hum_n[layer];
                Patch[k].fom_c_pool1[layer] = Patch[j].fom_c_pool1[layer];
                Patch[k].fom_c_pool2[layer] = Patch[j].fom_c_pool2[layer];
                Patch[k].fom_c_pool3[layer] = Patch[j].fom_c_pool3[layer];
                Patch[k].fom_n_pool1[layer] = Patch[j].fom_n_pool1[layer];
                Patch[k].fom_n_pool2[layer] = Patch[j].fom_n_pool2[layer];
                Patch[k].fom_n_pool3[layer] = Patch[j].fom_n_pool3[layer];
            }

            // store today's values
            Patch[k].InitCalc();
        }
Beispiel #13
0
 public static void FixM445PaletteGlitch(Patch p)
 {
     for (int i = 0; i < 3; i++)
     {
         p.Add(0x395BD + i, 0xEA, "M-445 Palette Glitch Fix");
     }
 }
Beispiel #14
0
        /// <summary>
        /// Shuffle which Robot Master awards Items 1, 2, and 3.
        /// </summary>
        public void Randomize(Patch patch, Random r)
        {
            // 0x03C291 - Item # from Heat Man
            // 0x03C292 - Item # from Air Man
            // 0x03C293 - Item # from Wood Man
            // 0x03C294 - Item # from Bubble Man
            // 0x03C295 - Item # from Quick Man
            // 0x03C296 - Item # from Flash Man
            // 0x03C297 - Item # from Metal Man
            // 0x03C298 - Item # from Crash Man

            List <EItemNumber> newItemOrder = new List <EItemNumber>();

            for (byte i = 0; i < 5; i++)
            {
                newItemOrder.Add(EItemNumber.None);
            }
            newItemOrder.Add(EItemNumber.One);
            newItemOrder.Add(EItemNumber.Two);
            newItemOrder.Add(EItemNumber.Three);
            newItemOrder.Shuffle(r);

            for (int i = 0; i < 8; i++)
            {
                patch.Add((int)EItemStageAddress.HeatMan + i, (byte)newItemOrder[i], String.Format("{0}man Item Get", ((EDmgVsBoss.Offset)i).ToString()));
            }
        }
Beispiel #15
0
        /// <summary>
        /// Shuffle which Robot Master awards Items 1, 2, and 3.
        /// </summary>
        public void Randomize(Patch in_Patch, ISeed in_Seed)
        {
            // 0x03C291 - Item # from Heat Man
            // 0x03C292 - Item # from Air Man
            // 0x03C293 - Item # from Wood Man
            // 0x03C294 - Item # from Bubble Man
            // 0x03C295 - Item # from Quick Man
            // 0x03C296 - Item # from Flash Man
            // 0x03C297 - Item # from Metal Man
            // 0x03C298 - Item # from Crash Man
            List <EItemNumber> itemGetList = new List <EItemNumber>()
            {
                EItemNumber.None,
                EItemNumber.None,
                EItemNumber.None,
                EItemNumber.None,
                EItemNumber.None,
                EItemNumber.One,
                EItemNumber.Two,
                EItemNumber.Three,
            };

            IList <EItemNumber> itemGetOrder = in_Seed.Shuffle(itemGetList);

            for (Int32 index = 0; index < itemGetOrder.Count; ++index)
            {
                in_Patch.Add(
                    (Int32)EItemStageAddress.HeatMan + index,
                    (Byte)itemGetOrder[index],
                    String.Format("{0}man Item Get", ((EDmgVsBoss.Offset)index).ToString()));
            }
        }
Beispiel #16
0
        /// <summary>
        /// TODO
        /// </summary>
        public static void SetFastText(Patch p)
        {
            //int address = (jVersion) ? 0x037C51 : 0x037D4A;
            int address = 0x037D4A;

            p.Add(address, 0x04, "Weapon Get Text Write Delay");
        }
Beispiel #17
0
        public void FixWeaponLetters(Patch p, int[] permutation)
        {
            // Re-order the letters array to match the ordering of the shuffled weapons
            char[] newLettersPermutation = new char[9];
            newLettersPermutation[0] = newWeaponLetters[0];
            for (int i = 0; i < 8; i++)
            {
                newLettersPermutation[i + 1] = newWeaponLetters[permutation[i] + 1];
            }

            // Write new weapon letters to weapon get screen
            for (int i = 1; i < 9; i++)
            {
                // Write to Weapon Get screen (note: Buster value is unused here)
                int newLetter = 0x41 + Alphabet.IndexOf(newLettersPermutation[i]); // unicode
                p.Add(offsetWpnGetLetters + i - 1, (byte)newLetter, $"Weapon Get {((EDmgVsBoss.Offset)i).Name} Letter: {newWeaponLetters[i]}");
            }

            //// Write new weapon letters to pause menu
            //for (int i = 0; i < 9; i++)
            //{
            //int[] pauseLetterBytes = PauseScreenCipher[newWeaponLetters[i + 1]];
            //int wpnLetterAddress = PauseScreenWpnAddressByBossIndex[permutedIndex + 1];
            //for (int j = 0; j < pauseLetterBytes.Length; j++)
            //{
            //    p.Add(wpnLetterAddress + j, (byte)pauseLetterBytes[j], $"Pause menu weapon letter GFX for \'{newWeaponLetters[permutedIndex]}\', byte #{j}");
            //}
            //}
        }
        protected void ChangeCrash(Patch in_Patch, ISeed in_Seed)
        {
            //0x03D4AD - C x-speed on shoot (04) (do 2-7)
            Int32 xVel = in_Seed.NextInt32(0x06) + 0x02;

            in_Patch.Add(0x03D4AD, (Byte)xVel, "(C) | X-Velocity (Integer)");

            //0x03D4D7 - C y-speed integer for explosion (up only) (0)
            // TODO: Figure how this works more to apply in all directions
            // For now, 25% chance to make this move upward at 2px/fr
            Int32  yVelExplode      = 0x00;
            Double rTestYVelExplode = in_Seed.NextDouble();

            if (rTestYVelExplode > 0.75)
            {
                yVelExplode = in_Seed.NextInt32(2) + 0x01;
            }

            in_Patch.Add(0x03D4D7, (Byte)yVelExplode, "(C) | X-Velocity (Explosion)");

            //0x03DB99 - C ammo per shot (04) (do 1-3)
            Int32 ammoUse = in_Seed.NextInt32(0x03) + 0x01;

            in_Patch.Add(0x03DB99, (Byte)ammoUse, "(C) | Ammo Usage");
            AmmoUsage.Add(ammoUse);

            // 0x03DB9F - C explosion type? (02)
            // Change to 03 to "single explosion" type. Most other values break the game.
            // For now, 50% chance to change
            Int32  multiExplode      = 0x02;
            Double rTestMultiExplode = in_Seed.NextDouble();

            if (rTestMultiExplode > 0.50)
            {
                multiExplode = 0x03;
            }

            in_Patch.Add(0x03DB9F, (Byte)multiExplode, "(C) | Explosion Type");

            //0x03DBA6 - C shoot sound effect (24)
            ESoundID sound = this.GetRandomSound(in_Seed);

            in_Patch.Add(0x03DBA6, (Byte)sound, "(C) | Sound Shoot");

            //0x03E089 - C attach sound effect (2E)
            sound = this.GetRandomSound(in_Seed);
            in_Patch.Add(0x03E089, (Byte)sound, "(C) | Sound Attach");

            //0x03E09C - C delay before explosion (7E) (do 01 to C0)
            Int32 delayExplosion = in_Seed.NextInt32(0xBF) + 0x01;

            in_Patch.Add(0x03E09C, (Byte)delayExplosion, "(C) | Explode Delay");

            //0x03E0DA - C explode sound effect
            sound = this.GetRandomSound(in_Seed);
            in_Patch.Add(0x03E0DA, (Byte)sound, "(C) | Sound Explode");
        }
Beispiel #19
0
        /// <summary>
        /// This will change the delay defeating a boss and teleporting out of the field to be much shorter.
        /// The victory fanfare will not play, and you teleport out exactly 10 frames after landing the killing
        /// blow on a robot master, and faster for Wily bosses as well. This indirectly fixes the issue of
        /// potentially zipping out of Bubbleman or other robot masters' chambers, since you teleport immediately.
        /// </summary>
        /// <param name="p"></param>
        public static void SetFastBossDefeatTeleport(Patch p)
        {
            // 0x02E0AF: Time until teleport after fanfare starts. ($FD, change to $40)
            // 0x02E0A2: Time until boss-defeat fanfare starts. Note that if set too low without any additional
            //           changes, a softlock may occur after some Wily bosses. Change from $FD to $10, then
            //           modify other areas that set the intial value of $05A7 (address storing our comparison).
            //           It turns out taht Mechadragon, Picopico-kun, and Gutsdozer set the intial value to $70
            //           (at 0x02D16F). Buebeam has its own special routine with extra explosions, setting the
            //           initial value to $80 (at 0x02D386). Wily Machine and Alien do not call these subroutines
            //           and no further modification is needed.
            // 0x02D170: Wily 1/2/3 boss defeat, time until fanfare starts. ($70, change to $10)
            //           Must be less or equal to value above (at 0x02E0A2)
            // 0x02D386: Buebeam defeat, time until fanfare starts. ($80 change to $10)
            //           Must be less or equal to value above (at 0x02E0A2)
            //
            // The original subroutine that uses 0x02E0A2 is as follows:
            //
            // BossDefeatWaitForTeleport:
            //  0B:A08B: 4E 21 04  LSR $0421    // Not sure what this is for, but it gets zeroed out after a couple loops
            //  0B:A08E: AD A7 05  LDA $05A7    // $05A7 frequently stores a frame-counter or a 'state' value
            //  0B:A091: C9 10     CMP #$FD     // Compare value at $05A7 with 0xFD
            //  0B:A093: B0 04     BCS PlayFanfare_ThenWait  // If value at $05A7 >= 0xFD, jump to PlayFanfare_ThenWait
            //  0B:A095: EE A7 05  INC $05A7    // Increase value at $05A7 by 1
            //  0B:A098: 60        RTS          // Return
            // PlayFanfare_ThenWait:
            //  0B:A099                         // Play fanfare once, then wait to teleport....
            //  ...
            //
            // When defeating Wily 1, 2, 3, or 4, the BossDefeatWaitForTeleport subroutine is entered for the first time
            // with $05A7 having a value of 0x70 or 0x80; if you change the comparison value at $2E0A2 from 0xFD to a
            // value smaller than the intial $05A7, an infinite loop occurs.

            p.Add(0x02E0AF, 0x40, "Fast Boss Defeat Teleport: Teleport delay after fanfare");
            p.Add(0x02E0A2, 0x10, "Fast Boss Defeat Teleport: Global delay before fanfare");
            p.Add(0x02D170, 0x10, "Fast Boss Defeat Teleport: W1/2/3 boss delay before fanfare");
            p.Add(0x02D386, 0x10, "Fast Boss Defeat Teleport: W4 boss delay before fanfare");

            // Also, NOP out the code that plays the fanfare. It's too distorted sounding when immediately teleporting.
            // Or TODO in the future, change to a different sound?
            //  02E0B3: A9 15      LDA #$15       // Let A = the fanfare sound value (15)
            //  02E0B5: 20 51 C0   JSR PlaySound  // Jump to "PlaySound" function, which plays the value in A
            for (int i = 0; i < 5; i++)
            {
                p.Add(0x02E0B3 + i, 0xEA, "Fast Boss Defeat Teleport: Fanfare sound NOP");
            }
        }
Beispiel #20
0
        protected void ChangeFlash(Patch in_Patch, ISeed in_Seed)
        {
            // Unused addresses
            //0x02CA71 - Projectile type 0x35
            //0x02CA52 - "Length of time stopper / projectile frequency ?"

            // Flashman's AI

            //0x02C982 - Walk velocity integer 1, do from 0 to 3
            in_Patch.Add(0x02C982, in_Seed.NextUInt8(4), "Flashman Walk Velocity Integer");

            //0x02C97D - Walk velocity fraction 6, do 0 to 255
            in_Patch.Add(0x02C97D, in_Seed.NextUInt8(256), "Flashman Walk Velocity Fraction");

            //0x02C98B - Delay before time stopper 187 frames. Do from 30 frames to 240 frames
            in_Patch.Add(0x02C98B, in_Seed.NextUInt8(30, 241), "Flashman Delay Before Time Stopper");

            //0x02CAC6 - Jump distance integer 0, do 0 to 3
            // TODO do fraction also
            in_Patch.Add(0x02CAC6, in_Seed.NextUInt8(4), "Flashman Jump X-Velocity Integer");

            //0x02CACE - Jump height 4, do 3 to 8
            in_Patch.Add(0x02CACE, in_Seed.NextUInt8(3, 9), "Flashman Jump Y-Velocity Integer");

            //0x02CA81 - Projectile speed 8, do 2 to 10
            in_Patch.Add(0x02CA81, in_Seed.NextUInt8(2, 11), "Flashman Projectile Velocity Integer");

            //0x02CA09 - Number of projectiles to shoot 6, do 3 to 16
            in_Patch.Add(0x02CA09, in_Seed.NextUInt8(3, 17), "Flashman Number of Projectiles");
        }
        public void RandomizeAndWrite(Patch patch, Random rand, int setNumber)
        {
            Index = rand.Next(ColorBytes.Count);

            for (int i = 0; i < addresses.Length; i++)
            {
                patch.Add(addresses[i], (byte)ColorBytes[Index][i], String.Format("Color Set {0} (Index Chosen: {1}) Value #{2}", setNumber, Index, i));
            }
        }
Beispiel #22
0
        public void OldRando(Patch p, Random r)
        {
            List <EMusicID> newBGMOrder = new List <EMusicID>();
            List <EMusicID> robos       = new List <EMusicID>();

            // Select 2 replacement tracks for the 2 extra instance of the boring W3/4/5 theme
            robos.Add(EMusicID.Flash);
            robos.Add(EMusicID.Heat);
            robos.Add(EMusicID.Air);
            robos.Add(EMusicID.Wood);
            robos.Add(EMusicID.Quick);
            robos.Add(EMusicID.Metal);
            robos.Add(EMusicID.Clash);
            robos.Add(EMusicID.Bubble);
            robos.Shuffle(r);

            newBGMOrder.Add(EMusicID.Flash);
            newBGMOrder.Add(EMusicID.Heat);
            newBGMOrder.Add(EMusicID.Air);
            newBGMOrder.Add(EMusicID.Wood);
            newBGMOrder.Add(EMusicID.Quick);
            newBGMOrder.Add(EMusicID.Metal);
            newBGMOrder.Add(EMusicID.Clash);
            newBGMOrder.Add(EMusicID.Bubble);
            newBGMOrder.Add(EMusicID.Wily12);
            newBGMOrder.Add(EMusicID.Wily12);  // Wily 1/2 track will play twice
            newBGMOrder.Add(EMusicID.Wily345); // Wily 3/4/5 track only plays once
            newBGMOrder.Add(robos[0]);         // Add extra Robot Master tracks to the set
            newBGMOrder.Add(robos[1]);

            // Randomize tracks
            newBGMOrder.Shuffle(r);

            // Start writing at Heatman BGM ID, both J and U
            // Loop through BGM addresses Heatman to Wily 5 (Wily 6 still silent)
            for (int i = 0; i < newBGMOrder.Count; i++)
            {
                EMusicID bgm = newBGMOrder[i];
                p.Add(0x0381E0 + i, (byte)bgm, String.Format("BGM Stage {0}", i));
            }

            // Finally, fix Wily 5 track when exiting a Teleporter to be the selected Wily 5 track instead of default
            p.Add(0x038489, (byte)newBGMOrder.Last(), "BGM Wily 5 Teleporter Exit Fix");
        }
Beispiel #23
0
        protected void ChangeHeat(Patch Patch, Random r)
        {
            int rInt = 0;

            // Heatman AI 0x02C16E - 0x02C1FE

            // projectile y - distances
            //0x02C207 default 07, good from 03 - 08
            //0x02C208 default 05, good from 04 - 07
            //0x02C209 default 03, good from 03 - 05
            rInt = r.Next(6) + 0x03;
            Patch.Add(0x02C207, (byte)rInt, "Heatman Projectile 1 Y-Distance");
            rInt = r.Next(4) + 0x04;
            Patch.Add(0x02C208, (byte)rInt, "Heatman Projectile 2 Y-Distance");
            rInt = r.Next(3) + 0x03;
            Patch.Add(0x02C209, (byte)rInt, "Heatman Projectile 3 Y-Distance");

            // projectile x-distances, 0x3A 0x2E 0x1C
            // - The lower value, the faster speed. Different for each fireball.
            //0x02C20A - 1st value should be 0x47 to hit megaman, Or, from 0x30 to 0x80
            //0x02C20B - 2nd value should be 0x2E to hit megaman. Or, from 0x22 to 0x40
            //0x02C20C - 3rd value should be 0x17 to hit megaman, Or, from 0x10 to 0x30
            rInt = r.Next(0x80 - 0x30 + 1) + 0x30;
            Patch.Add(0x02C20A, (byte)rInt, "Heatman Projectile 1 X-Distance");
            rInt = r.Next(0x40 - 0x22 + 1) + 0x22;
            Patch.Add(0x02C20B, (byte)rInt, "Heatman Projectile 2 X-Distance");
            rInt = r.Next(0x30 - 0x10 + 1) + 0x10;
            Patch.Add(0x02C20C, (byte)rInt, "Heatman Projectile 3 X-Distance");

            // 30/60/90 frame delay
            //0x02C29D - Delay 1 0x1F
            //0x02C29E - Delay 2 0x3E
            //0x02C29F - Delay 3 0x5D
            // Choose delay interval from 10-40 frames
            rInt = r.Next(31) + 10;
            Patch.Add(0x02C29D, (byte)rInt, "Heatman Invuln Delay 1");
            Patch.Add(0x02C29E, (byte)(rInt * 2), "Heatman Invuln Delay 2");
            Patch.Add(0x02C29F, (byte)(rInt * 3), "Heatman Invuln Delay 3");

            //0x02C253 - Charge velocity(0x04, 0x08 or more usually puts him on side of screen)
            rInt = r.Next(4) + 0x02;
            Patch.Add(0x02C253, (byte)rInt, "Heatman Charge Velocity");
        }
Beispiel #24
0
        private static void ChangeW4FloorsSpikePit(Patch Patch, Random r)
        {
            // 5 tiles, but since two adjacent must construct a gap, 4 possible gaps.  Choose 1 random gap.
            int gap = r.Next(4);

            for (int i = 0; i < 4; i++)
            {
                if (i == gap)
                {
                    Patch.Add(0x00CB9A + i * 8, 0x9B, String.Format("Wily 4 Room 5 Tile {0} (gap on right)", i));
                    Patch.Add(0x00CB9A + i * 8 + 8, 0x9C, String.Format("Wily 4 Room 5 Tile {0} (gap on left)", i));
                    ++i; // skip next tile since we just drew it
                }
                else
                {
                    Patch.Add(0x00CB9A + i * 8, 0x9D, String.Format("Wily 4 Room 5 Tile {0} (solid)", i));
                }
            }
        }
Beispiel #25
0
        public void RandomizeAndWrite(Patch in_Patch, ISeed in_Seed, Int32 setNumber)
        {
            this.Index = in_Seed.NextInt32(ColorBytes.Count);

            for (Int32 i = 0; i < this.addresses.Length; i++)
            {
                in_Patch.Add(
                    this.addresses[i],
                    (Byte)this.ColorBytes[this.Index][i],
                    String.Format("Color Set {0} (Index Chosen: {1}) Value #{2}", setNumber, Index, i));
            }
        }
Beispiel #26
0
        //
        // Private Static Methods
        //

        /// <summary>
        /// This method patches the company name in the intro screen.
        /// </summary>
        /// <remarks>
        /// Intro Screen Line 1: 0x036EA8 - 0x036EBA (19 chars)
        /// ©2017 <company name> (13 chars for company, 19 total)
        /// </remarks>
        public static void PatchCompanyName(Patch in_Patch, CompanyName in_CompanyName)
        {
            const Int32 MAX_LINE_LENGTH     = 19;
            const Int32 INTRO_LINE1_ADDRESS = 0x036EA8;

            String line = $"©{DateTime.Now.Year} {in_CompanyName.GetCompanyName()}".PadCenter(MAX_LINE_LENGTH);

            in_Patch.Add(
                INTRO_LINE1_ADDRESS,
                line.AsIntroString(),
                $"Splash Text: {line}");
        }
Beispiel #27
0
        /// <summary>
        /// TODO
        /// </summary>
        public static void SetBurstChaser(Patch p, bool jVersion)
        {
            p.Add(0x038147, 0x60, "READY Text Delay");
            p.Add(0x038921, 0x03, "Mega Man Walk X-Velocity Integer");
            p.Add(0x03892C, 0x00, "Mega Man Walk X-Velocity Fraction");
            p.Add(0x038922, 0x03, "Mega Man Air X-Velocity Integer");
            p.Add(0x03892D, 0x00, "Mega Man Air X-Velocity Fraction");
            p.Add(0x0386EF, 0x01, "Mega Man Ladder Climb Up Integer");
            p.Add(0x03872E, 0xFE, "Mega Man Ladder Climb Down Integer");

            int address = (jVersion) ? 0x03D4A4 : 0x03D4A7;

            p.Add(address, 0x08, "Buster Projectile X-Velocity Integer");
        }
Beispiel #28
0
        protected void ChangeQuick(Patch Patch, Random r)
        {
            int rInt;

            // Other addresses with potential:
            //0x02C872 - Projectile type, 0x59

            // Quickman's AI
            //0x02C86E - Number of Boomerangs, 0x03, do from 1 - 0x0A
            rInt = r.Next(0x0B) + 0x01;
            Patch.Add(0x02C86E, (byte)rInt, "Quickman Number of Boomerangs");

            //0x02C882 - Boomerang: delay before arc 0x25. 0 for no arc, or above like 0x35. do from 5 to 0x35.
            rInt = r.Next(0x35 - 0x05 + 1) + 0x05;
            Patch.Add(0x02C882, (byte)rInt, "Quickman Boomerang Delay 1");

            //0x02C887 - Boomerang speed when appearing, 0x04, do from 0x01 to 0x07
            rInt = r.Next(0x07 - 0x01 + 1) + 0x01;
            Patch.Add(0x02C887, (byte)rInt, "Quickman Boomerang Velocity Integer 1");

            //0x03B726 - Boomerang speed secondary, 0x04, does this affect anything else?
            rInt = r.Next(0x07 - 0x01 + 1) + 0x01;
            Patch.Add(0x03B726, (byte)rInt, "Quickman Boomerang Velocity Integer 2");

            // For all jumps, choose randomly from 0x02 to 0x0A
            //0x02C8A3 - Middle jump, 0x07
            rInt = r.Next(0x0A - 0x02 + 1) + 0x02;
            Patch.Add(0x02C8A3, (byte)rInt, "Quickman Jump Height 1 Integer");

            //0x02C8A4 - High jump, 0x08
            rInt = r.Next(0x0A - 0x02 + 1) + 0x02;
            Patch.Add(0x02C8A4, (byte)rInt, "Quickman Jump Height 2 Integer");

            //0x02C8A5 - Low jump, 0x04
            rInt = r.Next(0x0A - 0x02 + 1) + 0x02;
            Patch.Add(0x02C8A5, (byte)rInt, "Quickman Jump Height 3 Integer");

            //0x02C8E4 - Running time, 0x3E, do from 0x18 to 0x50
            rInt = r.Next(0x50 - 0x18 + 1) + 0x18;
            Patch.Add(0x02C8E4, (byte)rInt, "Quickman Running Time");

            //0x02C8DF - Running speed, 0x02, do from 0x05 to 0x01
            rInt = r.Next(0x05 - 0x01 + 1) + 0x01;
            Patch.Add(0x02C8DF, (byte)rInt, "Quickman Running Velocity Integer");
        }
Beispiel #29
0
        /// <summary>
        /// This method patches the intro story text.
        /// </summary>
        /// <remarks>
        /// Intro Story: 0x036D56 - 0x036E64 (270 chars)
        /// 27 characters per line
        /// 10 lines
        /// </remarks>
        public static void PatchIntroStory(Patch in_Patch, ISeed in_Seed)
        {
            const Int32 INTRO_STORY_PAGE1_ADDRESS = 0x036D56;

            IntroStorySet            introStorySet = Properties.Resources.IntroStoryConfig.Deserialize <IntroStorySet>();
            IEnumerable <IntroStory> introStories  = introStorySet.Where(x => true == x.Enabled);
            IntroStory introStory = in_Seed.NextElement(introStories);

            in_Patch.Add(
                INTRO_STORY_PAGE1_ADDRESS,
                introStory.GetFormattedString(),
                $"Intro Text: {introStory.Title}");
        }
Beispiel #30
0
        protected void ChangeMetal(Patch Patch, Random r)
        {
            int    rInt;
            double rDbl;

            // Unused addresses
            //0x02CC2D - Projectile type
            //0x02CC29 - Metal Blade sound effect 0x20

            // Metalman AI

            //0x02CC3F - Speed of Metal blade 0x04, do 2 to 9
            rInt = r.Next(8) + 2;
            Patch.Add(0x02CC3F, (byte)rInt, "Metalman Projectile Velocity Integer");

            //0x02CC1D - Odd change to attack behavior, 0x06, only if different than 6. Give 25% chance.
            rDbl = r.NextDouble();
            if (rDbl > 0.75)
            {
                Patch.Add(0x02CC1D, 0x05, "Metalman Alternate Attack Behavior");
            }

            //0x02CBB5 - Jump Height 1 0x06, do from 03 - 07 ? higher than 7 bonks ceiling
            //0x02CBB6 - Jump Height 2 0x05
            //0x02CBB7 - Jump Height 3 0x04
            List <int> jumpHeight = new List <int>()
            {
                0x03, 0x04, 0x05, 0x06, 0x07
            };

            for (int i = 0; i < 3; i++)
            {
                // Pick a height at random and remove from list to get 3 different heights
                rInt = r.Next(jumpHeight.Count);
                Patch.Add(0x02CBB5 + i, (byte)jumpHeight[rInt], String.Format("Metalman Jump {0} Y-Velocity Integer", i + 1));
                jumpHeight.RemoveAt(rInt);
            }
        }