From 175ec21f7b5983a3bb472953c2119af9e3b69f39 Mon Sep 17 00:00:00 2001 From: tom-overton Date: Thu, 22 Dec 2022 22:37:02 -0800 Subject: Gen 5: Fix Shedinja evo crashing on Bizhawk/real hardware --- .../sneed/pkrandom/romhandlers/Gen4RomHandler.java | 13 ++-- .../sneed/pkrandom/romhandlers/Gen5RomHandler.java | 69 ++++++++-------------- 2 files changed, 31 insertions(+), 51 deletions(-) (limited to 'src/com/sneed/pkrandom/romhandlers') diff --git a/src/com/sneed/pkrandom/romhandlers/Gen4RomHandler.java b/src/com/sneed/pkrandom/romhandlers/Gen4RomHandler.java index 56b0147..8a936ec 100755 --- a/src/com/sneed/pkrandom/romhandlers/Gen4RomHandler.java +++ b/src/com/sneed/pkrandom/romhandlers/Gen4RomHandler.java @@ -539,6 +539,12 @@ public class Gen4RomHandler extends AbstractDSRomHandler { (romEntry.romType == Gen4Constants.Type_Plat && romEntry.tweakFiles.containsKey("NewRoamerSubroutineTweak")) || (romEntry.romType == Gen4Constants.Type_HGSS && romEntry.tweakFiles.containsKey("NewRoamerSubroutineTweak")); + try { + computeCRC32sForRom(); + } catch (IOException e) { + throw new RandomizerIOException(e); + } + // We want to guarantee that the catching tutorial in HGSS has Ethan/Lyra's new Pokemon. We also // want to allow the option of randomizing the enemy Pokemon too. Unfortunately, the latter can // occur *before* the former, but there's no guarantee that it will even happen. Since we *know* @@ -548,12 +554,6 @@ public class Gen4RomHandler extends AbstractDSRomHandler { arm9 = extendARM9(arm9, extendBy, romEntry.getString("TCMCopyingPrefix"), Gen4Constants.arm9Offset); genericIPSPatch(arm9, "NewCatchingTutorialSubroutineTweak"); } - - try { - computeCRC32sForRom(); - } catch (IOException e) { - throw new RandomizerIOException(e); - } } private void loadMoves() { @@ -5660,6 +5660,7 @@ public class Gen4RomHandler extends AbstractDSRomHandler { @Override public boolean isRomValid() { if (romEntry.arm9ExpectedCRC32 != actualArm9CRC32) { + System.out.println(actualArm9CRC32); return false; } diff --git a/src/com/sneed/pkrandom/romhandlers/Gen5RomHandler.java b/src/com/sneed/pkrandom/romhandlers/Gen5RomHandler.java index 58fe224..242b2ca 100755 --- a/src/com/sneed/pkrandom/romhandlers/Gen5RomHandler.java +++ b/src/com/sneed/pkrandom/romhandlers/Gen5RomHandler.java @@ -478,6 +478,13 @@ public class Gen5RomHandler extends AbstractDSRomHandler { } catch (IOException e) { throw new RandomizerIOException(e); } + + // If there are tweaks for expanding the ARM9, do it here to keep it simple. + boolean shouldExtendARM9 = romEntry.tweakFiles.containsKey("ShedinjaEvolutionTweak") || romEntry.tweakFiles.containsKey("NewIndexToMusicTweak"); + if (shouldExtendARM9) { + int extendBy = romEntry.getInt("Arm9ExtensionSize"); + arm9 = extendARM9(arm9, extendBy, romEntry.getString("TCMCopyingPrefix"), Gen5Constants.arm9Offset); + } } private void loadPokemonStats() { @@ -1977,8 +1984,7 @@ public class Gen5RomHandler extends AbstractDSRomHandler { e.printStackTrace(); } - int extendBy = romEntry.getInt("NewIndexToMusicSize"); - arm9 = extendARM9(arm9, extendBy, romEntry.getString("TCMCopyingPrefix"), Gen5Constants.arm9Offset); + // Relies on arm9 already being extended, which it *should* have been in loadedROM genericIPSPatch(arm9, "NewIndexToMusicTweak"); String newIndexToMusicPrefix = romEntry.getString("NewIndexToMusicPrefix"); @@ -2510,13 +2516,12 @@ public class Gen5RomHandler extends AbstractDSRomHandler { // set on the save file. If it isn't, the code branches to a separate code path // where the function returns 0. The below code simply nops this branch so that // this function always returns 1, regardless of the status of flag 2403. - int fieldOverlayNumber = Gen5Constants.getFieldOverlayNumber(romEntry.romType); - byte[] fieldOverlay = readOverlay(fieldOverlayNumber); + byte[] fieldOverlay = readOverlay(romEntry.getInt("FieldOvlNumber")); String prefix = Gen5Constants.runningShoesPrefix; int offset = find(fieldOverlay, prefix); if (offset != 0) { writeWord(fieldOverlay, offset, 0); - writeOverlay(fieldOverlayNumber, fieldOverlay); + writeOverlay(romEntry.getInt("FieldOvlNumber"), fieldOverlay); } } catch (IOException e) { throw new RandomizerIOException(e); @@ -3051,7 +3056,7 @@ public class Gen5RomHandler extends AbstractDSRomHandler { for (int i = 1; i <= Gen5Constants.pokemonCount; i++) { byte[] evoEntry = evoNARC.files.get(i); Pokemon pk = pokes[i]; - if (pk.number == Species.nincada) { + if (pk.number == Species.nincada && romEntry.tweakFiles.containsKey("ShedinjaEvolutionTweak")) { writeShedinjaEvolution(); } int evosWritten = 0; @@ -3087,48 +3092,22 @@ public class Gen5RomHandler extends AbstractDSRomHandler { if (nincada.evolutionsFrom.size() < 2) { return; } + Pokemon extraEvolution = nincada.evolutionsFrom.get(1).to; - // In all the Gen 5 games, the evolution overlay is hardcoded to generate - // a Shedinja by loading its species ID using the following instructions: - // mov r1, #0x49 - // lsl r1, r1, #2 - // Since Gen 5 has more than 510 species, we cannot use 8-bit addition to - // load any Pokemon; instead, we nop out a useless load of a string, then - // use the space that used to store the address of that string to instead - // store Nincada's new extra evolution's species ID. + // Update the evolution overlay to point towards our custom code in the expanded arm9. byte[] evolutionOverlay = readOverlay(romEntry.getInt("EvolutionOvlNumber")); - int functionOffset = find(evolutionOverlay, Gen5Constants.shedinjaFunctionLocator); - if (functionOffset > 0) { - int[] patchOffsets = romEntry.arrayEntries.get("ShedinjaCodePatchOffsets"); - - // First, nop the instruction that loads a pointer to the string - // "shinka_demo.c" into a register; this has seemingly no effect on - // the game and was probably used strictly for debugging. - evolutionOverlay[functionOffset + patchOffsets[0]] = 0x00; - evolutionOverlay[functionOffset + patchOffsets[0] + 1] = 0x00; - - // In the space that used to hold the address of the "shinka_demo.c" string, - // we're going to instead store a species ID. We need to write a pc-relative - // load to that space. However, the original Shedinja instructions are - // misaligned to do a load; there's an "add r0, r4, #0x0" between the move - // and the shift that is correctly-aligned. So we first move this add up one - // instruction, then we write out the load ("ldr r1, [pc #pcRelativeOffset]") - // in the correctly-aligned space, then we nop out the shift. - int pcRelativeOffset = patchOffsets[2] - patchOffsets[1] - 6; - evolutionOverlay[functionOffset + patchOffsets[1]] = 0x20; - evolutionOverlay[functionOffset + patchOffsets[1] + 1] = 0x1c; - evolutionOverlay[functionOffset + patchOffsets[1] + 2] = (byte) (pcRelativeOffset / 4); - evolutionOverlay[functionOffset + patchOffsets[1] + 3] = 0x49; - evolutionOverlay[functionOffset + patchOffsets[1] + 4] = 0x00; - evolutionOverlay[functionOffset + patchOffsets[1] + 5] = 0x00; - - // Finally, we replace what used to store the address of "shinka_demo.c" - // with the species ID of Nincada's new extra evolution. - int newSpeciesIDOffset = functionOffset + patchOffsets[2]; - FileFunctions.writeFullInt(evolutionOverlay, newSpeciesIDOffset, extraEvolution.number); - - writeOverlay(romEntry.getInt("EvolutionOvlNumber"), evolutionOverlay); + genericIPSPatch(evolutionOverlay, "ShedinjaEvolutionOvlTweak"); + writeOverlay(romEntry.getInt("EvolutionOvlNumber"), evolutionOverlay); + + // Relies on arm9 already being extended, which it *should* have been in loadedROM + genericIPSPatch(arm9, "ShedinjaEvolutionTweak"); + + // After applying the tweak, Shedinja's ID is simply pc-relative loaded, so just + // update the constant + int offset = romEntry.getInt("ShedinjaSpeciesOffset"); + if (offset > 0) { + FileFunctions.writeFullInt(arm9, offset, extraEvolution.number); } } -- cgit v1.2.3