Blazephlozard

ZZAZZ ACE

Apr 8th, 2021 (edited)
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.47 KB | None | 0 0
  1. I've never found ACE in a game before, but since the 2019 April Fools event, I HAD helped to craft / optimize the instruction sequence for Pokemon TCG1 and TCG2's ACE TASes, so I wanted to give it a try. But, I had to think of a logical entrypoint, because I wasn't going to just mess around trying to get something.
  2.  
  3. I found it very peculiar that the inventory had 40 slots, yet there's only 18 items in the game. You would need to collect at least 2200 items to actually reach that 40th slot... That sure sounds like a possible entrypoint!
  4.  
  5. Sure enough, through cheating stacks of 99, I found that the game performs no kind of check to prevent new item stacks from going past the intended inventory space. (In fact, if you open the item menu with 39 items, an underflow occurs that wipes 255 byte pairs past the inventory with FF 00, crashing the game. Luckily this crash doesn't happen if you don't open the menu and just keep gaining items!)
  6.  
  7. From here I thought that I would easily just reach some code, craft a sequence that perhaps places/runs into an E9 (jump to HL) when I have HL set to B882, or something. Unfortunately, just a few spots past the intended inventory, is code that's called every time an item is put into your inventory. Modifying this code is a big dead end as far as I can see; it starts with a quantity byte, and if it's set to 01, you'll crash upon gaining an item.
  8.  
  9. But the state that the inventory is in once you've gotten a 40th item still had potential. The inventory's "FF" terminator gets overwritten by something music-related, so you now have a gigantic inventory. Opening the items menu is prone to crashing still (due to writing FF 00s past the inventory's end), and you can't access items past slot 40 anyway, and shifting the memory down by freeing a slot would just crash, so using a glitch item was out of the question.
  10.  
  11. That left one odd quirk that I doubted would get me anywhere. When picking up an item, it would search through this extended inventory for an existing copy of the item. So, if there were any bytes between 01 and 12 getting read as an item ID, I could increase the byte afterwards up to a max of 99 (0x63). If it's higher than 99, it gets clamped back down to 99.
  12.  
  13. I made a list of the potential bytes I can increase, and stumbled upon the goldmine. The password generation code:
  14.  
  15. 21 C0 DA: load DAC0 into HL
  16. 0E 04: load 4 into C
  17. 11 D4 F9: load F9D4 into DE
  18. and then some password stuff
  19.  
  20. "04 11" is modifiable by picking up Reviver Seeds when you have a full inventory. If I get it up to 16, the code is now:
  21.  
  22. 21 C0 DA: load DAC0 into HL
  23. 0E 04: load 4 into C
  24. 16 D4: load D4 into D
  25. F9: load HL into the stack pointer
  26.  
  27. Oh my! The stack pointer is now at the password! And RIGHT before the password in memory is the game's seed!
  28.  
  29. Loading D4 into D also messes with the password generation in a useful way. In testing, with the Pikachu 100 HP achievement (which I knew I'd be getting), the start of the password is "C6C6", which ends up getting jumped to thanks to our new stack pointer.
  30.  
  31. This is at the tail end of on-screen map code, so I can manipulate the contents of it by moving around the map. This section of memory can contain opcode 3B in certain biomes, which decrements the stack pointer. After that block of memory, it runs into the current loaded map chunks, which can contain opcode 33, which increments the stack pointer.
  32.  
  33. I just need to decrement the stack pointer 6 times and I can jump to the last 2 bytes of the seed, which I can have set to the ACE address.
  34.  
  35. So, my plan of attack was surprisingly simple in the end:
  36.  
  37. 1. Get thousands of random drops from enemy encounters (note: this could be replaced by picking up thousands of ground items, if you're big brain enough to have the player path towards them)
  38. 2. Pick up 5 Reviver Seeds
  39. 3. Walk around until jumping to C6C6 would result in the stack pointer decrementing to the seed
  40. 4. Profit
  41.  
  42. ...I sure hope this wasn't the "intended" ACE method because that "thousands of random drops" part kinda sucks. But hey, empty input should compress pretty well into that 64 MB limit! Let's go!
  43.  
  44. ===
  45.  
  46. I went with a shockingly simple script for brute-forcing item drop encounters while making sure my health stays high:
  47.  
  48. 1. Walk into grass
  49. 2. Check the byte of "current encounter" for if it's what we need
  50. 3. Let the battle progress (that current encounter byte will get set back to 0)
  51. 4. Check if our health decreased too much, and that the last loaded "name" pointer is the item name pointer, rather than the pokemon name pointer
  52.  
  53. I check every 2 frames of walking into grass (it seemed like the encounters came in pairs). I feel like every part of this probably could be way smarter, because this probably works the same as the DSum manipulation stuff in regular Pokemon which is well-documented, but whatever...
  54.  
  55. I bruteforced to find rough item drop rates for all encounters. TMZ4 comes out far ahead with a 90% drop rate for Glitch Shards, so I find a Corruption biome ASAP. I was worried I'd get outclassed, but, TMZ4 is actually pathetically weak, and Pikachu's HP increases from level ups sustain him just fine.
  56.  
  57. ...Except, uh... If you attempt to get a 100th Glitch Shard, something changes about the game, and now fighting TMZ4 brings up MissingNo (despite being the same fight ID) and the game locks up. I feel like this might be some "intended ACE" shenanigans (is the 9999 map tile a hint?), but uh... I don't really care? I have my plan in mind, I don't want this. So, Shyhorns it is. (I tried cheating 99 Glitch Shards in BGB to try to see what's getting executed, but I didn't get this result at all...)
  58.  
  59. So, Shydons have a 50% chance of dropping Shyhorns, and I think they're a more frequent encounter than TMZ4 was! Not bad at all!
  60.  
  61. I ran into a hiccup at the end of my first stack; the game wouldn't make a new one if the x99 stack is at the end of the item list. Since Nidorinos drop Skip Sandwiches here, an item that can be used at any time with no restriction, I added code that eats my one Skip every 99 battles, then gets a new one before continuing with the Shyhorn grind. This code is very inefficient; I should be eating the Skip as soon as my new stack is started, and start the new Skip stack any time; but that would be harder to keep track of! It was bed time... I'm lucky I noticed this issue soon enough to fix it at all.
  62.  
  63. Waking up, I knew that I had a major speed bottleneck to handle. Loading/saving state includes the movie input, which is gigantic now. Checking every frame of walking and denying useless fights was no longer viable, so I switched to pacing back and forth and accepting all fights except Snorlaxes that give Reviver Seeds. (If I get 1, I need to get 98 more...)
  64.  
  65. This adds a LOT more movie length but greatly sped up IRL time (like, 10x). Also the new stack bug(?) seems to have stopped so I didn't need to worry about Skips anymore.
  66.  
  67. ...Oh, it adds a LOT LOT more movie length. 64 hours? Oops... I think this LOTAD just became a LOMBRE.
  68.  
  69. Unfortunately, my initial plan was a failure, because I didn't realize the first byte of the password is determined by your play time in minutes, maxing out at 255. I no longer had access to a C4C4 jump. I spent the day learning the ins and outs of the password generating, and found a new path to victory.
  70.  
  71. I couldn't jump to map data anymore, but I could jump to a jump to an echo of the map data! I had a secret trick up my sleeve; if I collect a Bravery Potion, it increases another byte of the password creation, which leaves behind a "decrement stack pointer" opcode. This gives me full control of the 2nd byte of where we jump to. My 1st byte options were limited but I found B0ED: call nz E211
  72.  
  73. I can jump to B0xx using 0x36 Reviver Seeds with the 100 HP and Daredevil Potion achievements. Then I just need to find a map chunk which leaves the second map seed ending in ED, with tiles that let me decrement the stack. Construct's pegs seem to do the job.
  74.  
  75. So, the new plan of attack was:
  76.  
  77. 1. Get thousands of random drops from enemy encounters
  78. 2. Fight Scyther with Daredevil Potion
  79. 3. Reach 40 items in inventory
  80. 4. Pick up 37 Reviver Seeds and 1 Bravery Potion
  81. 5. Walk to a Construct map chunk that leaves the RNG state ending in 0xED
  82. 6. Profit
  83.  
  84. Nothing funny happened this time, I'd learned the ins and outs of the method I'm using and I'm so happy that I was able to make my quantity-increasing exploit work.
  85.  
  86. I need to finish Challenge 3 (which I've been very slowly brute-forcing in BizHawk...) and then maybe I'll try to have this not take 64 hours...
  87.  
  88.  
Add Comment
Please, Sign In to add comment