Add() публичный Метод

public Add ( int address, byte value, string note = "" ) : void
address int
value byte
note string
Результат void
Пример #1
0
        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
        }
Пример #2
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");
 }
Пример #3
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));
         }
     }
 }
Пример #4
0
        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));
            }
        }
Пример #5
0
        public void Randomize(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");
        }
Пример #6
0
        private static void ChangeW4FloorsBeforeSpikes(Patch Patch, Random r)
        {
            // Choose 2 of the 5 32x32 tiles to be fake
            int tileA = r.Next(5);
            int tileB = r.Next(4);

            // Make sure 2nd tile chosen is different
            if (tileB == tileA) tileB++;

            for (int i = 0; i < 5; i++)
            {
                if (i == tileA || i == tileB)
                {
                    Patch.Add(0x00CB5C + i * 8, 0x94, String.Format("Wily 4 Room 4 Tile {0} (fake)", i));
                }
                else
                {
                    Patch.Add(0x00CB5C + i * 8, 0x85, String.Format("Wily 4 Room 4 Tile {0} (solid)", i));
                }
            }
        }
Пример #7
0
        public static void DrawTitleScreenChanges(Patch p, int seed)
        {
            // Draw version number
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            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, String.Format("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), String.Format("Title Screen Seed"));
            }
        }
Пример #8
0
        /// <summary>
        /// Enabling Random Weapons or Random Stages will cause the wrong Robot Master portrait to
        /// be blacked out when a stage is completed. The game uses your acquired weapons to determine
        /// which portrait to black-out. This function changes the lookup table for x and y positions
        /// of portraits to black-out based on what was randomized.
        /// </summary>
        public static void FixPortraits(Patch Patch, bool is8StagesRandom, RStages randomStages, bool isWeaponGetRandom, RWeaponGet randomWeaponGet)
        {
            // Arrays of default values for X and Y of the black square that marks out each portrait
            // Index of arrays are stage order, e.g. Heat, Air, etc.
            byte[] portraitBG_y = new byte[] { 0x21, 0x20, 0x21, 0x20, 0x20, 0x22, 0x22, 0x22 };
            byte[] portraitBG_x = new byte[] { 0x86, 0x8E, 0x96, 0x86, 0x96, 0x8E, 0x86, 0x96 };

            // Adjusting the sprites is not necessary because the hacked portrait graphics ("?" images)
            // only use the background, and the sprites have been blacked out. Left in for reference.
            //byte[] portraitSprite_x = new byte[] { 0x3C, 0x0C, 0x4C, 0x00, 0x20, 0x84, 0x74, 0xA4 };
            //byte[] portraitSprite_y = new byte[] { 0x10, 0x14, 0x28, 0x0C, 0x1C, 0x20, 0x10, 0x18 };

            // Apply changes to portrait arrays based on shuffled stages
            if (is8StagesRandom)
            {
                randomStages.FixPortraits(ref portraitBG_x, ref portraitBG_y);
            }

            // Apply changes to portrait arrays based on shuffled weapons. Only need a standard "if" with no "else",
            // because the arrays must be permuted twice if both randomization settings are enabled.
            if (isWeaponGetRandom)
            {
                randomWeaponGet.FixPortraits(ref portraitBG_x, ref portraitBG_y);
            }

            for (int i = 0; i < 8; i++)
            {
                Patch.Add(0x034541 + i, portraitBG_y[i], String.Format("Stage Select Portrait {0} Y-Pos Fix", i + 1));
                Patch.Add(0x034549 + i, portraitBG_x[i], String.Format("Stage Select Portrait {0} X-Pos Fix", i + 1));
                // Changing this sprite table misplaces their positions by default.
                //stream.Position = 0x03460D + i;
                //stream.WriteByte(portraitSprite_y[i]);
                //stream.Position = 0x034615 + i;
                //stream.WriteByte(portraitSprite_x[i]);
            }
        }
Пример #9
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()));
            }
        }
Пример #10
0
        protected void ChangeClash(Patch Patch, Random r)
        {
            int rInt;
            double rDbl;

            // Unused addresses
            //0x02CDAF - Jump velocity fraction? 0x44 double check

            // Clashman AI

            // Crash Man's routine for attack
            //0x02CCf2 - Walk x-vel fraction 0x47
            rInt = r.Next(256);
            Patch.Add(0x02CCf2, (byte)rInt, "Clashman Walk X-Velocity Fraction");

            //0x02CCF7 - Walk x-vel integer 0x01, do 0 to 3
            rInt = r.Next(4);
            Patch.Add(0x02CCF7, (byte)rInt, "Clashman Walk X-Velocity Integer");

            //0x02CD07 - Jump behavior 0x27. 0x17 = always jumping, any other value = doesn't react with a jump.
            // Give 25% chance for each unique behavior, and 50% for default.
            rDbl = r.NextDouble();
            byte jumpType = 0x27;
            if (rDbl > 0.75)
            {
                jumpType = 0x17;
            }
            else if (rDbl > 0.5)
            {
                jumpType = 0x26;
            }
            Patch.Add(0x02CD07, jumpType, "Clashman Special Jump Behavior");

            //0x02CD2A - Jump y-vel intger, 0x06, do from 0x02 to 0x0A
            rInt = r.Next(0x0A - 0x02 + 1) + 0x02;
            Patch.Add(0x02CD2A, (byte)rInt, "Clashman Jump Y-Velocity Integer");

            //0x02CDD3 - Shot behavior, 0x5E, change to have him always shoot when jumping, 20% chance
            rDbl = r.NextDouble();
            if (rDbl > 0.80)
                Patch.Add(0x02CDD3, 0x50, "Clashman Disable Single Shot");

            //0x02CDEE - Clash Bomber velocity, 0x06, do from 2 to 8
            rInt = r.Next(7) + 2;
            Patch.Add(0x02CD2A, (byte)rInt, "Clashman Clash Bomber X-Velocity");
        }
