public void try_decompres_recomp_decomp_overworld(byte[] originalCompressed, byte[] expectedDecompress) { int compsize = 0; var decompressed = Decompress.ALTTPDecompressOverworld(originalCompressed, 0, originalCompressed.Length, ref compsize); int i = 0; while (i < expectedDecompress.Length && i < decompressed.Length) { if (expectedDecompress[i] != decompressed[i]) { output.WriteLine($"mismatch at {i}, expected: {expectedDecompress[i].ToString("X2")} decompressed: {decompressed[i].ToString("X2")}"); } i++; } Assert.Equal(expectedDecompress, decompressed); // recompress var recomp = Compress.ALTTPCompressOverworld(decompressed, 0, decompressed.Length); bool same = false; try { i = 0; while (i < originalCompressed.Length && i < recomp.Length) { if (originalCompressed[i] != recomp[i]) { output.WriteLine($"recompress mismatch at {i}, expected: {originalCompressed[i].ToString("X2")} recomp: {recomp[i].ToString("X2")}"); } i++; } Assert.Equal(originalCompressed, recomp); same = true; } catch (Exception ex) { same = false; } output.WriteLine($"recompress is same as original compresssed? {same}"); decompressed = Decompress.ALTTPDecompressOverworld(recomp, 0, recomp.Length, ref compsize); i = 0; while (i < expectedDecompress.Length && i < decompressed.Length) { if (expectedDecompress[i] != decompressed[i]) { output.WriteLine($"mismatch at {i}, expected: {expectedDecompress[i].ToString("X2")} decompressed: {decompressed[i].ToString("X2")}"); } i++; } Assert.Equal(expectedDecompress, decompressed); }
static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("Enter the seed name too."); return; } //todo better (or any lol) file checking string fileName = args[0]; //string fileName = "test0.sfc"; byte[] data = File.ReadAllBytes(fileName); int table_address = 0x27ce0; int c_table_length = 799; Random rnd = new Random(); string spoiler = ""; // decompress the enemy damage table from the ROM (thanks Zarby) int f = 0; byte[] sdata = Decompress.ALTTPDecompressOverworld(data, 0x27ce0, c_table_length, ref f); byte[] udata = new byte[3000]; byte[] enemy_table = new byte[5000]; // expanding the array (unsure if needed) for (int i = 0; i < udata.Length; i++) { if (i < sdata.Length) { udata[i] = sdata[i]; } else { udata[i] = 0; } } // split bytes for (int i = 0; i < 5000; i += 2) { enemy_table[i] = (byte)(udata[i / 2] >> 4); enemy_table[i + 1] = (byte)(udata[i / 2] & 0x0F); } // normalize the enemy damage table byte[] new_enemy_table = Enemy_Table_Setup(enemy_table); // recombine bytes byte[] combined_table = new byte[2048]; for (int i = 0; i < 2048; i += 1) { combined_table[i] = (byte)((new_enemy_table[(i * 2)] << 4) | new_enemy_table[(i * 2) + 1]); } // recompress table byte[] compressed_enemy_table = Compress.ALTTPCompressOverworld(combined_table, 0, combined_table.Length); // write table to ROM data - table cannot exceed 799 bytes length for (int i = 0; (i < c_table_length & i < compressed_enemy_table.Length); i++) { data[table_address + i] = compressed_enemy_table[i]; } // create new damage table and write to ROM data byte[] new_damage_table = Create_Damage_Table(); int damage_table_address = 0x6B8F1; for (int i = 0; i < 128; i++) { data[damage_table_address + i] = new_damage_table[i]; } // write spoiler info string[] weaponClassNames = new string[] { "Boomerang", "Level 1", "Level 2", "Level 3", "Level 4", "Level 5", "Bow", "Hookshot", "Bombs", "Silvers", "Powder", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake" }; for (int i = 0; i < 16; i++) { spoiler += weaponClassNames[i] + ": " + Convert.ToString(new_damage_table[i * 8 + 1]) + "\r\n"; } // randomize powder fairy prize int fairy_address = 0x36DD0; // fairy, bees, appl, fish, heart, $5, $20, bomb, magic byte[] fairy_options = new byte[] { 0xE3, 0x79, 0xAC, 0xD2, 0xD8, 0xDA, 0xDB, 0xDC, 0xDF }; data[fairy_address] = fairy_options[rnd.Next(fairy_options.Length)]; spoiler += "Fairy prize: " + Convert.ToString(data[fairy_address] + "\r\n"); // randomize bomb timers lol int bomb_timer_address = 0x41543; // write fuse timer to ROM, first byte - setting to 00 causes max timer data[bomb_timer_address] = (byte)(rnd.Next(254) + 1); spoiler += "Bomb timers: " + Convert.ToString(data[bomb_timer_address]) + ", "; // bomb explosion speed is next 10 bytes byte[,] rates = new byte[, ] { { 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02 }, // fastest { 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03 }, // double speed { 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06 }, // default { 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0C, 0x0C, 0x0C }, // half speed { 0x18, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x18, 0x18, 0x18, 0x18 }, // quarter speed lol // repeat 'moderate' ones to increase weight { 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03 }, // double speed { 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06 }, // default { 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0C, 0x0C, 0x0C }, // half speed // repeat default again for most weight { 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06 } }; // default // choose one of the 9 rows int row = rnd.Next(9); // write to ROM for (int i = 0; i < 10; i++) { data[bomb_timer_address + i + 1] = rates[row, i]; spoiler += Convert.ToString(rates[row, i]) + " "; } spoiler += "\r\n"; File.WriteAllText("wpn_" + fileName + ".txt", spoiler); FileStream fs = new FileStream("wpn_" + fileName, FileMode.CreateNew, FileAccess.Write); fs.Write(data, 0, data.Length); fs.Close(); }