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)"); }
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"); }
/// <summary> /// Get a random unique sound for a weapon to use /// </summary> /// <param name="r"></param> /// <returns>Sound ID byte</returns> private ESoundID GetRandomSound(Random r) { int i = r.Next(sounds.Count); ESoundID sound = sounds.ElementAt(i); sounds.RemoveAt(i); // Pick a random charge level if charge sound is chosen if (sound == ESoundID.WeaponH_Charge0) { i = r.Next(3); sound = ESoundID.WeaponH_Charge0 + i; } return(sound); }
/// <summary> /// Get a random unique sound for a weapon to use /// </summary> /// <param name="r"></param> /// <returns>Sound ID Byte</returns> private ESoundID GetRandomSound(ISeed in_Seed) { Int32 i = in_Seed.NextInt32(sounds.Count); ESoundID sound = sounds.ElementAt(i); sounds.RemoveAt(i); // Pick a random charge level if charge sound is chosen if (sound == ESoundID.WeaponH_Charge0) { i = in_Seed.NextInt32(3); sound = ESoundID.WeaponH_Charge0 + i; } return(sound); }
protected void ChangeMetal(Patch Patch, Random r) { //0x03DBB6 - M max shots (04) (change to 0x02-0x05, or 1-4) int maxShots = r.Next(0x04) + 0x02; Patch.Add(0x03DBB6, (byte)maxShots, "(M) | Max Shots"); //0x03DBC9 - M sound effect(23) ESoundID sound = GetRandomSound(r); Patch.Add(0x03DBC9, (byte)sound, "(M) | Sound"); //0x03DBD2 - M shots per ammo tick(04) (change to 1-5) int magSize = r.Next(0x05) + 0x01; Patch.Add(0x03DBD2, (byte)magSize, "(M) | Shots Per Ammo Tick"); AmmoUsage.Add(1d / magSize); // Speeds. Change each to be 2-7. Diagonal will be half each, rounded up. int velX = r.Next(0x06) + 0x02; int velY = r.Next(0x06) + 0x02; int halfY = (int)Math.Ceiling((double)velY / 2d); int halfX = (int)Math.Ceiling((double)velX / 2d); //0x03DC12 - M y - speed, holding up(04) Patch.Add(0x03DC12, (byte)velY, "(M) | Y-Velocity Up"); //0x03DC31 - M x - speed, no direction(04) Patch.Add(0x03DC31, (byte)velX, "(M) | X-Velocity Neutral"); //0x03DC35 - M x - speed, holding left(04) Patch.Add(0x03DC35, (byte)velX, "(M) | X-Velocity Left"); //0x03DC39 - M x - speed, holding right(04) Patch.Add(0x03DC39, (byte)velX, "(M) | X-Velocity Right"); //0x03DC13 - M y - speed, holding down(FC) Patch.Add(0x03DC13, (byte)(0x00 - (byte)velY), "(M) | Y-Velocity Down"); //0x03DC16 - M y - speed, holding up + left(02) Patch.Add(0x03DC16, (byte)halfY, "(M) | Y-Velocity Up+Left"); //0x03DC17 - M y - speed, holding down + left(FD) Patch.Add(0x03DC17, (byte)(0x00 - (byte)halfY), "(M) | Y-Velocity Down+Left"); //0x03DC1A - M y - speed, holding up + right(02) Patch.Add(0x03DC1A, (byte)halfY, "(M) | Y-Velocity Up+Right"); //0x03DC1B - M y - speed, holding down + right(FD) Patch.Add(0x03DC1B, (byte)(0x00 - (byte)halfY), "(M) | Y-Velocity Down+Right"); //0x03DC36 - M x - speed, holding up + left(02) Patch.Add(0x03DC36, (byte)halfX, "(M) | X-Velocity Up+Left"); //0x03DC37 - M x - speed, holding down + left(02) Patch.Add(0x03DC37, (byte)halfX, "(M) | X-Velocity Down+Left"); //0x03DC3A - M x - speed, holding up + right(02) Patch.Add(0x03DC3A, (byte)halfX, "(M) | X-Velocity Up+Right"); //0x03DC3B - M x - speed, holding down + right(02) Patch.Add(0x03DC3B, (byte)halfX, "(M) | X-Velocity Down+Right"); }
protected void ChangeFlash(Patch Patch, Random r) { //0x03DC59 - F sound (21) ESoundID sound = GetRandomSound(r); Patch.Add(0x03DC59, (byte)sound, "(F) | Sound"); //0x03E172 - F custom subroutine for reusable weapon // 75% chance to occur double rTestFChange = r.NextDouble(); if (rTestFChange > 0.25) { // 0x03E175 - New ammo-usage address. byte[] ammos = new byte[] { 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; int rIndex = r.Next(7); byte ammo = ammos[rIndex]; // Change ammo-tick subroutine into one that resumes time byte[] sub = new byte[] { 0xA5, 0xA1, // LDA ammoFlash = #$0A 0xE9, ammo, // SBC {ammo use} 0x85, 0xA1, // STA ammoFlash = #$0A 0x5E, 0x20, 0x04, // LSR megaXDir, X @ megaXDir = #$C0 0xA9, 0x00, // LDA #$00 0x85, 0xAA, // STA $00AA = #$00 0x85, 0x50, // STA $0050 = #$00 ; we erased LDA #$01, but doesn't seem to hurt }; for (int i = 0; i < sub.Length; i++) { Patch.Add(0x03E172 + i, sub[i], "(F) | Reusable Time-Stopper Subroutine"); } // 0x03E16E and 0x03D49D is the new duration, in frames. They must both be the same value. int duration = 0x01; switch (ammo) { case 0x02: duration = r.Next(70) + 20; break; case 0x03: duration = r.Next(60) + 40; break; case 0x04: duration = r.Next(60) + 60; break; case 0x05: duration = r.Next(60) + 80; break; case 0x06: duration = r.Next(60) + 100; break; case 0x07: duration = r.Next(85) + 120; break; case 0x08: duration = r.Next(115) + 140; break; default: break; } Patch.Add(0x03E16E, (byte)duration, "(F) | Freeze Duration (1)"); Patch.Add(0x03D49D, (byte)duration, "(F) | Freeze Duration (2)"); // Finally, a fix is needed to prevent ammo underflow // 0x03DC41 - WpnMove_FStart sub = new byte[] { 0xA2, 0x02, // LDX #$02 0xAD, 0x22, 0x04, // LDA $0422 = #$61 0x30, 0x1E, // BMI WpnMove_Done 0xA5, 0xA1, // LDA ammoFlash = #$02 0xC9, 0x07, // CMP #$07 0x90, 0x18, // BCC WpnMove_Done }; for (int i = 0; i < sub.Length; i++) { Patch.Add(0x03DC41 + i, sub[i], "(F) | Reusable Time-Stopper Ammo-Underflow Fix"); } } else { // Standard Time Stopper, but modify the tick frequency // Default 0x0F. For 28 ticks, that's 7 seconds. Modify to be 4-10 seconds, which is about 0x09 to 0x16 int tickDelay = r.Next(0x13) + 9; Patch.Add(0x03E16E, (byte)tickDelay, "(F) | Time-Stopper Ammo Tick Delay (1)"); Patch.Add(0x03D49D, (byte)tickDelay, "(F) | Time-Stopper Ammo Tick Delay (2)"); } }
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 }
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"); }
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)); } }
protected void ChangeHeat(Patch Patch, Random r) { //0x03DE55 - H L1 Ammo use(01) //0x03DE56 - H L2 Ammo use(06) //0x03DE57 - H L3 Ammo use(0A) // 90% chance for L1 to be free, else cost 1 ammo // L2 ammo cost = L1 ammo cost // L3 will cost 1-4 ammo double rTestL1Ammo = r.NextDouble(); byte L1Ammo = (rTestL1Ammo > 0.1) ? (byte)0 : (byte)1; Patch.Add(0x03DE55, L1Ammo, $"(H) | Shot L1 Ammo Cost: {L1Ammo}"); Patch.Add(0x03DE56, L1Ammo, $"(H) | Shot L2 Ammo Cost: {L1Ammo}"); byte[] bytes = new byte[] { 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, }; int rInt = r.Next(bytes.Length); Patch.Add(0x03DE57, bytes[rInt], $"(H) | Shot L3 Ammo Cost: {bytes[rInt]}"); AmmoUsage.Add(bytes[rInt]); // Charge Behavior // 20% to have old charge behavior, 40% to skip 1 level, 40% to shoot L3 immediately double rTestChargeType = r.NextDouble(); //0x03DD66 - H change these 4 bytes to 0xEA to skip L2 charge if (rTestChargeType < 0.8) { for (int i = 0; i < 4; i++) { Patch.Add(0x03DD66 + i, 0xEA, $"(H) | Skip L2 Charge"); } } //0x03DD62 - H after doing the previous, change these 2 bytes to 0xEA to skip charge altogether if (rTestChargeType < 0.4) { Patch.Add(0x03DD62, 0xEA, $"(H) | Skip L1 Charge"); Patch.Add(0x03DD63, 0xEA, $"(H) | Skip L1 Charge"); //0x03DD95 - H change this from 0x0D to 0x14 to fire the charge on press instead of on release Patch.Add(0x03DD95, 0x14, $"(H) | Fire Shot On Press"); } // Charge delay for L2 will be between 0x10 and 0x80 frames //0x03DD61 - H L2 charge delay (0x7D) int chargeDelayL2 = r.Next(0x70) + 0x09; Patch.Add(0x03DD61, (byte)chargeDelayL2, "(H) | L2 Charge Delay"); // Charge delay for L3 will L2 plus a value between 0x10 and 0x40 frames //0x03DD67 - H L3 charge delay(0xBB) int chargeDelayL3 = r.Next(0x30) + 0x09 + chargeDelayL2; if (rTestChargeType >= 0.8) { Patch.Add(0x03DD67, (byte)chargeDelayL3, "(H) | L3 Charge Delay"); } //0x03DDEC - H shot sound effect(38) ESoundID sound = GetRandomSound(r); Patch.Add(0x03DDEC, (byte)sound, "(H) | Shot Sound"); //0x03DDF1 - H x - speed (04, all levels) // Do from 02 to 08 int xVel = r.Next(0x07) + 0x02; Patch.Add(0x03DDF1, (byte)xVel, "(H) | X-Velocity"); //0x03DE45 - H charge sound 1(35) Unused //0x03DE46 - H charge sound 2(35) sound = GetRandomSound(r); Patch.Add(0x03DE46, (byte)sound, "(H) | L1 Sound"); //0x03DE47 - H charge sound 3(36) sound = GetRandomSound(r); Patch.Add(0x03DE47, (byte)sound, "(H) | L2 Sound"); //0x03DE48 - H charge sound 4(37) sound = GetRandomSound(r); Patch.Add(0x03DE48, (byte)sound, "(H) | L3 Sound"); }