Пример #11
0
        protected void ChangeBubble(Patch Patch, Random r)
        {
            byte[] yVels;
            int rInt;

            // Bubbleman's AI

            //0x02C70B - Falling speed integer, 0xFF.
            yVels = new byte[] { 0xF0, 0xF4, 0xF8, 0xFC, 0xFF };
            rInt = r.Next(yVels.Length);
            Patch.Add(0x02C70B, yVels[rInt], "Bubbleman Y-Velocity Falling");

            //0x02C6D3 - Rising speed integer, 0x01.
            yVels = new byte[] { 0x01, 0x02, 0x03, 0x05 };
            rInt = r.Next(yVels.Length);
            Patch.Add(0x02C6D3, yVels[rInt], "Bubbleman Y-Velocity Rising");
        }
Пример #12
0
        /// <summary>
        /// Shuffle the Robot Master stages.  This shuffling will not be indicated by the Robot Master portraits.
        /// </summary>
        public void Randomize(Patch Patch, Random r)
        {
            // StageSelect  Address    Value
            // -----------------------------
            // Bubble Man   0x034670   3
            // Air Man      0x034671   1
            // Quick Man    0x034672   4
            // Wood Man     0x034673   2
            // Crash Man    0x034674   7
            // Flash Man    0x034675   5
            // Metal Man    0x034676   6
            // Heat Man     0x034677   0

            StageSelect = new List<StageFromSelect>();

            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Bubble Man",
                PortraitAddress = ERMPortraitAddress.BubbleMan,
                PortraitDestinationOriginal = 3,
                PortraitDestinationNew = 3,
                StageClearAddress = ERMStageClearAddress.BubbleMan,
                StageClearDestinationOriginal = 8,
                StageClearDestinationNew = 8
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Air Man",
                PortraitAddress = ERMPortraitAddress.AirMan,
                PortraitDestinationOriginal = 1,
                PortraitDestinationNew = 1,
                StageClearAddress = ERMStageClearAddress.AirMan,
                StageClearDestinationOriginal = 2,
                StageClearDestinationNew = 2
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Quick Man",
                PortraitAddress = ERMPortraitAddress.QuickMan,
                PortraitDestinationOriginal = 4,
                PortraitDestinationNew = 4,
                StageClearAddress = ERMStageClearAddress.QuickMan,
                StageClearDestinationOriginal = 16,
                StageClearDestinationNew = 16
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Wood Man",
                PortraitAddress = ERMPortraitAddress.WoodMan,
                PortraitDestinationOriginal = 2,
                PortraitDestinationNew = 2,
                StageClearAddress = ERMStageClearAddress.WoodMan,
                StageClearDestinationOriginal = 4,
                StageClearDestinationNew = 4
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Clash Man",
                PortraitAddress = ERMPortraitAddress.CrashMan,
                PortraitDestinationOriginal = 7,
                PortraitDestinationNew = 7,
                StageClearAddress = ERMStageClearAddress.CrashMan,
                StageClearDestinationOriginal = 128,
                StageClearDestinationNew = 128
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Flash Man",
                PortraitAddress = ERMPortraitAddress.FlashMan,
                PortraitDestinationOriginal = 5,
                PortraitDestinationNew = 5,
                StageClearAddress = ERMStageClearAddress.FlashMan,
                StageClearDestinationOriginal = 32,
                StageClearDestinationNew = 32
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Metal Man",
                PortraitAddress = ERMPortraitAddress.MetalMan,
                PortraitDestinationOriginal = 6,
                PortraitDestinationNew = 6,
                StageClearAddress = ERMStageClearAddress.MetalMan,
                StageClearDestinationOriginal = 64,
                StageClearDestinationNew = 64
            });
            StageSelect.Add(new StageFromSelect()
            {
                PortraitName = "Heat Man",
                PortraitAddress = ERMPortraitAddress.HeatMan,
                PortraitDestinationOriginal = 0,
                PortraitDestinationNew = 0, // 4 = quick
                StageClearAddress = ERMStageClearAddress.HeatMan,
                StageClearDestinationOriginal = 1,
                StageClearDestinationNew = 1
            });

            List<byte> newStageOrder = new List<byte>();
            for (byte i = 0; i < 8; i++) newStageOrder.Add(i);

            newStageOrder.Shuffle(r);

            for (int i = 0; i < 8; i++)
            {
                string portrait = StageSelect[i].PortraitName;
                StageSelect[i].PortraitDestinationNew = StageSelect[newStageOrder[i]].PortraitDestinationOriginal;
            }

            foreach (StageFromSelect stage in StageSelect)
            {
                Patch.Add((int)stage.PortraitAddress, (byte)stage.PortraitDestinationNew, String.Format("Stage Select {0} Destination", stage.PortraitName));
            }
        }
Пример #13
0
        protected void ChangeAir(Patch Patch, Random r)
        {
            //0x03DAD6 - A num projectiles, default 0x04
            //  Values 0x02 and 0x03 work, but larger values behave strangely
            int numProjectiles = 0x04;
            double rTestNumProjectiles = r.NextDouble();
            if (rTestNumProjectiles > 0.80)
                numProjectiles = 0x03;
            else if (rTestNumProjectiles > 0.60)
                numProjectiles = 0x02;
            Patch.Add(0x03DAD6, (byte)numProjectiles, "(A) | Number of Projectiles");

            //0x03DADA - A projectile type, default 0x02
            //  Can use this to change behavior completely!Buggy though.

            //0x03DAE6 - A sound effect (0x3F)
            ESoundID sound = GetRandomSound(r);
            Patch.Add(0x03DAE6, (byte)sound, "(A) | Sound");

            //0x03DAEE - A ammo used(0x02)
            int ammoUse = r.Next(0x02) + 0x01;
            Patch.Add(0x03DAEE, (byte)ammoUse, "(A) | Ammo Use");
            AmmoUsage.Add(ammoUse);

            //0x03DE6E - A projectile y-acceleration fraction(10)
            // Do 0x02 to 0x32, where values above 0x10 are less common
            int yAccFrac = r.Next(0x17) + 0x02;
            if (yAccFrac > 0x10)
            {
                // double the addition of any acceleration value chosen above 0x10
                yAccFrac += (yAccFrac - 0x10) * 2;
            }
            Patch.Add(0x03DE6E, (byte)yAccFrac, "(A) | Y-Acceleration (fraction)");

            //0x03DE76 - A projectile y-acceleration integer(00)
            // 15% chance to be significantly faster
            int yAccInt = 0x00;
            double rYAcc = r.NextDouble();
            if (rYAcc > 0.85)
                yAccInt = 0x01;
            Patch.Add(0x03DE76, (byte)yAccInt, "(A) | Y-Acceleration (integer)");

            //0x03DE7E - A x - speed fraction projectile 1(19)
            //0x03DE7F - A x - speed fraction projectile 2(99)
            //0x03DE80 - A x - speed fraction projectile 3(33)
            for (int i = 0; i < 3; i++)
            {
                int xFracSpeed = r.Next(0xFF) + 0x01;
                Patch.Add(0x03DE7E + i, (byte)xFracSpeed, String.Format("(A) | Projectile {0} X-Velocity (fraction)", i + 1));
            }

            //0x03DE81 - A x - speed integer projectile 1(01)
            //0x03DE82 - A x - speed integer projectile 2(01)
            //0x03DE83 - A x - speed integer projectile 3(02)
            int[] xIntSpeeds = new int[] {
                0x00, 0x01, 0x02, 0x04, 0x06
            };
            int rIndex = 0;
            int xIntSpeed = 0;
            for (int i = 0; i < 3; i++)
            {
                rIndex = r.Next(xIntSpeeds.Length);
                xIntSpeed = xIntSpeeds[rIndex];
                Patch.Add(0x03DE81 + i, (byte)xIntSpeed, String.Format("(A) | Projectile {0} X-Velocity (integer)", i + 1));
            }
        }
Пример #14
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");
        }
Пример #15
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);
            }
        }
Пример #16
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
                int busterI1 = r.Next(8);
                int busterI2 = busterI1;
                while (busterI2 == busterI1)
                    busterI2 = r.Next(8);

                // 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];
                    //stream.Position = weakWeap2 + i;
                    byte dmgSecondary = 0x02;
                    if (weakWeap2 == EDmgVsBoss.U_DamageH)
                    {
                        dmgSecondary = 0x04;
                    }
                    else if (weakWeap2 == EDmgVsBoss.U_DamageF)
                    {
                        dmgSecondary = 0x00;
                        //long prevStreamPos = stream.Position;
                        //stream.Position = 0x02C08F;
                        //stream.WriteByte((byte)i);
                        //stream.Position = prevStreamPos;
                        // 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));
                    //stream.WriteByte(dmgSecondary);

                    // Add buster damage
                    //stream.Position = EDmgVsBoss.U_DamageP + i;
                    if (i == busterI1 || i == busterI2)
                    {
                        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.AppendLine();
            }

            // 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() ));
                    }
                }
            }
        }
Пример #17
0
        /// <summary>
        /// TODO
        /// </summary>
        public static void SetBurstChaser(Patch p, bool jVersion)
        {
            p.Add(0x038147, 0x60, String.Format("READY Text Delay"));
            p.Add(0x038921, 0x03, String.Format("Mega Man Walk X-Velocity Integer"));
            p.Add(0x03892C, 0x00, String.Format("Mega Man Walk X-Velocity Fraction"));
            p.Add(0x038922, 0x03, String.Format("Mega Man Air X-Velocity Integer"));
            p.Add(0x03892D, 0x00, String.Format("Mega Man Air X-Velocity Fraction"));
            p.Add(0x0386EF, 0x01, String.Format("Mega Man Ladder Climb Up Integer"));
            p.Add(0x03872E, 0xFE, String.Format("Mega Man Ladder Climb Down Integer"));

            int address = (jVersion) ? 0x03D4A4 : 0x03D4A7;
            p.Add(address, 0x08, String.Format("Buster Projectile X-Velocity Integer"));
        }
Пример #18
0
 public static void EnablePressDamage(Patch Patch)
 {
     Patch.Add(EDmgVsEnemy.DamageP + EDmgVsEnemy.Offset.Press, 0x01, "Buster Damage Against Press");
 }
Пример #19
0
 /// <summary>
 /// TODO
 /// </summary>
 public static void SetFastText(Patch p, bool jVersion)
 {
     int address = (jVersion) ? 0x037C51 : 0x037D4A;
     p.Add(address, 0x04, String.Format("Weapon Get Text Write Delay"));
 }
Пример #20
0
        protected void ChangeFlash(Patch Patch, Random r)
        {
            int rInt;

            // Unused addresses
            //0x02CA71 - Projectile type 0x35
            //0x02CA52 - "Length of time stopper / projectile frequency ?"

            // Flashman's AI

            //0x02C982 - Walk velocity integer 0x01, do from 0 to 3
            rInt = r.Next(0x04);
            Patch.Add(0x02C982, (byte)rInt, "Flashman Walk Velocity Integer");

            //0x02C97D - Walk velocity fraction 0x06, do 0x00-0xFF
            rInt = r.Next(256);
            Patch.Add(0x02C97D, (byte)rInt, "Flashman Walk Velocity Fraction");

            //0x02C98B - Delay before time stopper 0xBB (187 frames). Do from 30 frames to 240 frames
            rInt = r.Next(211) + 30;
            Patch.Add(0x02C98B, (byte)rInt, "Flashman Delay Before Time Stopper");

            //0x02CAC6 - Jump distance integer 0x00, do 0 to 3
            // TODO do fraction also
            rInt = r.Next(4);
            Patch.Add(0x02CAC6, (byte)rInt, "Flashman Jump X-Velocity Integer");

            //0x02CACE - Jump height 0x04, do 3 - 8
            rInt = r.Next(6) + 3;
            Patch.Add(0x02CACE, (byte)rInt, "Flashman Jump Y-Velocity Integer");

            //0x02CA81 - Projectile speed 0x08, do 2 - 0A
            rInt = r.Next(0x0A - 0x02 + 1) + 0x02;
            Patch.Add(0x02CA81, (byte)rInt, "Flashman Projectile Velocity Integer");

            //0x02CA09 - Number of projectiles to shoot 0x06, do 3 - 0x10
            rInt = r.Next(0x10 - 0x03 + 1) + 0x03;
            Patch.Add(0x02CA09, (byte)rInt, "Flashman Number of Projectiles");
        }
Пример #21
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");
        }
Пример #22
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 6 for the main weakness
                // Deal ammoUse x 2 for another
                // Deal ammoUse x 1 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 = ' ';

                    // Pico weakness 1, deal ammoUse x8 damage
                    if (weapon == enemyWeak1)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 10);
                        if (damage < 2) damage = 3;
                        level = '^';
                    }
                    // weakness 2, deal ammoUse x5 damage
                    else if (weapon == enemyWeak2)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 5);
                        if (damage < 2) damage = 2;
                        level = '*';
                    }
                    // weakness 3, deal ammoUse x2 damage
                    else if (weapon == enemyWeak3)
                    {
                        damage = (byte)(RWeaponBehavior.AmmoUsage[i + 1] * 2);
                        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
                rInt = r.Next(dmgBarrierList.Count);
                EDmgVsEnemy wpnBarrier = dmgBarrierList[rInt];

                // 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", wpnBarrier.WeaponName));
                    Patch.Add(wpn.Address + EDmgVsEnemy.Offset.ClashBarrier_Other, damage, String.Format("{0} Damage to Clash Barrier 2", wpnBarrier.WeaponName));
                }

                // Remove Barrier weakness from list (therefore, different Buebeam weakness)
                dmgBarrierList.Remove(wpnBarrier);

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

                // 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);
                }
                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.AppendLine();
            } // 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
        }
Пример #23
0
        protected void ChangeAir(Patch Patch, Random r)
        {
            int rInt = 0;
            double rDbl = 0;

            // Airman AI 0x02C2F3 - 0x02C50A

            // Create random Air Shooter patterns

            //0x02C393 - Tornado 0 Pattern 0 y-vel fraction
            //0x02C395 - Tornado 1 Pattern 0 y-vel frac
            //...
            //0x02C39A - Tornado 0 Pattern 1 y-vel frac
            //... ...
            //0x02C3B1 - Tornado 0 Pattern 0 y-vel integer
            //0x02C3CF - Tornado 0 Pattern 0 x-vel fraction
            //0x02C3ED - Tornado 0 Pattern 0 x-vel integer
            //0x02C40B - Tornado 0 Pattern 0 delay before stop
            const int A_tornadoTableLength = 0x1E;

            // Write y-vel fractions: 00-FF
            for (int i = 0; i < A_tornadoTableLength; i++)
            {
                rInt = r.Next(256);
                Patch.Add(0x02C393 + i, (byte)rInt, String.Format("Airman Tornado {0} Y-Vel Frac", i));
            }

            // Write y-vel integers: FF-03, rare 04
            for (int i = 0; i < A_tornadoTableLength; i++)
            {
                byte A_yVelInt = 0;
                byte[] A_yVelInts = new byte[] { 0xFF, 0x00, 0x01, 0x02, 0x03 };
                rDbl = r.NextDouble();
                if (rDbl > 0.9)
                {
                    A_yVelInt = 0x04;
                }
                else
                {
                    rInt = r.Next(A_yVelInts.Length);
                    A_yVelInt = A_yVelInts[rInt];
                }
                Patch.Add(0x02C3B1 + i, A_yVelInt, String.Format("Airman Tornado {0} Y-Vel Int", i));
            }

            // Write x-vel fractions: 00-FF
            for (int i = 0; i < A_tornadoTableLength; i++)
            {
                rInt = r.Next(256);
                Patch.Add(0x02C3CF + i, (byte)rInt, String.Format("Airman Tornado {0} X-Vel Frac", i));
            }

            // Write x-vel integers: 00-04, rare 04, common 03
            for (int i = 0; i < A_tornadoTableLength; i++)
            {
                byte A_xVelInt = 0;
                byte[] A_xVelInts = new byte[] { 0x00, 0x01, 0x02 };
                rDbl = r.NextDouble();
                if (rDbl > 0.9)
                {
                    A_xVelInt = 0x04;
                }
                else if (rDbl > 0.6)
                {
                    A_xVelInt = 0x03;
                }
                else
                {
                    rInt = r.Next(A_xVelInts.Length);
                    A_xVelInt = A_xVelInts[rInt];
                }
                Patch.Add(0x02C3ED + i, A_xVelInt, String.Format("Airman Tornado {0} X-Vel Int", i));
            }

            // Write delays: 05-2A
            for (int i = 0; i < A_tornadoTableLength; i++)
            {
                rInt = r.Next(0x25) + 0x05;
                Patch.Add(0x02C40B + i, (byte)rInt, String.Format("Airman Tornado {0} Delay Time", i));
            }

            // 0x02C30C - Num patterns before jumping 0x03 (do 1-4)
            rInt = r.Next(4) + 1;
            Patch.Add(0x02C30C, (byte)rInt, "Airman Patterns Before Jump");

            //0x02C4DD - First Jump y-vel frac, 0xE6
            //0x02C4DE - Second Jump y-vel frac, 0x76
            //0x02C4E0 - First Jump y-vel int, 0x04
            //0x02C4E1 - Second Jump y-vel int 0x07
            //0x02C4E3 - First Jump x-vel frac, 0x39
            //0x02C4E4 - Second Jump x-vel frac 0x9a
            //0x02C4E6 - First Jump x-vel int, 0x01
            //0x02C4E7 - Second Jump x-vel int 0x01
            // Pick x-vel integers for both jumps first. Must add up to 2 or 3.
            int rSum = r.Next(2) + 2;
            int jump1x = r.Next(rSum + 1);
            int jump2x = rSum - jump1x;
            Patch.Add(0x02C4E6, (byte)jump1x, "Airman X-Velocity Integer Jump 1");
            Patch.Add(0x02C4E7, (byte)jump2x, "Airman X-Velocity Integer Jump 2");

            // If a jump's x-int is 0, its corresponding y-int must be 6-7
            // If a jump's x-int is 1, its corresponding y-int must be 4-7
            // If a jump's x-int is 2, its corresponding y-int must be 3-5
            // If a jump's x-int is 3, its corresponding y-int must be 2-4
            int jump1y = AirmanGetJumpYVelocity(jump1x, r);
            int jump2y = AirmanGetJumpYVelocity(jump2x, r);
            Patch.Add(0x02C4E0, (byte)jump1y, "Airman Y-Velocity Integer Jump 1");
            Patch.Add(0x02C4E1, (byte)jump2y, "Airman Y-Velocity Integer Jump 2");

            // Random x and y-vel fractions for both jumps
            //stream.Position = 0x02C4DD; // 1st jump y-vel frac
            rInt = r.Next(0xF1); // If jump is 7 and fraction is > 0xF0, Airman gets stuck!
            Patch.Add(0x02C4DD, (byte)rInt, "Airman Y-Velocity Fraction Jump 1");
            rInt = r.Next(0xF1);
            Patch.Add(0x02C4DE, (byte)rInt, "Airman Y-Velocity Fraction Jump 2");
            rInt = r.Next(256);
            Patch.Add(0x02C4E3, (byte)rInt, "Airman X-Velocity Fraction Jump 1");
            rInt = r.Next(256);
            Patch.Add(0x02C4E4, (byte)rInt, "Airman X-Velocity Fraction Jump 2");
        }
Пример #24
0
        private void RandomizeWeaponColors(Patch p, Random r)
        {
            // Create lists of possible colors to choose from and shuffle them
            List<byte> PossibleDarkColors = new List<byte>();
            List<byte> PossibleLightColors = new List<byte>();

            for (byte i = 0x01; i <= 0x0C; i++)
            {
                // Add first two rows of colors to dark list (except black/white/gray)
                PossibleDarkColors.Add(i);
                PossibleDarkColors.Add((byte)(i + 0x10));
                // Add third and fourth rows to light list (except black/white/gray)
                PossibleLightColors.Add((byte)(i + 0x20));
                PossibleLightColors.Add((byte)(i + 0x30));
            }
            // Add black and dark-gray to dark list, white and light-gray to light list
            PossibleDarkColors.Add(0x0F);
            PossibleDarkColors.Add(0x00);
            PossibleLightColors.Add(0x10);
            PossibleLightColors.Add(0x20);

            // Randomize lists, and pick the first 9 and 8 elements to use as new colors
            PossibleDarkColors.Shuffle(r);
            PossibleLightColors.Shuffle(r);
            Queue<byte> DarkColors = new Queue<byte>(PossibleDarkColors.GetRange(0, 9));
            Queue<byte> LightColors = new Queue<byte>(PossibleLightColors.GetRange(0, 8));

            // Get starting address depending on game version
            int startAddress = (RandomMM2.Settings.IsJapanese) ? MegaManColorAddressJ : MegaManColorAddressU;

            // Change 8 robot master weapon colors
            for (int i = 0; i < 8; i++)
            {
                byte dark = DarkColors.Dequeue();
                byte light = LightColors.Dequeue();

                int pos = startAddress + 0x04 + i * 0x04;
                p.Add(pos, light, String.Format("{0} Weapon Color Light", ((EDmgVsBoss.Offset)i).ToString()));
                p.Add(pos+1, dark, String.Format("{0} Weapon Color Dark", ((EDmgVsBoss.Offset)i).ToString()));

                if (i == 0)
                {
                    //0x03DE49 - H charge colors
                    //    0F 15 - flash neutral color (15 = weapon color)
                    //    31 15 - flash lv 1(outline only; keep 15 from weapon color)
                    //    35 2C - flash lv 2
                    //    30 30 - flash lv 3
                    p.Add(0x03DE4A, dark, "Heat Weapon Charge Color 1");
                    p.Add(0x03DE4C, dark, "Heat Weapon Charge Color 2");
                }
            }

            // Change 3 Item colors
            byte itemColor = DarkColors.Dequeue();
            for (int i = 0; i < 3; i++)
            {
                p.Add(startAddress + 0x25 + i * 0x04, itemColor, String.Format("Item {0} Dark Color", i+1));
            }
        }
Пример #25
0
        protected void ChangeWood(Patch Patch, Random r)
        {
            int rInt = 0;
            double rDbl = 0.0;
            byte[] xVels;

            // Woodman AI

            // Some unused addresses for later:
            //0x02C567 - Falling leaf y-pos start, 0x20
            //0x03DA34 - Leaf shield y-velocity while it's attached to woodman, lol.

            //0x02C537 - Delay between leaves 0x12. Do 0x06 to 0x20.
            rInt = r.Next(0x20 - 0x06 + 1) + 0x06;
            Patch.Add(0x02C537, (byte)rInt, "Woodman Leaf Spacing Delay");

            //0x02C5DD - Jump height, 0x04. Do 0x03 to 0x08.
            rInt = r.Next(0x08 - 0x03 + 1) + 0x03;
            Patch.Add(0x02C5DD, (byte)rInt, "Woodman Jump Y-Velocity");

            //0x02C5E2 - Jump distance, 0x01. Do 0x01 to 0x04.
            rInt = r.Next(0x04 - 0x01 + 1) + 0x01;
            Patch.Add(0x02C5E2, (byte)rInt, "Woodman Jump X-Velocity");

            //0x02C5A9 - Shield launch speed, 0x04. Do 0x01 to 0x08.
            rInt = r.Next(0x08 - 0x01 + 1) + 0x01;
            Patch.Add(0x02C5A9, (byte)rInt, "Woodman Shield Launch X-Velocity");

            //0x02C553 - Number of falling leaves, 0x03. Do 0x02 20% of the time.
            rDbl = r.NextDouble();
            if (rDbl > 0.8)
                Patch.Add(0x02C553, 0x02, "Woodman Falling Leaf Quantity");

            //0x02C576 - Falling leaf x-vel, 0x02. Do 0x01 or 0x02, but with a 10% chance for 0x00 and 10% for 0x03
            xVels = new byte[] {
                0x00,
                0x03,
                0x01,0x01,0x01,0x01,
                0x02,0x02,0x02,0x02,
            };
            rInt = r.Next(xVels.Length);
            Patch.Add(0x02C576, xVels[rInt], "Woodman Falling Leaf X-Velocity");

            //0x03D8F6 - 0x02, change to 0x06 for an interesting leaf shield pattern 25% of the time
            rDbl = r.NextDouble();
            if (rDbl > 0.66)
            {
                Patch.Add(0x03D8F6, 0x06, "Woodman Leaf Shield Pattern");
            }

            //0x03B855 - Leaf fall speed(sort of ?) 0x20.
            // Decrease value to increase speed. At 0x40, it doesn't fall.
            // 20% of the time, change to a high number to instantly despawn leaves for a fast pattern.
            // Do from 0x00 to 0x24.  Make less than 0x1A a lower chance.
            int yVel;
            rDbl = r.NextDouble();
            if (rDbl > 0.8)
            {
                yVel = 0xA0; // Leaves go upwards
            }
            else
            {
                xVels = new byte[]
                {
                    0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, // Fall faster
                    0x1D, 0x1E, 0x20, 0x21, 0x22, 0x23, 0x24        // Fall slower
                };
                rInt = r.Next(xVels.Length);
                yVel = xVels[rInt];
            }
            Patch.Add(0x03B855, (byte)yVel, "Woodman Falling Leaf Y-Velocity");
        }
Пример #26
0
        protected void ChangeQuick(Patch Patch, Random r)
        {
            // Q autofire delay, default 0x0B
            //    Do from 0x05 to 0x12
            int autoFireDelay = r.Next(0x0D) + 0x05;
            Patch.Add(0x03DB54, (byte)autoFireDelay, "(Q) | Autofire Delay");

            // Q max shots, default 0x05
            //    Do from 0x03 to 0x07(2 to 6 shots)
            int maxShots = r.Next(0x04) + 0x03;
            Patch.Add(0x03DB5C, (byte)maxShots, "(Q) | Max Shots");

            // 0x03DB6F - Q sound effect
            ESoundID sound = GetRandomSound(r);
            Patch.Add(0x03DB6F, (byte)sound, "(Q) | Sound");

            // Q shots per ammo tick, default 0x08
            //    Do from 0x04 to 0x0A ?
            int magSize = r.Next(0x06) + 0x04;
            Patch.Add(0x03DB78, (byte)magSize, "(Q) | Shots Per Ammo Tick");
            AmmoUsage.Add(1d / (double)magSize);

            // Q behavior, distance, default 0x12
            //    Do from 0x0A to 0x20 ?
            int distance = r.Next(0x16) + 0x0A;
            Patch.Add(0x03DFE2, (byte)distance, "(Q) | Travel Distance");

            // Q behavior, initial angle, default 0x4B
            //    Do from 0x00 to 0x60 ?
            int angle1 = r.Next(0x60);
            Patch.Add(0x03DFEA, (byte)angle1, "(Q) | Initial Angle");

            //0x03DFF2 - Q behavior, weird, default 0x00
            //    Don't use, but change to 0x01 for dumb effect

            // Q behavior, angle, default 0x40
            //    0x40 - (GOOD)Normal
            //    0x80 - (GOOD / HARD) Disappears(doesn't return)
            //    0x00 - (GOOD)Sine wave
            //    0x03 - (GOOD)Float downwards(interesting behavior when changing other byte)
            //    0x04, 05 - Float downwards(short, not different enough from 03)
            //    0x06 - Float downwards(faster)
            int[] angle2s = new int[] { 0x40, 0x80, 0x00, 0x03 };
            int rIndex = r.Next(angle2s.Length);
            int angle2 = angle2s[rIndex];
            Patch.Add(0x03DFFF, (byte)angle2, "(Q) | Secondary Angle");

            // Q behavior, time before disappearing on return, default 0x23
            //    Do from 0x1E to 0x30
            int despawnDelay = r.Next(0x12) + 0x1E;
            Patch.Add(0x03E007, (byte)despawnDelay, "(Q) | Despawn Delay");

            // Q behavior, return angle, default 0x4B
            //    Do from 0x00 to 0x90
            int angle3 = r.Next(0x90);
            Patch.Add(0x03E013, (byte)angle3, "(Q) | Return Angle");

            //0x03E01B - Q behavior, weird, default 0x00
            //    Change to 0x01 for interesting effects
        }
Пример #27
0
        public void Randomize(Patch p, Random r)
        {
            // Write in new weapon names
            for (int i = 0; i < 8; i++)
            {
                int offset = offsetAtomicFire + i * 0x10;

                string name = GetRandomName(r);
                char[] chars = name.ToCharArray();

                for (int j = 0; j < MAX_CHARS; j++)
                {
                    if (j < chars.Length)
                    {
                        byte b = Convert.ToByte(chars[j]);
                        p.Add(offset + j, b, String.Format("Weapon Name {0} Char #{1}: {2}", ((EDmgVsBoss.Offset)i).Name, j, chars[j].ToString()));

                    }
                    else
                    {
                        p.Add(offset + j, Convert.ToByte('@'), String.Format("Weapon Name {0} Char #{1}: @", ((EDmgVsBoss.Offset)i).Name, j));
                    }
                }
            }

            // Erase "Boomerang" for now
            for (int i = 0; i < 10; i++)
            {
                p.Add(0x037f5e + i, Convert.ToByte('@'), String.Format("Quick Boomerang Name Erase Char #{0}: @", i));
            }

            // Write in new weapon letters
            for (int i = 0; i < 8; i++)
            {
                int randLetter = 0x41 + r.Next(26);
                p.Add(offsetLetters + i, (byte)randLetter, String.Format("Weapon Get {0} Letter: {1}", ((EDmgVsBoss.Offset)i).Name, Convert.ToChar(randLetter).ToString()));
            }
        }
Пример #28
0
        protected void ChangeWood(Patch Patch, Random r)
        {
            //0x03DEDA - W deploy time (0C)
            //    Can change from 06 to 12
            //    Note: Shield glitches on odd numbers.  Use evens only.
            int[] deployDelays = new int[] {
                0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x10, 0x14, 0x1C, 0x22
            };
            int rIndex = r.Next(deployDelays.Length);
            int deployDelay = deployDelays[rIndex];
            Patch.Add(0x03DEDA, (byte)deployDelay, "(W) | Deploy Delay");

            //0x03DF0D - W spin animation? (01)

            //0x03DF1B - W delay between sounds(07)
            // TODO

            //0x03DF1F - W deploy sound effect
            ESoundID sound = GetRandomSound(r);
            Patch.Add(0x03DF1F, (byte)sound, "(W) | Deploy Sound");

            //0x03DF41 - W which directions the shield is allowed to launch in (F0)
            //    Can prevent launching left / right, up / down, etc

            //0x03DF4D - W launch directions (C0)
            //    Don't use this one

            //0x03DF50 - W launch x - direction subroutine
            //    50% chance to have inverted x controls
            //    Change "LSR AND #40" (4A 29 40) to simply "AND #40" to implement
            double rTestReverseX = r.NextDouble();
            if (rTestReverseX > 0.5)
            {
                Patch.Add(0x03DF50, 0x29, "(W) | Reverse X-Direction Code AND");
                Patch.Add(0x03DF51, 0x40, "(W) | Reverse X-Direction Code #$40");
                Patch.Add(0x03DF52, 0xEA, "(W) | Reverse X-Direction Code NOP"); // (best thing i could find to simply "skip" a line)
            }

            //0x03DF59 - W x - speed(04) (do 0x02-0x08)
            int launchVel = r.Next(0x06) + 0x02;
            Patch.Add(0x03DF59, (byte)launchVel, "(W) | Launch X-Velocity Integer");

            //0x03DF64 - W launch y - direction(10)
            //  Change to 0x20 to reverse, 50% chance
            int reverseY = 0x10;
            double rTestReverseY = r.NextDouble();
            if (rTestReverseY > 0.5)
                reverseY = 0x20;
            Patch.Add(0x03DF64, (byte)reverseY, "(W) | Launch Y-Direction");

            //0x03DF72 - W ammo usage (3) (do from 1 to 3)
            int ammoUse = r.Next(0x03) + 0x01;
            Patch.Add(0x03DF72, (byte)ammoUse, "(W) | Ammo Usage");
            AmmoUsage.Add(ammoUse);

            //0x03DF7D - W y - speed(04)
            Patch.Add(0x03DF7D, (byte)launchVel, "(W) | Launch Y-Velocity Integer");
        }
Пример #29
0
        private void RandomizeBossColors(Patch p, Random r)
        {
            //// Robot Master Color Palettes
            List<int> SolidColorSolo = new List<int>
            {
                0x00B4EA, // Wood leaf color 0x29
                0x01B4A1, // Metal blade color 0x30
            };

            List<int> SolidColorPair1Main = new List<int> {
                0x01F4ED, // Clash red color 0x16
                0x0174B7, // Flash blue color 0x12
                0x0074B4, // Air projectile blue color 0x11
                0x00B4ED, // Wood orange color 0x17
            };

            List<int> SolidColorPair1White = new List<int> {
                0x01F4EC, // Clash white color 0x30
                0x0174B6, // Flash white color 0x30
                0x0074B3, // Air projectile white color 0x30
                0x00B4EC, // Wood white color 0x36
            };

            List<int> SolidColorPair2Dark = new List<int> {
                0x0034B4, // Heat projectile red color 0x15
                0x0034B7, // Heat red color 0x15
                0x0074B7, // Air blue color 0x11
                0x0134C6, // Quick intro color 2 0x28
                0x0134C9, // Quick red color 0x15
                0x01B4A5, // Metal red color 0x15
                0x00F4B7, // Bubble green color 0x19
            };

            List<int> SolidColorPair2Light = new List<int> {
                0x0034B3, // Heat projectile yellow color 0x28
                0x0034B6, // Heat yellow color 0x28
                0x0074B6, // Air yellow color 0x28
                0x0134C5, // Quick intro color 1 0x30
                0x0134C8, // Quick yellow color 0x28
                0x01B4A4, // Metal yellow color 0x28
                0x00F4B6, // Bubble white & projectile color 0x30
            };

            // Colors for bosses with 1 solid color and 1 white
            List<byte> goodSolidColors = new List<byte>()
            {
                0x0F,0x20,0x31,0x22,0x03,0x23,0x14,0x05,0x15,0x16,0x07,0x27,0x28,0x09,0x1A,0x2A,0x0B,0x2B,0x0C,0x1C,
            };

            // Colors for bosses with a dark and a light color
            List<byte> goodDarkColors = new List<byte>()
            {
                0x01,0x12,0x03,0x04,0x05,0x16,0x07,0x18,0x09,0x1A,0x0B,0x0C,0x0F,0x00,
            };
            List<byte> goodLightColors = new List<byte>()
            {
                0x21,0x32,0x23,0x34,0x15,0x26,0x27,0x28,0x29,0x3A,0x1B,0x2C,0x10,0x20,
            };

            // Dark colors only
            List<byte> darkOnly = new List<byte>()
            {
                0x0F,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C
            };
            // Medium colors only
            List<byte> mediumOnly = new List<byte>()
            {
                0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C
            };
            // Light colors only
            List<byte> lightOnly = new List<byte>()
            {
                0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C
            };

            int rColor = 0;
            for (int i = 0; i < SolidColorSolo.Count; i++)
            {
                rColor = r.Next(goodSolidColors.Count);
                p.Add(SolidColorSolo[i], goodSolidColors[rColor], String.Format("Robot Master Color"));
            }

            for (int i = 0; i < SolidColorPair1Main.Count; i++)
            {
                p.Add(SolidColorPair1Main[i], goodSolidColors[rColor], String.Format("Robot Master Color"));

                // Make 2nd color brighter. If already bright, make white.
                rColor = r.Next(goodSolidColors.Count);
                int lightColor = goodSolidColors[rColor] + 0x10;
                if (lightColor > 0x3C)
                {
                    lightColor = 0x30;
                }
                p.Add(SolidColorPair1White[i], (byte)lightColor, String.Format("Robot Master Color"));
            }

            for (int i = 0; i < SolidColorPair2Dark.Count; i++)
            {
                rColor = r.Next(SolidColorPair2Dark.Count);
                p.Add(SolidColorPair2Dark[i], goodDarkColors[rColor], String.Format("Robot Master Color"));

                rColor = r.Next(SolidColorPair2Light.Count);
                p.Add(SolidColorPair2Light[i], goodLightColors[rColor], String.Format("Robot Master Color"));
            }

            // Wily Machine
            // choose main body color
            rColor = r.Next(darkOnly.Count);
            byte shade0 = darkOnly[rColor];
            byte shade1 = (byte)(shade0 + 0x10);
            if (shade0 == 0x0F)
                shade1 = 0x00; // Dark gray up from black
            byte shade2 = (byte)(shade1 + 0x10);

            p.Add(0x02D7D5, shade2, String.Format("Wily Machine Light-Gold Color")); // 0x27
            p.Add(0x02D7D2, shade1, String.Format("Wily Machine Gold 1 Color")); // 0x17
            p.Add(0x02D7D6, shade1, String.Format("Wily Machine Gold 2 Color")); // 0x17
            p.Add(0x02D7DA, shade1, String.Format("Wily Machine Gold 3 Color")); // 0x17
            p.Add(0x02D7D7, shade0, String.Format("Wily Machine Dark Gold 1 Color")); // 0x07
            p.Add(0x02D7DB, shade0, String.Format("Wily Machine Dark Gold 2 Color")); // 0x07

            // choose front color
            rColor = r.Next(mediumOnly.Count);
            shade0 = mediumOnly[rColor];
            shade1 = (byte)(shade0 + 0x20);

            p.Add(0x02D7D1, shade0, String.Format("Wily Machine Red 1 Color")); // 0x15
            p.Add(0x02D7D9, shade0, String.Format("Wily Machine Red 2 Color")); // 0x15
            p.Add(0x02D7D3, shade1, String.Format("Wily Machine Light Red 1 Color")); // 0x15

            // Alien
            //0x02DC74(3 bytes) Alien Body, static   0x16 0x29 0x19
            //0x02DC78(3 bytes) Alien Head, static   0x16 0x29 0x19
            // Looks good as 4 separate color groups, should be easy. Save the animations for later.
            List<byte> mediumAndLight = new List<byte>(mediumOnly);
            mediumAndLight.AddRange(lightOnly);

            rColor = r.Next(mediumAndLight.Count);
            shade0 = mediumAndLight[rColor];
            p.Add(0x02DC74, shade0, String.Format("Alien Body Solid Color"));

            rColor = r.Next(mediumAndLight.Count);
            shade1 = mediumAndLight[rColor];
            p.Add(0x02DC78, shade1, String.Format("Alien Head Solid Color"));

            rColor = r.Next(mediumOnly.Count);
            shade0 = mediumOnly[rColor];
            p.Add(0x02DC76, shade0, String.Format("Alien Body Dark Color"));

            shade1 = (byte)(shade0 + 0x10);
            p.Add(0x02DC75, shade1, String.Format("Alien Body Light Color"));

            rColor = r.Next(mediumOnly.Count);
            shade0 = mediumOnly[rColor];
            p.Add(0x02DC7A, shade0, String.Format("Alien Body Dark Color"));

            shade1 = (byte)(shade0 + 0x10);
            p.Add(0x02DC79, shade1, String.Format("Alien Head Light Color"));
        }
Пример #30
0
        /// <summary>
        /// Shuffle which Robot Master awards which weapon.
        /// </summary>
        public void Randomize(Patch Patch, Random r)
        {
            // StageBeat    Address    Value
            // -----------------------------
            // Heat Man     0x03C289   1
            // Air Man      0x03C28A   2
            // Wood Man     0x03C28B   4
            // Bubble Man   0x03C28C   8
            // Quick Man    0x03C28D   16
            // Flash Man    0x03C28E   32
            // Metal Man    0x03C28F   64
            // Crash Man    0x03C290   128
            NewWeaponOrder.Shuffle(r);

            // Create table for which weapon is awarded by which robot master
            // This also affects which portrait is blacked out on the stage select
            // This also affects which teleporter deactivates after defeating a Wily 5 refight boss
            for (int i = 0; i < 8; i++)
            {
                Patch.Add((int)(ERMStageWeaponAddress.HeatMan + i), (byte)NewWeaponOrder[i], String.Format("{0}man Weapon Get", ((EDmgVsBoss.Offset)i).ToString()));
            }

            // Create a copy of the default weapon order table to be used by teleporter function
            // This is needed to fix teleporters breaking from the new weapon order.
            // Unused space at end of bank
            Patch.Add(0x03f310, (byte)ERMWeaponValueBit.HeatMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f311, (byte)ERMWeaponValueBit.AirMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f312, (byte)ERMWeaponValueBit.WoodMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f313, (byte)ERMWeaponValueBit.BubbleMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f314, (byte)ERMWeaponValueBit.QuickMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f315, (byte)ERMWeaponValueBit.FlashMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f316, (byte)ERMWeaponValueBit.MetalMan, "Custom Array of Default Weapon Order");
            Patch.Add(0x03f317, (byte)ERMWeaponValueBit.CrashMan, "Custom Array of Default Weapon Order");

            // Change function to call $f300 instead of $c279 when looking up defeated refight boss to
            // get our default weapon table, fixing the teleporter softlock
            Patch.Add(0x03843b, 0x00, "Teleporter Fix Custom Function Call Byte 1");
            Patch.Add(0x03843c, 0xf3, "Teleporter Fix Custom Function Call Byte 2");

            // Create table for which stage is selectable on the stage select screen (independent of it being blacked out)
            for (int i = 0; i < 8; i++)
            {
                Patch.Add((int)(ERMStageSelect.FirstStageInMemory + i), (byte)NewWeaponOrder[i], "Selectable Stage Fix for Random Weapon Get");
            }
        }