Hacking New Classic Controller Hacks

  • Thread starter Thread starter Vague Rant
  • Start date Start date
  • Views Views 244,594
  • Replies Replies 687
  • Likes Likes 42
Amazing work!
I have a question: is it possible to remap the analog triggers from the classic controller to the classic controller pro? Because, for example, DBZ BT3 has that issue when using the classic controller pro. It would be amazing if it had a layout similar to the PS2. It's just a question! ty
 
  • Like
Reactions: Vague Rant
While we're on the subject of fluids ...

Blue Tongue's de Blob was one of the few third-party Wii games to really break through Nintendo's commercial domination of the console. The fact that they managed to do so on Nintendo's home turf, the 3D platformer, makes that all the more impressive. With its environment-painting gameplay sometimes compared at launch to Super Mario Sunshine, in the years since, parallels have also been drawn to Splatoon, putting this game in some pretty good company. That said, once you got past the wildly creative gameplay, visuals and soundtrack, there was one major criticism: the poor use of motion controls. Players had to shake the Wiimote to jump, in a platformer. While this would be fixed in the excellent sequel, the original de Blob had to wait for HD ports on later consoles to get a jump button. Let's rectify that oversight.

I've read nothing but good things about this game. I've never tried it because of the controls, so thanks for sharing your code!
 
  • Like
Reactions: Vague Rant
@Vague Rant Could you also make a short tutorial for wii disc games like for the wads please? I mean you already did it partially on the first page, but I don't know the first steps like extracting the original control code out of a main.dol to modify it. Is there a command line for that or what program are you using? There are a lot of nerds and geeks on gbatemp who would like to participate in that cc hacking project and maybe in some years it will be possible to play all Wii games with a cc hack. That would be really great. I would also like to get deeper in that topic. So your tutorial would be a big help. Thanks a lot
To be honest, it wouldn't really be a short tutorial as it's a pretty involved process, but the next game I attempt, I'll document it as I go. There's no apps to modify games like this, I'm just digging into the assembly code and writing and inserting my own routines which reroute the KPAD data into different fields and stuff like that. The main Gecko code type these hacks are made up of are C2 codes, which are assembly insertion rather than in-place modifications, i.e. they're not so much editing the controls in the main.dol as they are adding new code to each game that didn't exist before so that it behaves differently.

Weren't there also hacks that enabled the Classic Controller for the Mario Galaxy games? I didn't see them listed here
Yep, there are Classic Controller hacks for both Mario Galaxy games by Super Hackio. This thread isn't a list of all Classic Controller hacks, these are just the ones that I've made personally. The others that I'm aware of are crediar's Donkey Kong Country Returns and Kirby's Return to Dreamland, Thomas83Lin's Rune Factory: Tides of Destiny and New Super Mario Bros. Wii, and the aforementioned Mario Galaxy hacks.

Amazing work!
I have a question: is it possible to remap the analog triggers from the classic controller to the classic controller pro? Because, for example, DBZ BT3 has that issue when using the classic controller pro. It would be amazing if it had a layout similar to the PS2. It's just a question! ty
I don't know, that sounds pretty much impossible to me.



new-hero.png

Dragon Ball Z: Budokai Tenkaichi 3 is the third entry in Spike's fighting game series based on the hit manga and anime by the late Akira Toriyama. Tenkaichi 3 is a deep dive into the lore and history of the Dragon Ball Z franchise, with a roster of 98 unique characters in 161 different forms, the largest ever fighting game roster at the time. Though hugely popular and successful, the Tenkaichi series would lie dormant for 17 years after the release of this game, until the fourth entry released *checks watch* ... yesterday.

This is technically a Classic Controller hack, but Tenkaichi 3 always supported the Classic Controller. The issue, as noted by @Alepss, is that the game was developed around the original Classic Controller and its analog shoulder buttons, which were removed in the Pro revision. This hack instead replicates the PlayStation 2 control scheme, where aerial controls are on R1/R2 (Classic R/ZR), with double-taps triggering the equivalent of a full analog button press.

USAUSA (Rev 1)EuropeJapanJapan (Rev 1)

  1. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2258EAC 00000002
    801E0000 70000100
    60000000 00000000
    C2259578 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  2. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2259A7C 00000002
    801E0000 70000100
    60000000 00000000
    C225A148 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  3. Code:
    Classic Controller Pro Mod [Vague Rant]
    C225A578 00000002
    801E0000 70000100
    60000000 00000000
    C225AC44 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  4. Code:
    Classic Controller Pro Mod [Vague Rant]
    C22586B0 00000002
    801E0000 70000100
    60000000 00000000
    C2258D7C 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  5. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2258E10 00000002
    801E0000 70000100
    60000000 00000000
    C22594DC 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000

Button Mapping​

The mapping here is mostly unchanged, besides the modified shoulder buttons, so I will only be covering the changed buttons.

Classic ControllerClassic Controller ProGame Function
L (half press)ZRDescend
L (full press)ZR (double tap)Rapid Descend
R (half press)RAscend
R (full press)R (double tap)Rapid Ascend
ZR (double tap)L (double tap)Emergency Blaster Wave

General Notes​

  • This modifies the control scheme for all Classic Controllers, so if you are playing on an original Classic Controller with analog shoulder buttons, I don't recommend using this code. The other control schemes (Wii Remote and Nunchuk, GameCube controller) are completely unmodified, so those are fine, but the original CC will play awfully with this control scheme. I don't know how or have any plan to fix this, just don't use the code if you want to play with an original Classic Controller.

  • As mentioned, this uses the control scheme from the PlayStation 2 version of Tenkaichi 3, where ascending/descending is done on the right shoulder/trigger buttons instead of L and R on the original Classic Controller. These have a more logical "up/down" layout than L/R do; the only reason they're laid out that way is because of the analog nature of the shoulder buttons on original CCs. On a more traditional, non-analog-shoulders controller, the PS2 layout makes more sense. This code is not really adjustable in the way most of the others are, so if you don't like this layout, eh ...

Technical Notes​

This was my first time remapping the Classic Controller itself or dealing with the original-CC-specific analog shoulder buttons. It went pretty well. Code breakdown:

C2
This is modifying read_kpad_stick(), which also reads the analog shoulder buttons, in a slightly tricky way. Instead of reading the actual analog shoulder data for the L button, it reads in the fake button value which I set up below in KPADRead(), 0x100. Notably, the Classic Controller (Pro) only has one free button field, since there's 16 possible bits and the CC has 15 buttons. Anyway, instead of actually faking some analog data, I'm reading in the actual bytes of the button value 0x100 as if it was analog data, because that's perfectly fine for this game specifically. Other games likely use different thresholds for when they consider the analog button "half-pressed", so this is in theory portable but in practice shrug, depends on the game.

C2
This modifies KPADRead() to first rotate the shoulder buttons around to match the PS2 setup and add a fake button 0x100 which we use to trigger the left analog shoulder (since it's been moved to ZR here). It then adds a function which masks out the L/R full-press bits by default (so all presses are half-presses) and tracks whether the player has pressed ascend or descend twice in the same 8-frame window. If they have, we unmask the relevant digital press bit so that the game is now reading a full press. Once you release the button, it goes back to the original masking behavior, i.e. the buttons return to half-presses. This matches the behavior of the Wiimote and Nunchuk control scheme, which uses Nunchuk C/Z and similarly checks for two presses in an 8-frame window. I didn't find or copy that code from the original game, just observed the 8-frame timer by pausing execution and frame advancing to see how it worked, but the result should be identical to the original Nunchuk double-tap detection.
 
Documentation sounds great. Tomorrow I'm gonna inject de Blob to the wii u system. This was a great game even with the crappy controls, but now it will be better than ever. Thanks for that. Have you considered the following games already: "batman the brave and the bold" (minimal motion controls) and "rhythm heaven fever" (no motion controls)?
 
  • Like
Reactions: Vague Rant
Some more ideas:
Could Mario Sports Mix get a CC mod? Theres lots of controls, it would work well in WiiVC mode with gamepad 👍 (or classic controller itself) The only motions controls are basketball dodge move, hockey actions, and other things

Rhythm heaven fever could also use one later on, with ZR/ZL as the A and B buttons
 
@Vague Rant I don't know if it's possible, but here's a mad idea: GC controller support for DK: Barrel Blast. More specifically, GC Bongo support.

Very few people would be interested as the game sucks (me included tbh), but restoring how the game was supposed to be played would be fascinating.
 
To be honest, it wouldn't really be a short tutorial as it's a pretty involved process, but the next game I attempt, I'll document it as I go. There's no apps to modify games like this, I'm just digging into the assembly code and writing and inserting my own routines which reroute the KPAD data into different fields and stuff like that. The main Gecko code type these hacks are made up of are C2 codes, which are assembly insertion rather than in-place modifications, i.e. they're not so much editing the controls in the main.dol as they are adding new code to each game that didn't exist before so that it behaves differently.


Yep, there are Classic Controller hacks for both Mario Galaxy games by Super Hackio. This thread isn't a list of all Classic Controller hacks, these are just the ones that I've made personally. The others that I'm aware of are crediar's Donkey Kong Country Returns and Kirby's Return to Dreamland, Thomas83Lin's Rune Factory: Tides of Destiny and New Super Mario Bros. Wii, and the aforementioned Mario Galaxy hacks.


I don't know, that sounds pretty much impossible to me.



View attachment 464252
Dragon Ball Z: Budokai Tenkaichi 3 is the third entry in Spike's fighting game series based on the hit manga and anime by the late Akira Toriyama. Tenkaichi 3 is a deep dive into the lore and history of the Dragon Ball Z franchise, with a roster of 98 unique characters in 161 different forms, the largest ever fighting game roster at the time. Though hugely popular and successful, the Tenkaichi series would lie dormant for 17 years after the release of this game, until the fourth entry released *checks watch* ... yesterday.

This is technically a Classic Controller hack, but Tenkaichi 3 always supported the Classic Controller. The issue, as noted by @Alepss, is that the game was developed around the original Classic Controller and its analog shoulder buttons, which were removed in the Pro revision. This hack instead replicates the PlayStation 2 control scheme, where aerial controls are on R1/R2 (Classic R/ZR), with double-taps triggering the equivalent of a full analog button press.

USAUSA (Rev 1)EuropeJapanJapan (Rev 1)

  1. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2258EAC 00000002
    801E0000 70000100
    60000000 00000000
    C2259578 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  2. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2259A7C 00000002
    801E0000 70000100
    60000000 00000000
    C225A148 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  3. Code:
    Classic Controller Pro Mod [Vague Rant]
    C225A578 00000002
    801E0000 70000100
    60000000 00000000
    C225AC44 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  4. Code:
    Classic Controller Pro Mod [Vague Rant]
    C22586B0 00000002
    801E0000 70000100
    60000000 00000000
    C2258D7C 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000
  5. Code:
    Classic Controller Pro Mod [Vague Rant]
    C2258E10 00000002
    801E0000 70000100
    60000000 00000000
    C22594DC 00000015
    7125DFFB 71200004
    41820008 60A52100
    71200200 41820004
    71202000 41820008
    60A50004 A01FFFFC
    B0BFFFFC 7CA60078
    887FFFFE 39202000
    4800001D 987FFFFE
    887FFFFF 39200200
    4800000D 987FFFFF
    48000048 7C630774
    7CC04839 41820014
    2C030000 40820014
    38600008 48000024
    2C03FFFF 40820010
    3860FFFF 7CA04839
    40820014 3463FFFF
    41810008 38600000
    7CA54878 4E800020
    7CA92B78 807F0060
    60000000 00000000

Button Mapping​

The mapping here is mostly unchanged, besides the modified shoulder buttons, so I will only be covering the changed buttons.

[TABLE=full]
[TR]
[TH]Classic Controller[/TH]
[TH]Classic Controller Pro[/TH]
[TH]Game Function[/TH]
[/TR]
[TR]
[TD]L (half press)[/TD]
[TD]ZR[/TD]
[TD]Descend[/TD]
[/TR]
[TR]
[TD]L (full press)[/TD]
[TD]ZR (double tap)[/TD]
[TD]Rapid Descend[/TD]
[/TR]
[TR]
[TD]R (half press)[/TD]
[TD]R[/TD]
[TD]Ascend[/TD]
[/TR]
[TR]
[TD]R (full press)[/TD]
[TD]R (double tap)[/TD]
[TD]Rapid Ascend[/TD]
[/TR]
[TR]
[TD]ZR (double tap)[/TD]
[TD]L (double tap)[/TD]
[TD]Emergency Blaster Wave[/TD]
[/TR]
[/TABLE]

General Notes​

  • This modifies the control scheme for all Classic Controllers, so if you are playing on an original Classic Controller with analog shoulder buttons, I don't recommend using this code. The other control schemes (Wii Remote and Nunchuk, GameCube controller) are completely unmodified, so those are fine, but the original CC will play awfully with this control scheme. I don't know how or have any plan to fix this, just don't use the code if you want to play with an original Classic Controller.

  • As mentioned, this uses the control scheme from the PlayStation 2 version of Tenkaichi 3, where ascending/descending is done on the right shoulder/trigger buttons instead of L and R on the original Classic Controller. These have a more logical "up/down" layout than L/R do; the only reason they're laid out that way is because of the analog nature of the shoulder buttons on original CCs. On a more traditional, non-analog-shoulders controller, the PS2 layout makes more sense. This code is not really adjustable in the way most of the others are, so if you don't like this layout, eh ...

Technical Notes​

This was my first time remapping the Classic Controller itself or dealing with the original-CC-specific analog shoulder buttons. It went pretty well. Code breakdown:

C2
This is modifying read_kpad_stick(), which also reads the analog shoulder buttons, in a slightly tricky way. Instead of reading the actual analog shoulder data for the L button, it reads in the fake button value which I set up below in KPADRead(), 0x100. Notably, the Classic Controller (Pro) only has one free button field, since there's 16 possible bits and the CC has 15 buttons. Anyway, instead of actually faking some analog data, I'm reading in the actual bytes of the button value 0x100 as if it was analog data, because that's perfectly fine for this game specifically. Other games likely use different thresholds for when they consider the analog button "half-pressed", so this is in theory portable but in practice shrug, depends on the game.

C2
This modifies KPADRead() to first rotate the shoulder buttons around to match the PS2 setup and add a fake button 0x100 which we use to trigger the left analog shoulder (since it's been moved to ZR here). It then adds a function which masks out the L/R full-press bits by default (so all presses are half-presses) and tracks whether the player has pressed ascend or descend twice in the same 8-frame window. If they have, we unmask the relevant digital press bit so that the game is now reading a full press. Once you release the button, it goes back to the original masking behavior, i.e. the buttons return to half-presses. This matches the behavior of the Wiimote and Nunchuk control scheme, which uses Nunchuk C/Z and similarly checks for two presses in an 8-frame window. I didn't find or copy that code from the original game, just observed the 8-frame timer by pausing execution and frame advancing to see how it worked, but the result should be identical to the original Nunchuk double-tap detection.
Exactly what I meant! Amazing job! :grog:
 
  • Like
Reactions: Vague Rant
Sounds interesting! Are there enough buttons left for all of the things you can do in Mario Kart Wii? Accelerate, Brake, Slide, Item, Trick, Wheelie ... there's only really four buttons on the Wiimote that are (somewhat) usable in sideways layout, so it'd be pretty crowded. But it might be fun to see if anything could be worked out.

I would be really happy if there were a patch that adjusts the controls of Mario Kart Wii to match those of Mario Kart 8. It would be especially great if you no longer had to shake the Wiimote to perform a trick.
 
I would be really happy if there were a patch that adjusts the controls of Mario Kart Wii to match those of Mario Kart 8. It would be especially great if you no longer had to shake the Wiimote to perform a trick.

Mario Kart has classic controller support and you can trick without shaking. Maybe it would be a nice addition to put the drift on the same button as the trick, but maybe it's not as great in mkwii as it is in mk8.
 
@Vague Rant I don't know if it's possible, but here's a mad idea: GC controller support for DK: Barrel Blast. More specifically, GC Bongo support.

Very few people would be interested as the game sucks (me included tbh), but restoring how the game was supposed to be played would be fascinating.
This would definitely be hugely creative and maybe (probably not) go some way to redeeming the game, but it's definitely beyond me right now. I've tried and failed to understand the GameCube PAD library once already, and I don't even own the DK Bongos to properly test those anyway. But that would be a great hack if it were possible.

I would be really happy if there were a patch that adjusts the controls of Mario Kart Wii to match those of Mario Kart 8. It would be especially great if you no longer had to shake the Wiimote to perform a trick.
Mario Kart has classic controller support and you can trick without shaking. Maybe it would be a nice addition to put the drift on the same button as the trick, but maybe it's not as great in mkwii as it is in mk8.
blue-spirit's idea is an interesting one. I haven't played MKWii recently enough to really know why they put Trick and Drift on separate buttons for that game. The Classic layout for that game has always been pretty weird in general, it's offputting that you have to take your thumb off the stick to perform certain moves. Checking out the controls page on StrategyWiki again, it looks like the Classic ZL button is competely unused. Worst case scenario, maybe Trick could go there so it's at least on a button you can press while keeping your thumb on the left stick.

Some more ideas:
Could Mario Sports Mix get a CC mod? Theres lots of controls, it would work well in WiiVC mode with gamepad 👍 (or classic controller itself) The only motions controls are basketball dodge move, hockey actions, and other things

Rhythm heaven fever could also use one later on, with ZR/ZL as the A and B buttons
Mario Sports Mix and Rhythm Heaven Fever are both on my list of games to look into for Classic Controller hacks. One's probably a bit closer to happening than the other ...

Documentation sounds great. Tomorrow I'm gonna inject de Blob to the wii u system. This was a great game even with the crappy controls, but now it will be better than ever. Thanks for that. Have you considered the following games already: "batman the brave and the bold" (minimal motion controls) and "rhythm heaven fever" (no motion controls)?
Batman is actually one I looked at very early on in the process of making Classic Controller hacks. It looked complicated at the time, but it might be worth taking another look to see if I can make more sense of it now. I actually added Rhythm Heaven Fever to my list when you mentioned it previously, sorry I missed replying to that part! Definitely a good candidate ...



Before getting to the next game, I'm going to walk through my current process for adding Classic Controller support. Hopefully, this will make it easier for the next person who decides to CC-hack games.

Important Notes​

  • this guide will not be covering anything game-specific; e.g. motion detection, disabling "Please remove unsupported extension controller" error messages, etc.

  • before doing anything else you should probably boot up the game in an emulator or on console with a Classic Controller attached and see if there's any kind of error message

  • if you can't hack away the error message, there's no point doing the rest of this stuff

Things You'll Need​

  • some degree of understanding of PPC assembly code

  • the Dolphin emulator

    • open up Dolphin and select Options > Configuration > Interface > Enable Debugging UI

  • the CodeWrite Gecko C2 code assembler

  • a text editor; Notepad will work but something else with assembly syntax highlighting like Notepad++ might make it easier

  • a backup of the game you're looking to hack

Identifying Functions​

  1. Before booting up the game in Dolphin, right click it and go to Properties > Filesystem

    • skim through the Data Partition looking for any files with the extension .elf or .map

    • these may be unstripped binaries or function name maps, respectively; however, .map is also a pretty generic extension, so it might literally be maps in the video game sense and not the symbol maps we're looking for

    • if you found any .elf or .map files which look useful, extract them (right click > Extract File...) to somewhere that seems sensible on your PC

    • Dolphin can load .elf files directly and .map files can be opened with Symbols > Load Other Map File...

    • developers are not supposed to leave these sorts of files on retail discs, so they're sort of rare-ish and it's not very likely you'll find either

    • there is a list of known Wii games with debug symbols at Retro Reversing

  2. proceeding with the assumption that nobody left behind any helpful symbols, load the game you're trying to hack and pause execution

  3. from the Dolphin menu, choose Symbols > Generate Symbols From > Signature Database

    • Dolphin includes an internal database of function signatures, which are sort of like fingerprints for code

    • Dolphin will use this database to identify as many functions as it recognizes, based on the fact that they appear in and are fairly similar across many games

    • this feature is absolutely not foolproof: there are many functions Dolphin will not identify and many that it will incorrectly identify

    • if Dolphin detects a function but doesn't recognize it, it will give it a name based on the address at which it appears and also color-code it in the disassembler view

    • if Dolphin completely fails to detect a function at any given location, it will display in white with no function name

  4. using the Symbols search field on the left side of the Code tab, try to locate the KPADRead/KPADiRead function

    • older SDK versions have KPADRead while newer SDKs (games released from about 2010 onward?) have KPADiRead; for the sake of simplicity I will just refer to this function as KPADRead for the rest of this post

    • Dolphin usually won't recognize KPADRead itself, but it may recognize child functions called within KPADRead or its children

    • often, select_1obj_continue is detected by Dolphin; this is a child function of read_kpad_dpd which is a child of KPADRead

      • as I write this post, Dolphin has not recognized select_1obj_continue, so I had to find KPADRead another way; for now let's just pretend it worked

    • click on select_1obj_continue in the search results, look in the bottom left Callers section and click either of those calls from an unrecognized function; that unrecognized function is read_kpad_dpd

    • right click anywhere inside that unrecognized function and click Rename Symbol; rename the symbol to read_kpad_dpd

    • whenever it seems appropriate, use Symbols > Save Symbol Map to ensure you don't lose any progress

    • look down at the Callers again and click on any of the calls you see from an unrecognized function; that unrecognized function is KPADRead

  5. right click > Rename Symbol > KPADRead; this is good progress

  6. identify the other major KPAD read functions

    • if you just navigated back here from read_kpad_dpd like I directed, you're currently looking at a section of the disassembler which should read something like this:
      Code:
      8016fb58	mr	r3, r31			KPADRead
      8016fb5c	mr	r4, r19			KPADRead
      8016fb60	bl	->0x8016E410	--> zz_8016e410_
      8016fb64	mr	r3, r31			KPADRead
      8016fb68	mr	r4, r19			KPADRead
      8016fb6c	bl	->0x8016C920	--> zz_8016c920_
      8016fb70	mr	r3, r31			KPADRead
      8016fb74	mr	r4, r19			KPADRead
      8016fb78	bl	->0x8016DBF0	--> read_kpad_dpd
    • the two function calls (bl instructions) right above read_kpad_dpd are to read_kpad_stick/ext (varies by SDK version, I will just call it stick from now on) and read_kpad_acc

    • right click on the first one and select Follow Branch

    • you're now inside read_kpad_stick, so right click > Rename Symbol > read_kpad_stick

    • go back to KPADRead from the Callers list

    • repeat the same process for the other unrecognized function, which is read_kpad_acc, so that you eventually have this:
      Code:
      8016fb58	mr	r3, r31			KPADRead
      8016fb5c	mr	r4, r19			KPADRead
      8016fb60	bl	->0x8016E410	--> read_kpad_stick
      8016fb64	mr	r3, r31			KPADRead
      8016fb68	mr	r4, r19			KPADRead
      8016fb6c	bl	->0x8016C920	--> read_kpad_acc
      8016fb70	mr	r3, r31			KPADRead
      8016fb74	mr	r4, r19			KPADRead
      8016fb78	bl	->0x8016DBF0	--> read_kpad_dpd
  7. find where the buttons are read by KPAD

    • this is the first significant fork between older and newer SDK games: older games read the buttons directly inside KPADRead while newer games call a separate read_kpad_button function

    • scroll up slowly until you get to another function call (bl instruction)

    • scroll up three more instructions past the bl and check whether the instruction is something that looks more like this:
      Code:
      stw	r0, 0x0068 (r31)
      ... or more like this:
      Code:
      lwz	r8, 0x0060 (r21)
    • the exact registers may not be the same, but the instructions (stw vs. lwz) and the offsets (0x0068 vs. 0x0060) should be persistent

    • if you have the first one, this is an older SDK game where buttons are read inside KPADRead

      • scroll up some more until you reach an instruction that looks like this:
        Code:
        andi.	r0, r7, 0x9FFF

    • if you have the second one, this is a newer SDK game where the buttons are read in a separate read_kpad_button function (the bl we just passed)

      • right click on the bl instruction and select Follow Branch

      • right click > Rename Symbol > read_kpad_button

      • look ahead one instruction to find the following:
        Code:
        andi.	r0, r6, 0x9FFF
  8. make a note of the address for the andi. instruction you just found; congratulations, that's the place where you'll be injecting the Classic Controller buttons into the Wii Remote!

Injecting Buttons​

  1. now, write a custom routine in PPC assembly which takes the button values from the Classic Controller register and drops them into the Wii Remote register; fine, I'll start:

    Old SDKNew SDK

    1. Code:
      ; KPADRead
      ; r4 holds extType
      ; r7 holds wiimote bitfield
      ; r8 holds wiimote+nunchuk bitfield
      ; r9 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r9, 0x800
            beq- CLASSIC_UP
            ori r7, r7, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r9, 0x1
            beq- CLASSIC_DOWN
            ori r7, r7, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r9, 0x4000
            beq- CLASSIC_LEFT
            ori r7, r7, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r9, 0x2
            beq- CLASSIC_RIGHT
            ori r7, r7, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r9, 0x8000
            beq- CLASSIC_A
            ori r7, r7, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r9, 0x10
            beq- CLASSIC_B
            ori r7, r7, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r9, 0x40
            beq- CLASSIC_X
            ori r7, r7, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r9, 0x8
            beq- CLASSIC_Y
            ori r7, r7, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r9, 0x20
            beq- CLASSIC_L
            ori r7, r7, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r9, 0x2000
            beq- CLASSIC_R
            ori r7, r7, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r9, 0x200
            beq- CLASSIC_ZL
            ori r7, r7, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r9, 0x80
            beq- CLASSIC_ZR
            ori r7, r7, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r9, 0x4
            beq- CLASSIC_PLUS
            ori r7, r7, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r9, 0x400
            beq- CLASSIC_MINUS
            ori r7, r7, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r9, 0x1000
            beq- RETURN
            ori r7, r7, 0x1000    ; minus
      
      RETURN:
        andi. r0, r7, 0x9FFF
    2. Code:
      ; read_kpad_button
      ; r4 holds extType
      ; r6 holds wiimote bitfield
      ; r7 holds wiimote+nunchuk bitfield
      ; r8 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r8, 0x800
            beq- CLASSIC_UP
            ori r6, r6, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r8, 0x1
            beq- CLASSIC_DOWN
            ori r6, r6, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r8, 0x4000
            beq- CLASSIC_LEFT
            ori r6, r6, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r8, 0x2
            beq- CLASSIC_RIGHT
            ori r6, r6, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r8, 0x8000
            beq- CLASSIC_A
            ori r6, r6, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r8, 0x10
            beq- CLASSIC_B
            ori r6, r6, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r8, 0x40
            beq- CLASSIC_X
            ori r6, r6, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r8, 0x8
            beq- CLASSIC_Y
            ori r6, r6, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r8, 0x20
            beq- CLASSIC_L
            ori r6, r6, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r8, 0x2000
            beq- CLASSIC_R
            ori r6, r6, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r8, 0x200
            beq- CLASSIC_ZL
            ori r6, r6, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r8, 0x80
            beq- CLASSIC_ZR
            ori r6, r6, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r8, 0x4
            beq- CLASSIC_PLUS
            ori r6, r6, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r8, 0x400
            beq- CLASSIC_MINUS
            ori r6, r6, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r8, 0x1000
            beq- RETURN
            ori r6, r6, 0x1000    ; minus
      
      RETURN:
        andi. r0, r6, 0x9FFF
    • the above example may not have the ideal button mapping for the game you're hacking; notably, that example is for a game with the vertical Wiimote layout; the D-Pad directions will be all wrong if you're doing a horizontal (NES-style) game, so you will need to edit those and whatever else needs fixing

  2. open the CodeWrite app and put your assembly button injector into the ASM field, the address you identified before with the andi. instruction into the Insertion Address field, and click the right arrow at the bottom of the window

  3. copy the resulting Gecko code and add it to Tools > Cheats Manager > Gecko Codes in Dolphin

  4. either toggle the code off and on again or quit the game and restart it, so that Dolphin picks up the new code

  5. test the game

    • make sure you have a Classic Controller configured and buttons mapped for it in Controllers > Configure and that you don't have the same keys/buttons mapped for the Classic Controller as the Wii Remote--you need to be certain the inputs you're passing to the emulator are Classic inputs, not Wiimote inputs

  6. if it works, you just made a Classic Controller hack

Adding Features​

We could just stop there, but you can add a bit of polish to make things a bit friendlier. First, let's add D-Pad emulation on the left analog stick so players can use either the stick or D-Pad for directional input.
  1. go back to read_kpad_stick, which you identified earlier

  2. locate the place where you'll be inserting the D-Pad emulation routine

    • scroll down until you see a bctrl instruction--that's where the Nunchuk analog stick data gets written out--then keep scrolling down some more until you see two bctrl instructions close together, something like this:
      Code:
      8016e55c	mr		r12, r31			read_kpad_stick
      8016e560	addi	r3, r30, 12			read_kpad_stick
      8016e564	lha		r4, 0x002C (r29)	read_kpad_stick
      8016e568	lha		r5, 0x002E (r29)	read_kpad_stick
      8016e56c	lwz		r6, -0x6F8C (r13)	read_kpad_stick
      8016e570	lwz		r7, -0x6F88 (r13)	read_kpad_stick
      8016e574	mtctr	r12					read_kpad_stick
      8016e578	bctrl						read_kpad_stick
      8016e57c	mr		r12, r31			read_kpad_stick
      8016e580	addi	r3, r30, 20			read_kpad_stick
      8016e584	lha		r4, 0x0030 (r29)	read_kpad_stick
      8016e588	lha		r5, 0x0032 (r29)	read_kpad_stick
      8016e58c	lwz		r6, -0x6F8C (r13)	read_kpad_stick
      8016e590	lwz		r7, -0x6F88 (r13)	read_kpad_stick
      8016e594	mtctr	r12					read_kpad_stick
      8016e598	bctrl						read_kpad_stick
    • these are the left and right Classic Controller analog sticks, respectively

  3. write an assembly routine to convert Classic Controller analog input into D-Pad button presses; here's one I prepared earlier:
    Code:
    ; read_kpad_stick
      bctrl
      cmpwi r22, 0x1
      bne- RETURN
    
    ; magic
      bl GRAB
    MAGIC:
        THRESHOLD:  .float 0.5
        ZERO:       .float 0.0
    GRAB:
      mflr r3
    
      lfs f2, THRESHOLD-MAGIC(r3)
      lfs f3, ZERO-MAGIC(r3)
      lwz r4, -0x60(r30)    ; currently held
      lwz r5, -0x5C(r30)    ; pressed this frame
      lwz r6, -0x58(r30)    ; released this frame
    
      lfs f1, 0x0C(r30)     ; left stick x axis
      li r8, 0x1
      bl STICK_EMULATION
    
      lfs f1, 0x10(r30)     ; left stick y axis
      li r8, 0x4
      bl STICK_EMULATION
      stw r4, -0x60(r30)
      stw r5, -0x5C(r30)
      stw r6, -0x58(r30)
      b RETURN
    
    STICK_EMULATION:
      fabs f0, f1
      fcmpo cr0, f0, f2     ; is stick more than halfway?
      bltlr-
    
      fcmpo cr0, f1, f3     ; positive or negative direction?
      blt- AXIS_SKIP
      slwi r8, r8, 0x1      ; left->right / down->up
    
        AXIS_SKIP:
          and. r0, r6, r8       ; was this button already being held?
          bne- NOT_NEW
          or r5, r5, r8         ; add to buttons newly pressed
    
        NOT_NEW:
          or r4, r4, r8         ; add to buttons held
          andc. r6, r6, r8      ; remove from buttons released
    
      blr
    
    RETURN:
  4. using CodeWrite, inject your custom routine at the address of the bctrl instruction for the stick you wish to use, like you did before for the button injector

    • for example, I'm using 8016e578, the left stick bctrl, as I write this post

    • again, the example routine above assumes that this is a vertical Wiimote game, the directions will need to be corrected for a horizontal Wiimote game

    • the above example is also specific to the left stick; even if you use the right stick bctrl, the function above reads the left stick values; you will need to edit the offsets if you're putting D-Pad emulation on the right stick

  5. add the code to Dolphin and test again

    • if it works, great; if the directions are wrong, fix them and test again; if it doesn't work at all, shrug

  6. next, add support for the Wii Remote pointer

    • even if the game you're hacking doesn't use the pointer, the Home Button Menu does, so it's always more convenient to have pointer emulation

  7. return to read_kpad_dpd, which you identified earlier

  8. locate the calc_dpd_variable function; Dolphin will not have recognized this for you so it will have an autogenerated name

    • scroll all the way to the bottom of read_kpad_dpd and look for the function call near the end, looking like this:
      Code:
      8016e078	mr		r3, r31			read_kpad_dpd
      8016e078	extsb	r4, r30			read_kpad_dpd
      8016e078	bl		->0x8016D610	--> zz_8016d610_
    • that unrecognized function is calc_dpd_variable

  9. right click > Follow Branch

  10. right click > Rename Symbol > calc_dpd_variable

    • the start of this function should look pretty much, if not exactly like this:
      Code:
      8016d610	stwu	sp, -0x0020 (sp)	calc_dpd_variable
      8016d614	mflr	r0					calc_dpd_variable
      8016d618	stw		r0, 0x0024 (sp)		calc_dpd_variable
    • that third instruction is an ideal location to insert pointer emulation; make a note of that address

  11. locate the SDK SCGetAspectRatio function

    • Dolphin is very good at incorrectly recognizing SCGetAspectRatio

    • use the symbol search to look for SCGetWpadSpeakerVolume; you will probably get 8 or more results, most of which are wrong

    • the first one is almost always the real SCGetAspectRatio, which Dolphin has mis-identified

    • for extra confidence, check if the function right above it has been identified by Dolphin as MyNandCallback and the function right below it has been identified as SCGetDisplayOffsetH; SCGetAspectRatio is usually sandwiched between those two functions which Dolphin often does correctly identify

    • make a note of the address where SCGetAspectRatio begins

  12. write an assembly routine to convert Classic Controller analog input into relative movement of the Wii Remote infra-red pointer, incorporating aspect ratio correction using SCGetAspectRatio; oh look, I found one:
    Code:
    ; calc_dpd_variable
      stw r0, 0x24(sp)
    
    ; player using real pointer? (gravity already valid)
      cmpwi r4, 0x0
      bne- NO_CLASSIC
    
    ; check for Classic Controller
      lbz r0, 0x5C(r3)
      cmpwi r0, 0x2
      bne- NO_CLASSIC
    
    ; magic
      bl GRAB
    MAGIC:
        GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
        ASPECT:     .float 1.3333333333
        MULTIPLIER: .float 0.015        ; pointer speed
        TIMER:      .hword 0
                    .hword 0
                    .hword 0
                    .hword 0
        DEADZONE:   .float 0.1
        MAX_RANGE:  .float 1.0
    GRAB:
      mflr r5
      stw r5, 0x0C(sp)      ; save magic pointer
    
    ; handle four separate timers for multiplayer
      slwi r7, r25, 0x1     ; player index
      addi r7, r7, TIMER-MAGIC
    
    STICK_WAKE:
      lfs f0, 0x74(r3)
      fabs f0, f0
      lfs f1, 0x78(r3)
      fabs f1, f1
      fadd f0, f0, f1
      lfs f2, DEADZONE-MAGIC(r5)
      fcmpo cr0, f0, f2
      blt- CHECK_TIMER
      li r6, 300
      b DELTA
    
    ; check pointer sleep timer
    CHECK_TIMER:
      lhax r6, r5, r7
      cmplwi r6, 0x0
      ble- NO_CLASSIC
      subi r6, r6, 0x1
    
    DELTA:
      sthx r6, r5, r7
      li r6, 0x2
      stb r6, 0x5E(r3)
      lwz r12, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
      mtlr r12
      blrl
      cmpwi r3, 0x1
      mr r3, r31            ; restore input pointer
      lwz r5, 0x0C(sp)      ; restore magic pointer
    
      lfs f2, ASPECT-MAGIC(r5)
      bne- FULLSCREEN
      fmuls f2, f2, f2       ; widescreen
    FULLSCREEN:
      lfs f3, MULTIPLIER-MAGIC(r5)
    
    ; pointer X axis
      lfs f0, 0x20(r3)
      lfs f1, 0x74(r3)       ; right stick X
      fdiv f1, f1, f2        ; divide by aspect ratio
      bl RANGE_CHECK
      stfs f0, 0x20(r3)
    
    ; pointer Y axis
      lfs f0, 0x24(r3)
      lfs f1, 0x78(r3)      ; right stick Y
      fneg f1, f1
      bl RANGE_CHECK
      stfs f0, 0x24(r3)
    
    RETURN:
      lwz r0, 0x24(sp)
      mtlr r0
      addi sp, sp, 0x20
      blr
    
    RANGE_CHECK:
      fmadd f0, f1, f3, f0
      lfs f1, MAX_RANGE-MAGIC(r5)
      fcmpu cr0, f0, f1
      blt CHECK_NEGATIVE
      fmr f0, f1
      b IN_RANGE
    
        CHECK_NEGATIVE:
          fneg f1, f1
          fcmpu cr0, f0, f1
          bgt IN_RANGE
          fmr f0, f1
          
        IN_RANGE:
          blr
    
    NO_CLASSIC:
    • depending on the game, you might want different implementations here: left stick, right stick, always on, toggled with a button; the example above supports four players, uses the right stick and the pointer is disabled after a few seconds of no movement

    • if you're using my example pointer routine, you must copy the address where you found SCGetAspectRatio into the following line:
      Code:
          GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
    • for example, in my case SCGetAspectRatio was at 80124550, so the line looks like this for me:
      Code:
          GETASPECT:  .int 0x80124550     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!

  13. back in CodeWrite, insert this routine at the address you found in calc_dpd_variable; I told you to make a note of it

  14. add the code to Dolphin and test it again

    • if everything is working at this point, you're done

    • if you're feeling generous, you can repeat this entire process for each disc revision and region

  15. post your new hack online!


Speaking of step 15 ...

SI_Wii_BeatTheBeatRhythmParadise_image1600w.jpg


From the creators of WarioWare, Nintendo SPD's Rhythm Heaven Fever aka Beat the Beat: Rhythm Paradise is a rhythm minigame collection which is elegantly simplistic in both gameplay and art-style. Like other entries in the series, Fever revolves almost entirely around pressing just two buttons. Since the series' Japan-only cult hit debut on Game Boy Advance, Rhythm Heaven has seen worldwide releases on Nintendo DS and 3DS, as well as this Wii version, generally regarded as the point where the series peaked. Things have been quiet for the series since 2016, so maybe it's time to revisit a classic.

USAEuropeJapanKorea

  1. Code:
    Classic Controller Support v1.1 [Vague Rant]
    C216D618 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124550
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E578 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C4D4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60100
    71000020 41820008
    60C60200 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  2. Code:
    Classic Controller Support v1.1 [Vague Rant]
    C216EF08 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80125E40
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216FE68 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216DDC4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60100
    71000020 41820008
    60C60200 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  3. Code:
    Classic Controller Support v1.1 [Vague Rant]
    C216F808 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80126740
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C2170768 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216E6C4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60100
    71000020 41820008
    60C60200 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  4. Code:
    Classic Controller Support v1.1 [Vague Rant]
    C216D4E8 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124420
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E448 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C3A4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60100
    71000020 41820008
    60C60200 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000

Button Mapping​

Wii RemoteClassic ControllerGame Function
HomeHome
Remember to use the Right Stick
Open/Close Home Button Menu
D-PadD-Pad
Left Stick
Menu Navigation
AA / L / ZLMain Action
BB / R / ZRSecondary Action
Wiimote 1YHi-Hat
Wiimote 2XNot used?
PlusPlusPause
Skip Training
MinusMinusNot used?

General Notes​

  • Being a game that only uses two buttons on a controller that has ~8 of them means I double-mapped A/B all over the place, so hopefully there's a layout that's comfortable for you. There's the Wiimote-style A+ZR, 3DS-style A+B, you can stick to the shoulder buttons, go nuts.

Changelog​

  • v1.1 adds mappings for Wiimote 1 and 2 on Classic Y and X; thanks @awesomeee

Technical Notes​

  • Rhythm Heaven Fever is the game from the tutorial above, so that's one giant technical note for this game.

  • That said, there's some mildly unique stuff going on here. Since I was going to be posting my assembly source in the tutorial, I figured I'd give it a once-over and clean it up a bit, so the D-Pad emulation got a bit of an optimization run vs. the original version and I tried to make the pointer feature as generic as possible so that it's more easily portable to other games. This version of the pointer function automatically switches off if there's no movement on the right stick and supports up to four players on Classic Controller (even though Rhythm Heaven Fever only supports two). As such, it should be pretty good to use in other games.
 
Last edited by Vague Rant,
This would definitely be hugely creative and maybe (probably not) go some way to redeeming the game, but it's definitely beyond me right now. I've tried and failed to understand the GameCube PAD library once already, and I don't even own the DK Bongos to properly test those anyway. But that would be a great hack if it were possible.



blue-spirit's idea is an interesting one. I haven't played MKWii recently enough to really know why they put Trick and Drift on separate buttons for that game. The Classic layout for that game has always been pretty weird in general, it's offputting that you have to take your thumb off the stick to perform certain moves. Checking out the controls page on StrategyWiki again, it looks like the Classic ZL button is competely unused. Worst case scenario, maybe Trick could go there so it's at least on a button you can press while keeping your thumb on the left stick.


Mario Sports Mix and Rhythm Heaven Fever are both on my list of games to look into for Classic Controller hacks. One's probably a bit closer to happening than the other ...


Batman is actually one I looked at very early on in the process of making Classic Controller hacks. It looked complicated at the time, but it might be worth taking another look to see if I can make more sense of it now. I actually added Rhythm Heaven Fever to my list when you mentioned it previously, sorry I missed replying to that part! Definitely a good candidate ...



Before getting to the next game, I'm going to walk through my current process for adding Classic Controller support. Hopefully, this will make it easier for the next person who decides to CC-hack games.

Important Notes​

  • this guide will not be covering anything game-specific; e.g. motion detection, disabling "Please remove unsupported extension controller" error messages, etc.

  • before doing anything else you should probably boot up the game in an emulator or on console with a Classic Controller attached and see if there's any kind of error message

  • if you can't hack away the error message, there's no point doing the rest of this stuff

Things You'll Need​

  • some degree of understanding of PPC assembly code

  • the Dolphin emulator
    • open up Dolphin and select Options > Configuration > Interface > Enable Debugging UI

  • the CodeWrite Gecko C2 code assembler

  • a text editor; Notepad will work but something else with assembly syntax highlighting like Notepad++ might make it easier

  • a backup of the game you're looking to hack

Identifying Functions​

  1. Before booting up the game in Dolphin, right click it and go to Properties > Filesystem
    • skim through the Data Partition looking for any files with the extension .elf or .map

    • these may be unstripped binaries or function name maps, respectively; however, .map is also a pretty generic extension, so it might literally be maps in the video game sense and not the symbol maps we're looking for

    • if you found any .elf or .map files which look useful, extract them (right click > Extract File...) to somewhere that seems sensible on your PC

    • Dolphin can load .elf files directly and .map files can be opened with Symbols > Load Other Map File...

    • developers are not supposed to leave these sorts of files on retail discs, so they're sort of rare-ish and it's not very likely you'll find either

    • there is a list of known Wii games with debug symbols at Retro Reversing

  2. proceeding with the assumption that nobody left behind any helpful symbols, load the game you're trying to hack and pause execution

  3. from the Dolphin menu, choose Symbols > Generate Symbols From > Signature Database
    • Dolphin includes an internal database of function signatures, which are sort of like fingerprints for code

    • Dolphin will use this database to identify as many functions as it recognizes, based on the fact that they appear in and are fairly similar across many games

    • this feature is absolutely not foolproof: there are many functions Dolphin will not identify and many that it will incorrectly identify

    • if Dolphin detects a function but doesn't recognize it, it will give it a name based on the address at which it appears and also color-code it in the disassembler view

    • if Dolphin completely fails to detect a function at any given location, it will display in white with no function name

  4. using the Symbols search field on the left side of the Code tab, try to locate the KPADRead/KPADiRead function
    • older SDK versions have KPADRead while newer SDKs (games released from about 2010 onward?) have KPADiRead; for the sake of simplicity I will just refer to this function as KPADRead for the rest of this post

    • Dolphin usually won't recognize KPADRead itself, but it may recognize child functions called within KPADRead or its children

    • often, select_1obj_continue is detected by Dolphin; this is a child function of read_kpad_dpd which is a child of KPADRead
      • as I write this post, Dolphin has not recognized select_1obj_continue, so I had to find KPADRead another way; for now let's just pretend it worked

    • click on select_1obj_continue in the search results, look in the bottom left Callers section and click either of those calls from an unrecognized function; that unrecognized function is read_kpad_dpd

    • right click anywhere inside that unrecognized function and click Rename Symbol; rename the symbol to read_kpad_dpd

    • whenever it seems appropriate, use Symbols > Save Symbol Map to ensure you don't lose any progress

    • look down at the Callers again and click on any of the calls you see from an unrecognized function; that unrecognized function is KPADRead

  5. right click > Rename Symbol > KPADRead; this is good progress

  6. identify the other major KPAD read functions
    • if you just navigated back here from read_kpad_dpd like I directed, you're currently looking at a section of the disassembler which should read something like this:
      Code:
      8016fb58    mr    r3, r31            KPADRead
      8016fb5c    mr    r4, r19            KPADRead
      8016fb60    bl    ->0x8016E410    --> zz_8016e410_
      8016fb64    mr    r3, r31            KPADRead
      8016fb68    mr    r4, r19            KPADRead
      8016fb6c    bl    ->0x8016C920    --> zz_8016c920_
      8016fb70    mr    r3, r31            KPADRead
      8016fb74    mr    r4, r19            KPADRead
      8016fb78    bl    ->0x8016DBF0    --> read_kpad_dpd
    • the two function calls (bl instructions) right above read_kpad_dpd are to read_kpad_stick/ext (varies by SDK version, I will just call it stick from now on) and read_kpad_acc

    • right click on the first one and select Follow Branch

    • you're now inside read_kpad_stick, so right click > Rename Symbol > read_kpad_stick

    • go back to KPADRead from the Callers list

    • repeat the same process for the other unrecognized function, which is read_kpad_acc, so that you eventually have this:
      Code:
      8016fb58    mr    r3, r31            KPADRead
      8016fb5c    mr    r4, r19            KPADRead
      8016fb60    bl    ->0x8016E410    --> read_kpad_stick
      8016fb64    mr    r3, r31            KPADRead
      8016fb68    mr    r4, r19            KPADRead
      8016fb6c    bl    ->0x8016C920    --> read_kpad_acc
      8016fb70    mr    r3, r31            KPADRead
      8016fb74    mr    r4, r19            KPADRead
      8016fb78    bl    ->0x8016DBF0    --> read_kpad_dpd
  7. find where the buttons are read by KPAD
    • this is the first significant fork between older and newer SDK games: older games read the buttons directly inside KPADRead while newer games call a separate read_kpad_button function

    • scroll up slowly until you get to another function call (bl instruction)

    • scroll up three more instructions past the bl and check whether the instruction is something that looks more like this:
      Code:
      stw    r0, 0x0068 (r31)
      ... or more like this:
      Code:
      lwz    r8, 0x0060 (r21)
    • the exact registers may not be the same, but the instructions (stw vs. lwz) and the offsets (0x0068 vs. 0x0060 should be persistent

    • if you have the first one, this is an older SDK game where buttons are read inside KPADRead
      • scroll up some more until you reach an instruction that looks like this:
        Code:
        andi.    r0, r7, 0x9FFF

    • if you have the second one, this is a newer SDK game where the buttons are read in a separate read_kpad_button function (the bl we just passed)
      • right click on the bl instruction and select Follow Branch

      • right click > Rename Symbol > read_kpad_button

      • look ahead one instruction to find the following:
        Code:
        andi.    r0, r6, 0x9FFF
  8. make a note of the address for the andi. instruction you just found; congratulations, that's the place where you'll be injecting the Classic Controller buttons into the Wii Remote!

Injecting Buttons​

  1. now, write a custom routine in PPC assembly which takes the button values from the Classic Controller register and drops them into the Wii Remote register; fine, I'll start:

    Old SDKNew SDK

    1. Code:
      ; KPADRead
      ; r4 holds extType
      ; r7 holds wiimote bitfield
      ; r8 holds wiimote+nunchuk bitfield
      ; r9 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r9, 0x800
            beq- CLASSIC_UP
            ori r7, r7, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r9, 0x1
            beq- CLASSIC_DOWN
            ori r7, r7, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r9, 0x4000
            beq- CLASSIC_LEFT
            ori r7, r7, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r9, 0x2
            beq- CLASSIC_RIGHT
            ori r7, r7, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r9, 0x8000
            beq- CLASSIC_A
            ori r7, r7, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r9, 0x10
            beq- CLASSIC_B
            ori r7, r7, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r9, 0x40
            beq- CLASSIC_X
            ori r7, r7, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r9, 0x8
            beq- CLASSIC_Y
            ori r7, r7, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r9, 0x20
            beq- CLASSIC_L
            ori r7, r7, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r9, 0x2000
            beq- CLASSIC_R
            ori r7, r7, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r9, 0x200
            beq- CLASSIC_ZL
            ori r7, r7, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r9, 0x80
            beq- CLASSIC_ZR
            ori r7, r7, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r9, 0x4
            beq- CLASSIC_PLUS
            ori r7, r7, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r9, 0x400
            beq- CLASSIC_MINUS
            ori r7, r7, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r9, 0x1000
            beq- RETURN
            ori r7, r7, 0x1000    ; minus
      
      RETURN:
        andi. r0, r7, 0x9FFF
    2. Code:
      ; read_kpad_button
      ; r4 holds extType
      ; r6 holds wiimote bitfield
      ; r7 holds wiimote+nunchuk bitfield
      ; r8 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r8, 0x800
            beq- CLASSIC_UP
            ori r6, r6, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r8, 0x1
            beq- CLASSIC_DOWN
            ori r6, r6, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r8, 0x4000
            beq- CLASSIC_LEFT
            ori r6, r6, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r8, 0x2
            beq- CLASSIC_RIGHT
            ori r6, r6, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r8, 0x8000
            beq- CLASSIC_A
            ori r6, r6, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r8, 0x10
            beq- CLASSIC_B
            ori r6, r6, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r8, 0x40
            beq- CLASSIC_X
            ori r6, r6, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r8, 0x8
            beq- CLASSIC_Y
            ori r6, r6, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r8, 0x20
            beq- CLASSIC_L
            ori r6, r6, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r8, 0x2000
            beq- CLASSIC_R
            ori r6, r6, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r8, 0x200
            beq- CLASSIC_ZL
            ori r6, r6, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r8, 0x80
            beq- CLASSIC_ZR
            ori r6, r6, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r8, 0x4
            beq- CLASSIC_PLUS
            ori r6, r6, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r8, 0x400
            beq- CLASSIC_MINUS
            ori r6, r6, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r8, 0x1000
            beq- RETURN
            ori r6, r6, 0x1000    ; minus
      
      RETURN:
      andi. r0, r6, 0x9FFF
    • the above example may not have the ideal button mapping for the game you're hacking; notably, that example is for a game with the vertical Wiimote layout; the D-Pad directions will be all wrong if you're doing a horizontal (NES-style) game, so you will need to edit those and whatever else needs fixing

  2. open the CodeWrite app and put your assembly button injector into the ASM field, the address you identified before with the andi. instruction into the Insertion Address field, and click the right arrow at the bottom of the window

  3. copy the resulting Gecko code and add it to Tools > Cheats Manager > Gecko Codes in Dolphin

  4. either toggle the code off and on again or quit the game and restart it, so that Dolphin picks up the new code

  5. test the game
    • make sure you have a Classic Controller configured and buttons mapped for it in Controllers > Configure and that you don't have the same keys/buttons mapped for the Classic Controller as the Wii Remote--you need to be certain the inputs you're passing to the emulator are Classic inputs, not Wiimote inputs

  6. if it works, you just made a Classic Controller hack

Adding Features​

We could just stop there, but you can add a bit of polish to make things a bit friendlier. First, let's add D-Pad emulation on the left analog stick so players can use either the stick or D-Pad for directional input.
  1. go back to read_kpad_stick, which you identified earlier

  2. locate the place where you'll be inserting the D-Pad emulation routine
    • scroll down until you see a bctrl instruction--that's where the Nunchuk analog stick data gets written out--then keep scrolling down some more until you see two bctrl instructions close together, something like this:
      Code:
      8016e55c    mr        r12, r31            read_kpad_stick
      8016e560    addi    r3, r30, 12            read_kpad_stick
      8016e564    lha        r4, 0x002C (r29)    read_kpad_stick
      8016e568    lha        r5, 0x002E (r29)    read_kpad_stick
      8016e56c    lwz        r6, -0x6F8C (r13)    read_kpad_stick
      8016e570    lwz        r7, -0x6F88 (r13)    read_kpad_stick
      8016e574    mtctr    r12                    read_kpad_stick
      8016e578    bctrl                        read_kpad_stick
      8016e57c    mr        r12, r31            read_kpad_stick
      8016e580    addi    r3, r30, 20            read_kpad_stick
      8016e584    lha        r4, 0x0030 (r29)    read_kpad_stick
      8016e588    lha        r5, 0x0032 (r29)    read_kpad_stick
      8016e58c    lwz        r6, -0x6F8C (r13)    read_kpad_stick
      8016e590    lwz        r7, -0x6F88 (r13)    read_kpad_stick
      8016e594    mtctr    r12                    read_kpad_stick
      8016e598    bctrl                        read_kpad_stick
    • these are the left and right Classic Controller analog sticks, respectively

  3. write an assembly routine to convert Classic Controller analog input into D-Pad button presses; here's one I prepared earlier:
    Code:
    ; read_kpad_stick
      bctrl
      cmpwi r22, 0x1
      bne- NO_EMULATION
    
    ; magic
      bl GRAB
    MAGIC:
        THRESHOLD:  .float 0.5
        ZERO:       .float 0.0
    GRAB:
      mflr r3
    
      lfs f2, THRESHOLD-MAGIC(r3)
      lfs f3, ZERO-MAGIC(r3)
      lwz r4, -0x60(r30)    ; currently held
      lwz r5, -0x5C(r30)    ; pressed this frame
      lwz r6, -0x58(r30)    ; released this frame
    
      lfs f1, 0x0C(r30)     ; left stick x axis
      li r8, 0x1
      bl STICK_EMULATION
    
      lfs f1, 0x10(r30)     ; left stick y axis
      li r8, 0x4
      bl STICK_EMULATION
      b RETURN
    
    STICK_EMULATION:
      fabs f0, f1
      fcmpo cr0, f0, f2     ; is stick more than halfway?
      bltlr-
    
      fcmpo cr0, f1, f3     ; positive or negative direction?
      blt- AXIS_SKIP
      slwi r8, r8, 0x1      ; left->right / down->up
    
        AXIS_SKIP:
          and. r0, r6, r8       ; was this button already being held?
          bne- NOT_NEW
          or r5, r5, r8         ; add to buttons newly pressed
    
        NOT_NEW:
          or r4, r4, r8         ; add to buttons held
          andc. r6, r6, r8      ; remove from buttons released
    
      blr
    
    RETURN:
      stw r4, -0x60(r30)
      stw r5, -0x5C(r30)
      stw r6, -0x58(r30)
    
    NO_EMULATION:
  4. using CodeWrite, inject your custom routine at the address of the bctrl instruction for the stick you wish to use, like you did before for the button injector
    • for example, I'm using 8016e578, the left stick bctrl, as I write this post

    • again, the example routine above assumes that this is a vertical Wiimote game, the directions will need to be corrected for a horizontal Wiimote game

    • the above example is also specific to the left stick; even if you use the right stick bctrl, the function above reads the left stick values; you will need to edit the offsets if you're putting D-Pad emulation on the right stick

  5. add the code to Dolphin and test again
    • if it works, great; if the directions are wrong, fix them and test again; if it doesn't work at all, shrug

  6. next, add support for the Wii Remote pointer
    • even if the game you're hacking doesn't use the pointer, the Home Button Menu does, so it's always more convenient to have pointer emulation

  7. return to read_kpad_dpd, which you identified earlier

  8. locate the calc_dpd_variable function; Dolphin will not have recognized this for you so it will have an autogenerated name
    • scroll all the way to the bottom of read_kpad_dpd and look for the function call near the end, looking like this:
      Code:
      8016e078    mr        r3, r31            read_kpad_dpd
      8016e078    extsb    r4, r30            read_kpad_dpd
      8016e078    bl        ->0x8016D610    --> zz_8016d610_
    • that unrecognized function is calc_dpd_variable

  9. right click > Follow Branch

  10. right click > Rename Symbol > calc_dpd_variable
    • the start of this function should look pretty much, if not exactly like this:
      Code:
      8016d610    stwu    sp, -0x0020 (sp)    calc_dpd_variable
      8016d614    mflr    r0                    calc_dpd_variable
      8016d618    stw        r0, 0x0024 (sp)        calc_dpd_variable
    • that third instruction is an ideal location to insert pointer emulation; make a note of that address

  11. locate the SDK SCGetAspectRatio function
    • Dolphin is very good at incorrectly recognizing SCGetAspectRatio

    • use the symbol search to look for SCGetWpadSpeakerVolume; you will probably get 8 or more results, most of which are wrong

    • the first one is almost always the real SCGetAspectRatio, which Dolphin has mis-identified

    • for extra confidence, check if the function right above it has been identified by Dolphin as MyNandCallback and the function right below it has been identified as SCGetDisplayOffsetH; SCGetAspectRatio is usually sandwiched between those two functions which Dolphin often does correctly identify

    • make a note of the address where SCGetAspectRatio begins

  12. write an assembly routine to convert Classic Controller analog input into relative movement of the Wii Remote infra-red pointer, incorporating aspect ratio correction using SCGetAspectRatio; oh look, I found one:
    Code:
    ; calc_dpd_variable
      stw r0, 0x24(sp)
    
    ; player using real pointer? (gravity already valid)
      cmpwi r4, 0x0
      bne- NO_CLASSIC
    
    ; check for Classic Controller
      lbz r0, 0x5C(r3)
      cmpwi r0, 0x2
      bne- NO_CLASSIC
    
    ; magic
      bl GRAB
    MAGIC:
        GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
        ASPECT:     .float 1.3333333333
        MULTIPLIER: .float 0.015        ; pointer speed
        TIMER:      .hword 0
                    .hword 0
                    .hword 0
                    .hword 0
        DEADZONE:   .float 0.1
        MAX_RANGE:  .float 1.0
    GRAB:
      mflr r5
      stw r5, 0x0C(sp)      ; save magic pointer
    
    ; handle four separate timers for multiplayer
      slwi r7, r25, 0x1     ; player index
      addi r7, r7, TIMER-MAGIC
    
    STICK_WAKE:
      lfs f0, 0x74(r3)
      fabs f0, f0
      lfs f1, 0x78(r3)
      fabs f1, f1
      fadd f0, f0, f1
      lfs f2, DEADZONE-MAGIC(r5)
      fcmpo cr0, f0, f2
      blt- CHECK_TIMER
      li r6, 300
      b DELTA
    
    ; check pointer sleep timer
    CHECK_TIMER:
      lhax r6, r5, r7
      cmplwi r6, 0x0
      ble- NO_CLASSIC
      subi r6, r6, 0x1
    
    DELTA:
      sthx r6, r5, r7
      li r6, 0x2
      stb r6, 0x5E(r3)
      lwz r12, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
      mtlr r12
      blrl
      cmpwi r3, 0x1
      mr r3, r31            ; restore input pointer
      lwz r5, 0x0C(sp)      ; restore magic pointer
    
      lfs f2, ASPECT-MAGIC(r5)
      bne- FULLSCREEN
      fmuls f2, f2, f2       ; widescreen
    FULLSCREEN:
      lfs f3, MULTIPLIER-MAGIC(r5)
    
    ; pointer X axis
      lfs f0, 0x20(r3)
      lfs f1, 0x74(r3)       ; right stick X
      fdiv f1, f1, f2        ; divide by aspect ratio
      bl RANGE_CHECK
      stfs f0, 0x20(r3)
    
    ; pointer Y axis
      lfs f0, 0x24(r3)
      lfs f1, 0x78(r3)      ; right stick Y
      fneg f1, f1
      bl RANGE_CHECK
      stfs f0, 0x24(r3)
    
    RETURN:
      lwz r0, 0x24(sp)
      mtlr r0
      addi sp, sp, 0x20
      blr
    
    RANGE_CHECK:
      fmadd f0, f1, f3, f0
      lfs f1, MAX_RANGE-MAGIC(r5)
      fcmpu cr0, f0, f1
      blt CHECK_NEGATIVE
      fmr f0, f1
      b IN_RANGE
    
        CHECK_NEGATIVE:
          fneg f1, f1
          fcmpu cr0, f0, f1
          bgt IN_RANGE
          fmr f0, f1
         
        IN_RANGE:
          blr
    
    NO_CLASSIC:
    • depending on the game, you might want different implementations here: left stick, right stick, always on, toggled with a button; the example above supports four players, uses the right stick and the pointer is disabled after a few seconds of no movement

    • if you're using my example pointer routine, you must copy the address where you found SCGetAspectRatio into the following line:
      Code:
          GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
    • for example, in my case SCGetAspectRatio was at 80124550, so the line looks like this for me:
      Code:
          GETASPECT:  .int 0x80124550     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!

  13. back in CodeWrite, insert this routine at the address you found in calc_dpd_variable; I told you to make a note of it

  14. add the code to Dolphin and test it again
    • if everything is working at this point, you're done

    • if you're feeling generous, you can repeat this entire process for each disc revision and region

  15. post your new hack online!


Speaking of step 15 ...

View attachment 464593

From the creators of WarioWare, Nintendo SPD's Rhythm Heaven Fever aka Beat the Beat: Rhythm Paradise is a rhythm minigame collection which is elegantly simplistic in both gameplay and art-style. Like other entries in the series, Fever revolves almost entirely around pressing just two buttons. Since the series' Japan-only cult hit debut on Game Boy Advance, Rhythm Heaven has seen worldwide releases on Nintendo DS and 3DS, as well as this Wii version, generally regarded as the point where the series peaked. Things have been quiet for the series since 2016, so maybe it's time to revisit a classic.

USAEuropeJapanKorea

  1. Code:
    Classic Controller Support [Vague Rant]
    C216D618 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124550
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E578 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C4D4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C216EF08 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80125E40
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216FE68 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216DDC4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  3. Code:
    Classic Controller Support [Vague Rant]
    C216F808 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80126740
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C2170768 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216E6C4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  4. Code:
    Classic Controller Support [Vague Rant]
    C216D4E8 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124420
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E448 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C3A4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000

Button Mapping​

[TABLE=full]
[TR]
[TH]Wii Remote[/TH]
[TH]Classic Controller[/TH]
[TH]Game Function[/TH]
[/TR]
[TR]
[TD]Home[/TD]
[TD]Home
Remember to use the Right Stick[/TD]
[TD]Open/Close Home Button Menu[/TD]
[/TR]
[TR]
[TD]D-Pad[/TD]
[TD]D-Pad
Left Stick[/TD]
[TD]Menu Navigation[/TD]
[/TR]
[TR]
[TD]A[/TD]
[TD]A / Y / L / ZL[/TD]
[TD]Main Action[/TD]
[/TR]
[TR]
[TD]B[/TD]
[TD]B / X / R / ZR[/TD]
[TD]Secondary Action[/TD]
[/TR]
[TR]
[TD]Wiimote 1 & 2[/TD]
[TD]Not mapped[/TD]
[TD]Not used?[/TD]
[/TR]
[TR]
[TD]Plus[/TD]
[TD]Plus[/TD]
[TD]Pause
Skip Training[/TD]
[/TR]
[TR]
[TD]Minus[/TD]
[TD]Minus[/TD]
[TD]Not used?[/TD]
[/TR]
[/TABLE]

General Notes​

  • Being a game that only uses two buttons on a controller that has ~8 of them means I double-mapped A/B all over the place, so hopefully there's a layout that's comfortable for you. There's the Wiimote-style A+ZR, 3DS-style A+B, you can stick to the shoulder buttons, go nuts.

Technical Notes​

  • Rhythm Heaven Fever is the game from the tutorial above, so that's one giant technical note for this game.

  • That said, there's some mildly unique stuff going on here. Since I was going to be posting my assembly source in the tutorial, I figured I'd give it a once-over and clean it up a bit, so the D-Pad emulation got a bit of an optimization run vs. the original version and I tried to make the pointer feature as generic as possible so that it's more easily portable to other games. This version of the pointer function automatically switches off if there's no movement on the right stick and supports up to four players on Classic Controller (even though Rhythm Heaven Fever only supports two). As such, it should be pretty good to use in other games.
I also wanted to say thank you very much for your hard work and effort. It's easy to ask about specific games to be classic controller hacked, but it looks very complicated from your documentation. I guess I need a masters degree in computer science to do that. Thought it would be easier like to fiddle around with a gecko code, but this is real magic you are doing here. Yesterday I have tested de Blob on the wii u gamepad and it feels like a different game, always ment to be for the wii u system 🙏
 
  • Like
Reactions: Vague Rant
This would definitely be hugely creative and maybe (probably not) go some way to redeeming the game, but it's definitely beyond me right now. I've tried and failed to understand the GameCube PAD library once already, and I don't even own the DK Bongos to properly test those anyway. But that would be a great hack if it were possible.



blue-spirit's idea is an interesting one. I haven't played MKWii recently enough to really know why they put Trick and Drift on separate buttons for that game. The Classic layout for that game has always been pretty weird in general, it's offputting that you have to take your thumb off the stick to perform certain moves. Checking out the controls page on StrategyWiki again, it looks like the Classic ZL button is competely unused. Worst case scenario, maybe Trick could go there so it's at least on a button you can press while keeping your thumb on the left stick.


Mario Sports Mix and Rhythm Heaven Fever are both on my list of games to look into for Classic Controller hacks. One's probably a bit closer to happening than the other ...


Batman is actually one I looked at very early on in the process of making Classic Controller hacks. It looked complicated at the time, but it might be worth taking another look to see if I can make more sense of it now. I actually added Rhythm Heaven Fever to my list when you mentioned it previously, sorry I missed replying to that part! Definitely a good candidate ...



Before getting to the next game, I'm going to walk through my current process for adding Classic Controller support. Hopefully, this will make it easier for the next person who decides to CC-hack games.

Important Notes​

  • this guide will not be covering anything game-specific; e.g. motion detection, disabling "Please remove unsupported extension controller" error messages, etc.

  • before doing anything else you should probably boot up the game in an emulator or on console with a Classic Controller attached and see if there's any kind of error message

  • if you can't hack away the error message, there's no point doing the rest of this stuff

Things You'll Need​

  • some degree of understanding of PPC assembly code

  • the Dolphin emulator
    • open up Dolphin and select Options > Configuration > Interface > Enable Debugging UI

  • the CodeWrite Gecko C2 code assembler

  • a text editor; Notepad will work but something else with assembly syntax highlighting like Notepad++ might make it easier

  • a backup of the game you're looking to hack

Identifying Functions​

  1. Before booting up the game in Dolphin, right click it and go to Properties > Filesystem
    • skim through the Data Partition looking for any files with the extension .elf or .map

    • these may be unstripped binaries or function name maps, respectively; however, .map is also a pretty generic extension, so it might literally be maps in the video game sense and not the symbol maps we're looking for

    • if you found any .elf or .map files which look useful, extract them (right click > Extract File...) to somewhere that seems sensible on your PC

    • Dolphin can load .elf files directly and .map files can be opened with Symbols > Load Other Map File...

    • developers are not supposed to leave these sorts of files on retail discs, so they're sort of rare-ish and it's not very likely you'll find either

    • there is a list of known Wii games with debug symbols at Retro Reversing

  2. proceeding with the assumption that nobody left behind any helpful symbols, load the game you're trying to hack and pause execution

  3. from the Dolphin menu, choose Symbols > Generate Symbols From > Signature Database
    • Dolphin includes an internal database of function signatures, which are sort of like fingerprints for code

    • Dolphin will use this database to identify as many functions as it recognizes, based on the fact that they appear in and are fairly similar across many games

    • this feature is absolutely not foolproof: there are many functions Dolphin will not identify and many that it will incorrectly identify

    • if Dolphin detects a function but doesn't recognize it, it will give it a name based on the address at which it appears and also color-code it in the disassembler view

    • if Dolphin completely fails to detect a function at any given location, it will display in white with no function name

  4. using the Symbols search field on the left side of the Code tab, try to locate the KPADRead/KPADiRead function
    • older SDK versions have KPADRead while newer SDKs (games released from about 2010 onward?) have KPADiRead; for the sake of simplicity I will just refer to this function as KPADRead for the rest of this post

    • Dolphin usually won't recognize KPADRead itself, but it may recognize child functions called within KPADRead or its children

    • often, select_1obj_continue is detected by Dolphin; this is a child function of read_kpad_dpd which is a child of KPADRead
      • as I write this post, Dolphin has not recognized select_1obj_continue, so I had to find KPADRead another way; for now let's just pretend it worked

    • click on select_1obj_continue in the search results, look in the bottom left Callers section and click either of those calls from an unrecognized function; that unrecognized function is read_kpad_dpd

    • right click anywhere inside that unrecognized function and click Rename Symbol; rename the symbol to read_kpad_dpd

    • whenever it seems appropriate, use Symbols > Save Symbol Map to ensure you don't lose any progress

    • look down at the Callers again and click on any of the calls you see from an unrecognized function; that unrecognized function is KPADRead

  5. right click > Rename Symbol > KPADRead; this is good progress

  6. identify the other major KPAD read functions
    • if you just navigated back here from read_kpad_dpd like I directed, you're currently looking at a section of the disassembler which should read something like this:
      Code:
      8016fb58    mr    r3, r31            KPADRead
      8016fb5c    mr    r4, r19            KPADRead
      8016fb60    bl    ->0x8016E410    --> zz_8016e410_
      8016fb64    mr    r3, r31            KPADRead
      8016fb68    mr    r4, r19            KPADRead
      8016fb6c    bl    ->0x8016C920    --> zz_8016c920_
      8016fb70    mr    r3, r31            KPADRead
      8016fb74    mr    r4, r19            KPADRead
      8016fb78    bl    ->0x8016DBF0    --> read_kpad_dpd
    • the two function calls (bl instructions) right above read_kpad_dpd are to read_kpad_stick/ext (varies by SDK version, I will just call it stick from now on) and read_kpad_acc

    • right click on the first one and select Follow Branch

    • you're now inside read_kpad_stick, so right click > Rename Symbol > read_kpad_stick

    • go back to KPADRead from the Callers list

    • repeat the same process for the other unrecognized function, which is read_kpad_acc, so that you eventually have this:
      Code:
      8016fb58    mr    r3, r31            KPADRead
      8016fb5c    mr    r4, r19            KPADRead
      8016fb60    bl    ->0x8016E410    --> read_kpad_stick
      8016fb64    mr    r3, r31            KPADRead
      8016fb68    mr    r4, r19            KPADRead
      8016fb6c    bl    ->0x8016C920    --> read_kpad_acc
      8016fb70    mr    r3, r31            KPADRead
      8016fb74    mr    r4, r19            KPADRead
      8016fb78    bl    ->0x8016DBF0    --> read_kpad_dpd
  7. find where the buttons are read by KPAD
    • this is the first significant fork between older and newer SDK games: older games read the buttons directly inside KPADRead while newer games call a separate read_kpad_button function

    • scroll up slowly until you get to another function call (bl instruction)

    • scroll up three more instructions past the bl and check whether the instruction is something that looks more like this:
      Code:
      stw    r0, 0x0068 (r31)
      ... or more like this:
      Code:
      lwz    r8, 0x0060 (r21)
    • the exact registers may not be the same, but the instructions (stw vs. lwz) and the offsets (0x0068 vs. 0x0060 should be persistent

    • if you have the first one, this is an older SDK game where buttons are read inside KPADRead
      • scroll up some more until you reach an instruction that looks like this:
        Code:
        andi.    r0, r7, 0x9FFF

    • if you have the second one, this is a newer SDK game where the buttons are read in a separate read_kpad_button function (the bl we just passed)
      • right click on the bl instruction and select Follow Branch

      • right click > Rename Symbol > read_kpad_button

      • look ahead one instruction to find the following:
        Code:
        andi.    r0, r6, 0x9FFF
  8. make a note of the address for the andi. instruction you just found; congratulations, that's the place where you'll be injecting the Classic Controller buttons into the Wii Remote!

Injecting Buttons​

  1. now, write a custom routine in PPC assembly which takes the button values from the Classic Controller register and drops them into the Wii Remote register; fine, I'll start:

    Old SDKNew SDK

    1. Code:
      ; KPADRead
      ; r4 holds extType
      ; r7 holds wiimote bitfield
      ; r8 holds wiimote+nunchuk bitfield
      ; r9 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r9, 0x800
            beq- CLASSIC_UP
            ori r7, r7, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r9, 0x1
            beq- CLASSIC_DOWN
            ori r7, r7, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r9, 0x4000
            beq- CLASSIC_LEFT
            ori r7, r7, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r9, 0x2
            beq- CLASSIC_RIGHT
            ori r7, r7, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r9, 0x8000
            beq- CLASSIC_A
            ori r7, r7, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r9, 0x10
            beq- CLASSIC_B
            ori r7, r7, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r9, 0x40
            beq- CLASSIC_X
            ori r7, r7, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r9, 0x8
            beq- CLASSIC_Y
            ori r7, r7, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r9, 0x20
            beq- CLASSIC_L
            ori r7, r7, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r9, 0x2000
            beq- CLASSIC_R
            ori r7, r7, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r9, 0x200
            beq- CLASSIC_ZL
            ori r7, r7, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r9, 0x80
            beq- CLASSIC_ZR
            ori r7, r7, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r9, 0x4
            beq- CLASSIC_PLUS
            ori r7, r7, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r9, 0x400
            beq- CLASSIC_MINUS
            ori r7, r7, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r9, 0x1000
            beq- RETURN
            ori r7, r7, 0x1000    ; minus
      
      RETURN:
        andi. r0, r7, 0x9FFF
    2. Code:
      ; read_kpad_button
      ; r4 holds extType
      ; r6 holds wiimote bitfield
      ; r7 holds wiimote+nunchuk bitfield
      ; r8 holds classic bitfield
      
      CLASSIC:
        cmpwi r4, 0x2
        bne- RETURN
      
          CLASSIC_HOME:
            andi. r0, r8, 0x800
            beq- CLASSIC_UP
            ori r6, r6, 0x8000    ; home
      
          CLASSIC_UP:
            andi. r0, r8, 0x1
            beq- CLASSIC_DOWN
            ori r6, r6, 0x8       ; up
      
          CLASSIC_DOWN:
            andi. r0, r8, 0x4000
            beq- CLASSIC_LEFT
            ori r6, r6, 0x4       ; down
      
          CLASSIC_LEFT:
            andi. r0, r8, 0x2
            beq- CLASSIC_RIGHT
            ori r6, r6, 0x1       ; left
      
          CLASSIC_RIGHT:
            andi. r0, r8, 0x8000
            beq- CLASSIC_A
            ori r6, r6, 0x2       ; right
      
          CLASSIC_A:
            andi. r0, r8, 0x10
            beq- CLASSIC_B
            ori r6, r6, 0x800     ; a
      
          CLASSIC_B:
            andi. r0, r8, 0x40
            beq- CLASSIC_X
            ori r6, r6, 0x400     ; b
      
          CLASSIC_X:
            andi. r0, r8, 0x8
            beq- CLASSIC_Y
            ori r6, r6, 0x100     ; 2
      
          CLASSIC_Y:
            andi. r0, r8, 0x20
            beq- CLASSIC_L
            ori r6, r6, 0x200     ; 1
      
          CLASSIC_L:
            andi. r0, r8, 0x2000
            beq- CLASSIC_R
            ori r6, r6, 0x800     ; a
      
          CLASSIC_R:
            andi. r0, r8, 0x200
            beq- CLASSIC_ZL
            ori r6, r6, 0x400     ; b
      
          CLASSIC_ZL:
            andi. r0, r8, 0x80
            beq- CLASSIC_ZR
            ori r6, r6, 0x800     ; a
      
          CLASSIC_ZR:
            andi. r0, r8, 0x4
            beq- CLASSIC_PLUS
            ori r6, r6, 0x400     ; b
      
          CLASSIC_PLUS:
            andi. r0, r8, 0x400
            beq- CLASSIC_MINUS
            ori r6, r6, 0x10      ; plus
      
          CLASSIC_MINUS:
            andi. r0, r8, 0x1000
            beq- RETURN
            ori r6, r6, 0x1000    ; minus
      
      RETURN:
      andi. r0, r6, 0x9FFF
    • the above example may not have the ideal button mapping for the game you're hacking; notably, that example is for a game with the vertical Wiimote layout; the D-Pad directions will be all wrong if you're doing a horizontal (NES-style) game, so you will need to edit those and whatever else needs fixing

  2. open the CodeWrite app and put your assembly button injector into the ASM field, the address you identified before with the andi. instruction into the Insertion Address field, and click the right arrow at the bottom of the window

  3. copy the resulting Gecko code and add it to Tools > Cheats Manager > Gecko Codes in Dolphin

  4. either toggle the code off and on again or quit the game and restart it, so that Dolphin picks up the new code

  5. test the game
    • make sure you have a Classic Controller configured and buttons mapped for it in Controllers > Configure and that you don't have the same keys/buttons mapped for the Classic Controller as the Wii Remote--you need to be certain the inputs you're passing to the emulator are Classic inputs, not Wiimote inputs

  6. if it works, you just made a Classic Controller hack

Adding Features​

We could just stop there, but you can add a bit of polish to make things a bit friendlier. First, let's add D-Pad emulation on the left analog stick so players can use either the stick or D-Pad for directional input.
  1. go back to read_kpad_stick, which you identified earlier

  2. locate the place where you'll be inserting the D-Pad emulation routine
    • scroll down until you see a bctrl instruction--that's where the Nunchuk analog stick data gets written out--then keep scrolling down some more until you see two bctrl instructions close together, something like this:
      Code:
      8016e55c    mr        r12, r31            read_kpad_stick
      8016e560    addi    r3, r30, 12            read_kpad_stick
      8016e564    lha        r4, 0x002C (r29)    read_kpad_stick
      8016e568    lha        r5, 0x002E (r29)    read_kpad_stick
      8016e56c    lwz        r6, -0x6F8C (r13)    read_kpad_stick
      8016e570    lwz        r7, -0x6F88 (r13)    read_kpad_stick
      8016e574    mtctr    r12                    read_kpad_stick
      8016e578    bctrl                        read_kpad_stick
      8016e57c    mr        r12, r31            read_kpad_stick
      8016e580    addi    r3, r30, 20            read_kpad_stick
      8016e584    lha        r4, 0x0030 (r29)    read_kpad_stick
      8016e588    lha        r5, 0x0032 (r29)    read_kpad_stick
      8016e58c    lwz        r6, -0x6F8C (r13)    read_kpad_stick
      8016e590    lwz        r7, -0x6F88 (r13)    read_kpad_stick
      8016e594    mtctr    r12                    read_kpad_stick
      8016e598    bctrl                        read_kpad_stick
    • these are the left and right Classic Controller analog sticks, respectively

  3. write an assembly routine to convert Classic Controller analog input into D-Pad button presses; here's one I prepared earlier:
    Code:
    ; read_kpad_stick
      bctrl
      cmpwi r22, 0x1
      bne- NO_EMULATION
    
    ; magic
      bl GRAB
    MAGIC:
        THRESHOLD:  .float 0.5
        ZERO:       .float 0.0
    GRAB:
      mflr r3
    
      lfs f2, THRESHOLD-MAGIC(r3)
      lfs f3, ZERO-MAGIC(r3)
      lwz r4, -0x60(r30)    ; currently held
      lwz r5, -0x5C(r30)    ; pressed this frame
      lwz r6, -0x58(r30)    ; released this frame
    
      lfs f1, 0x0C(r30)     ; left stick x axis
      li r8, 0x1
      bl STICK_EMULATION
    
      lfs f1, 0x10(r30)     ; left stick y axis
      li r8, 0x4
      bl STICK_EMULATION
      b RETURN
    
    STICK_EMULATION:
      fabs f0, f1
      fcmpo cr0, f0, f2     ; is stick more than halfway?
      bltlr-
    
      fcmpo cr0, f1, f3     ; positive or negative direction?
      blt- AXIS_SKIP
      slwi r8, r8, 0x1      ; left->right / down->up
    
        AXIS_SKIP:
          and. r0, r6, r8       ; was this button already being held?
          bne- NOT_NEW
          or r5, r5, r8         ; add to buttons newly pressed
    
        NOT_NEW:
          or r4, r4, r8         ; add to buttons held
          andc. r6, r6, r8      ; remove from buttons released
    
      blr
    
    RETURN:
      stw r4, -0x60(r30)
      stw r5, -0x5C(r30)
      stw r6, -0x58(r30)
    
    NO_EMULATION:
  4. using CodeWrite, inject your custom routine at the address of the bctrl instruction for the stick you wish to use, like you did before for the button injector
    • for example, I'm using 8016e578, the left stick bctrl, as I write this post

    • again, the example routine above assumes that this is a vertical Wiimote game, the directions will need to be corrected for a horizontal Wiimote game

    • the above example is also specific to the left stick; even if you use the right stick bctrl, the function above reads the left stick values; you will need to edit the offsets if you're putting D-Pad emulation on the right stick

  5. add the code to Dolphin and test again
    • if it works, great; if the directions are wrong, fix them and test again; if it doesn't work at all, shrug

  6. next, add support for the Wii Remote pointer
    • even if the game you're hacking doesn't use the pointer, the Home Button Menu does, so it's always more convenient to have pointer emulation

  7. return to read_kpad_dpd, which you identified earlier

  8. locate the calc_dpd_variable function; Dolphin will not have recognized this for you so it will have an autogenerated name
    • scroll all the way to the bottom of read_kpad_dpd and look for the function call near the end, looking like this:
      Code:
      8016e078    mr        r3, r31            read_kpad_dpd
      8016e078    extsb    r4, r30            read_kpad_dpd
      8016e078    bl        ->0x8016D610    --> zz_8016d610_
    • that unrecognized function is calc_dpd_variable

  9. right click > Follow Branch

  10. right click > Rename Symbol > calc_dpd_variable
    • the start of this function should look pretty much, if not exactly like this:
      Code:
      8016d610    stwu    sp, -0x0020 (sp)    calc_dpd_variable
      8016d614    mflr    r0                    calc_dpd_variable
      8016d618    stw        r0, 0x0024 (sp)        calc_dpd_variable
    • that third instruction is an ideal location to insert pointer emulation; make a note of that address

  11. locate the SDK SCGetAspectRatio function
    • Dolphin is very good at incorrectly recognizing SCGetAspectRatio

    • use the symbol search to look for SCGetWpadSpeakerVolume; you will probably get 8 or more results, most of which are wrong

    • the first one is almost always the real SCGetAspectRatio, which Dolphin has mis-identified

    • for extra confidence, check if the function right above it has been identified by Dolphin as MyNandCallback and the function right below it has been identified as SCGetDisplayOffsetH; SCGetAspectRatio is usually sandwiched between those two functions which Dolphin often does correctly identify

    • make a note of the address where SCGetAspectRatio begins

  12. write an assembly routine to convert Classic Controller analog input into relative movement of the Wii Remote infra-red pointer, incorporating aspect ratio correction using SCGetAspectRatio; oh look, I found one:
    Code:
    ; calc_dpd_variable
      stw r0, 0x24(sp)
    
    ; player using real pointer? (gravity already valid)
      cmpwi r4, 0x0
      bne- NO_CLASSIC
    
    ; check for Classic Controller
      lbz r0, 0x5C(r3)
      cmpwi r0, 0x2
      bne- NO_CLASSIC
    
    ; magic
      bl GRAB
    MAGIC:
        GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
        ASPECT:     .float 1.3333333333
        MULTIPLIER: .float 0.015        ; pointer speed
        TIMER:      .hword 0
                    .hword 0
                    .hword 0
                    .hword 0
        DEADZONE:   .float 0.1
        MAX_RANGE:  .float 1.0
    GRAB:
      mflr r5
      stw r5, 0x0C(sp)      ; save magic pointer
    
    ; handle four separate timers for multiplayer
      slwi r7, r25, 0x1     ; player index
      addi r7, r7, TIMER-MAGIC
    
    STICK_WAKE:
      lfs f0, 0x74(r3)
      fabs f0, f0
      lfs f1, 0x78(r3)
      fabs f1, f1
      fadd f0, f0, f1
      lfs f2, DEADZONE-MAGIC(r5)
      fcmpo cr0, f0, f2
      blt- CHECK_TIMER
      li r6, 300
      b DELTA
    
    ; check pointer sleep timer
    CHECK_TIMER:
      lhax r6, r5, r7
      cmplwi r6, 0x0
      ble- NO_CLASSIC
      subi r6, r6, 0x1
    
    DELTA:
      sthx r6, r5, r7
      li r6, 0x2
      stb r6, 0x5E(r3)
      lwz r12, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
      mtlr r12
      blrl
      cmpwi r3, 0x1
      mr r3, r31            ; restore input pointer
      lwz r5, 0x0C(sp)      ; restore magic pointer
    
      lfs f2, ASPECT-MAGIC(r5)
      bne- FULLSCREEN
      fmuls f2, f2, f2       ; widescreen
    FULLSCREEN:
      lfs f3, MULTIPLIER-MAGIC(r5)
    
    ; pointer X axis
      lfs f0, 0x20(r3)
      lfs f1, 0x74(r3)       ; right stick X
      fdiv f1, f1, f2        ; divide by aspect ratio
      bl RANGE_CHECK
      stfs f0, 0x20(r3)
    
    ; pointer Y axis
      lfs f0, 0x24(r3)
      lfs f1, 0x78(r3)      ; right stick Y
      fneg f1, f1
      bl RANGE_CHECK
      stfs f0, 0x24(r3)
    
    RETURN:
      lwz r0, 0x24(sp)
      mtlr r0
      addi sp, sp, 0x20
      blr
    
    RANGE_CHECK:
      fmadd f0, f1, f3, f0
      lfs f1, MAX_RANGE-MAGIC(r5)
      fcmpu cr0, f0, f1
      blt CHECK_NEGATIVE
      fmr f0, f1
      b IN_RANGE
    
        CHECK_NEGATIVE:
          fneg f1, f1
          fcmpu cr0, f0, f1
          bgt IN_RANGE
          fmr f0, f1
         
        IN_RANGE:
          blr
    
    NO_CLASSIC:
    • depending on the game, you might want different implementations here: left stick, right stick, always on, toggled with a button; the example above supports four players, uses the right stick and the pointer is disabled after a few seconds of no movement

    • if you're using my example pointer routine, you must copy the address where you found SCGetAspectRatio into the following line:
      Code:
          GETASPECT:  .int 0x00000000     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!
    • for example, in my case SCGetAspectRatio was at 80124550, so the line looks like this for me:
      Code:
          GETASPECT:  .int 0x80124550     ; PUT THE ADDRESS FOR SCGetAspectRatio HERE!

  13. back in CodeWrite, insert this routine at the address you found in calc_dpd_variable; I told you to make a note of it

  14. add the code to Dolphin and test it again
    • if everything is working at this point, you're done

    • if you're feeling generous, you can repeat this entire process for each disc revision and region

  15. post your new hack online!


Speaking of step 15 ...

View attachment 464593

From the creators of WarioWare, Nintendo SPD's Rhythm Heaven Fever aka Beat the Beat: Rhythm Paradise is a rhythm minigame collection which is elegantly simplistic in both gameplay and art-style. Like other entries in the series, Fever revolves almost entirely around pressing just two buttons. Since the series' Japan-only cult hit debut on Game Boy Advance, Rhythm Heaven has seen worldwide releases on Nintendo DS and 3DS, as well as this Wii version, generally regarded as the point where the series peaked. Things have been quiet for the series since 2016, so maybe it's time to revisit a classic.

USAEuropeJapanKorea

  1. Code:
    Classic Controller Support [Vague Rant]
    C216D618 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124550
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E578 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C4D4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C216EF08 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80125E40
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216FE68 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216DDC4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  3. Code:
    Classic Controller Support [Vague Rant]
    C216F808 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80126740
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C2170768 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216E6C4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000
  4. Code:
    Classic Controller Support [Vague Rant]
    C216D4E8 00000024
    90010024 2C040000
    40820110 8803005C
    2C000002 40820104
    48000021 80124420
    3FAAAAAB 3C75C28F
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4180000C
    38C0012C 48000014
    7CC53AAE 28060000
    408100A0 38C6FFFF
    7CC53B2E 38C00002
    98C3005E 81850000
    7D8803A6 4E800021
    2C030001 7FE3FB78
    80A1000C C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230074 FC211024
    4800002D D0030020
    C0030024 C0230078
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C0250018 FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    C216E448 00000012
    4E800421 2C160001
    40820080 4800000D
    3F000000 00000000
    7C6802A6 C0430000
    C0630004 809EFFA0
    80BEFFA4 80DEFFA8
    C03E000C 39000001
    48000015 C03E0010
    39000004 48000009
    48000034 FC000A10
    FC001040 4D800020
    FC011840 41800008
    5508083C 7CC04039
    40820008 7CA54378
    7C844378 7CC64079
    4E800020 909EFFA0
    90BEFFA4 90DEFFA8
    60000000 00000000
    C216C3A4 00000019
    2C040002 408200B8
    71000800 41820008
    60C68000 71000001
    41820008 60C60008
    71004000 41820008
    60C60004 71000002
    41820008 60C60001
    71008000 41820008
    60C60002 71000010
    41820008 60C60800
    71000040 41820008
    60C60400 71000008
    41820008 60C60400
    71000020 41820008
    60C60800 71002000
    41820008 60C60800
    71000200 41820008
    60C60400 71000080
    41820008 60C60800
    71000004 41820008
    60C60400 71000400
    41820008 60C60010
    71001000 41820008
    60C61000 70C09FFF
    60000000 00000000

Button Mapping​

[TABLE=full]
[TR]
[TH]Wii Remote[/TH]
[TH]Classic Controller[/TH]
[TH]Game Function[/TH]
[/TR]
[TR]
[TD]Home[/TD]
[TD]Home
Remember to use the Right Stick[/TD]
[TD]Open/Close Home Button Menu[/TD]
[/TR]
[TR]
[TD]D-Pad[/TD]
[TD]D-Pad
Left Stick[/TD]
[TD]Menu Navigation[/TD]
[/TR]
[TR]
[TD]A[/TD]
[TD]A / Y / L / ZL[/TD]
[TD]Main Action[/TD]
[/TR]
[TR]
[TD]B[/TD]
[TD]B / X / R / ZR[/TD]
[TD]Secondary Action[/TD]
[/TR]
[TR]
[TD]Wiimote 1 & 2[/TD]
[TD]Not mapped[/TD]
[TD]Not used?[/TD]
[/TR]
[TR]
[TD]Plus[/TD]
[TD]Plus[/TD]
[TD]Pause
Skip Training[/TD]
[/TR]
[TR]
[TD]Minus[/TD]
[TD]Minus[/TD]
[TD]Not used?[/TD]
[/TR]
[/TABLE]

General Notes​

  • Being a game that only uses two buttons on a controller that has ~8 of them means I double-mapped A/B all over the place, so hopefully there's a layout that's comfortable for you. There's the Wiimote-style A+ZR, 3DS-style A+B, you can stick to the shoulder buttons, go nuts.

Technical Notes​

  • Rhythm Heaven Fever is the game from the tutorial above, so that's one giant technical note for this game.

  • That said, there's some mildly unique stuff going on here. Since I was going to be posting my assembly source in the tutorial, I figured I'd give it a once-over and clean it up a bit, so the D-Pad emulation got a bit of an optimization run vs. the original version and I tried to make the pointer feature as generic as possible so that it's more easily portable to other games. This version of the pointer function automatically switches off if there's no movement on the right stick and supports up to four players on Classic Controller (even though Rhythm Heaven Fever only supports two). As such, it should be pretty good to use in other games.
THANK U SOO MUCH!
Also i think the 1 button on WiiMote is used in the hi-hat toy to play a demo, haha
 
  • Like
Reactions: Vague Rant
Hi @Vague Rant and thank you for those amazing wii stuffs. Do you know if there is a place to download cc hack already dolpatched iso ? (for making wii u injects) My computer is a piece of s*** and i can't make it myself. Many thanks.
 
@Vague Rant So, i tried classic controller emulation via Dolphin and a mayflash dolphin bar, and i have a good idea of what the controls should be now:

Gather water: Y
Jump: B
Control water left and right: L stick
Burst water up (ability found in world 4, up D pad on wiimote) ZR
Minus button on pro controller - view map

These would be good because:
1. Gathering water with a button your thumb can easily reach would be cool
2. Jumping with B could also be convenient
3. ZR to splash the water up (up d pad ability later in the game) would be easier then reaching over to the CC d-pad
I have no idea how the other motion controls will work. Thanks!
 
  • Like
Reactions: Vague Rant
Hey @Vague Rant, just wanted to say I got the Paper Mario one working on my Dolphin Android... I obviously done something wrong last time so just wanted to update you and for anyone else. Great work man, game feels so much better now! :grog:
 
  • Like
Reactions: Vague Rant
Nice, I'm glad you eventually got DK Returns running on the GamePad, super awesome to hear that it works. Thanks for letting me know about Wario as well. The broken controls like that are usually a symptom of the Wii game not correctly detecting the Classic Controller; the same thing happens with injections of Excite Truck unless you enable the "Force Classic Controller connected" checkbox in the injector tool. I wonder if Wario could be fixed with that? If not, it's out of my hands, it's an issue with the Classic Controller emulation in Wii VC injection where it's just not compatible with some games. Unfortunately, that's the case for New Super Mario Bros. Wii, injected versions don't recognize the Classic Controller. Silent Hill definitely sounds like it's on the more complicated end of the spectrum, since it has multiple different hand motions that have to be recognized, so that's probably on the less-likely end, sorry.


That sounds like a great idea. It seems relatively feasible. I think the major complication would be remapping the inputs on the Wii Remote itself, since you'd need a different layout (A to jump, B to shoot, etc.). To date, I haven't done any remapping of original game inputs, only adding additional mappings on the Classic Controller, so I would need to figure out how to do that, but it does sound cool. I assume you mean retaining the original IR pointer for aiming, right? So you'd move on the Nunchuk, shoot/jump on B/A, maybe Morph Ball on Nunchuk C like in Prime, lock on camera on Nunchuk Z ... Concentration could either use the original motion controls or be mapped on Wiimote Minus or something, since the game doesn't use Minus anyway as far as I can tell. This is definitely an interesting one. As always, no promises, but my curiosity is piqued.



View attachment 462240

Animal Crossing: City Folk aka Let's Go to the City is the third game in Nintendo's Animal Crossing life sim series. The main addition to this entry was Wii Speak support the titular city, expanding on the small town areas of previous entries. This perhaps falls into the "controversial Wii sequel" series, with many complaints about the lack of improvements over the earlier games and the loss of NES games, since Nintendo were now selling those on the Wii Shop Channel instead of giving them away for free. Still, though not revolutionary, City Folk has the same charming atmosphere as the rest of the franchise. And at least it's a real Animal Crossing game. Cough, Amiibo Festival.
Pointer on Left Stick

USAUSA (Rev 1)EuropeEurope (Rev 1)Japan (Rev 1)Korea (Rev 1)

  1. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA624 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA68C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE160 48000010
    C2443CE4 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443D00 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE750 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D338
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23BF784 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  2. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA624 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA68C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE284 48000010
    C2443F4C 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443F68 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE9B8 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D5A0
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23BF9EC 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  3. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA784 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA7EC 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CDFB0 48000010
    C2443CC8 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443CE4 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE5A0 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D188
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23BF5D4 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  4. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA784 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA7EC 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE0D4 48000010
    C2443F30 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443F4C 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE808 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D3F0
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23BF83C 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  5. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA8DC 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA944 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE300 48000010
    C2443E80 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443E9C 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE8F4 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D4DC
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23BF928 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  6. Code:
    Classic Controller Support (Pointer on Left Stick) [Vague Rant, crediar]
    C20FA6A4 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA70C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CF840 48000010
    C244D8C4 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C244D8E0 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23C72FC 0000001C
    88A40028 2C050002
    408200CC 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803B 60C65EE4
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450084 40820008
    EC4200B2 C0650088
    C0030020 C023006C
    FC211024 48000039
    D0030020 C0030024
    C0230070 FC200850
    48000025 D0030024
    38000000 9003006C
    90030070 8001000C
    7C0803A6 38210010
    4E800020 FC0100FA
    C025008C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    3FAAAAAB 3CA3D70A
    3F800000 9421FFC0
    60000000 00000000
    C23C8330 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
Pointer on Right Stick

USAUSA (Rev 1)EuropeEurope (Rev 1)Japan (Rev 1)Korea (Rev 1)

  1. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA624 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA68C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE160 48000010
    C2443CE4 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443D00 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE750 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D338
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23BF784 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  2. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA624 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA68C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE284 48000010
    C2443F4C 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443F68 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE9B8 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D5A0
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23BF9EC 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  3. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA784 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA7EC 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CDFB0 48000010
    C2443CC8 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443CE4 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE5A0 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D188
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23BF5D4 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  4. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA784 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA7EC 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE0D4 48000010
    C2443F30 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443F4C 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE808 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D3F0
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23BF83C 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  5. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA8DC 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA944 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CE300 48000010
    C2443E80 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C2443E9C 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23BE8F4 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803A 60C6D4DC
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23BF928 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000
  6. Code:
    Classic Controller Support (Pointer on Right Stick) [Vague Rant, crediar]
    C20FA6A4 00000003
    2C030002 40820008
    3863FFFF 3803FF04
    60000000 00000000
    C20FA70C 00000003
    2C040002 40820008
    3884FFFF 20640001
    60000000 00000000
    042CF840 48000010
    C244D8C4 00000003
    2C000001 4182000C
    C0230104 48000008
    C0230074 00000000
    C244D8E0 00000003
    2C000001 4182000C
    C0230108 48000008
    C0230078 00000000
    C23C72FC 0000001A
    88A40028 2C050002
    408200C0 88A3005E
    2C050002 4C820020
    9421FFF0 7C0802A6
    9001000C 90610008
    3CC0803B 60C65EE4
    7CC803A6 4E800021
    2C030001 80610008
    48000005 7CA802A6
    C0450078 40820008
    EC4200B2 C065007C
    C0030020 C0230074
    FC211024 4800002D
    D0030020 C0030024
    C0230078 FC200850
    48000019 D0030024
    8001000C 7C0803A6
    38210010 4E800020
    FC0100FA C0250080
    FC000800 4180000C
    FC000890 48000014
    FC200850 FC000800
    41810008 FC000890
    4E800020 3FAAAAAB
    3CA3D70A 3F800000
    9421FFC0 00000000
    C23C8330 00000026
    901F0068 811F0060
    48000061 80DF0000
    7D083378 911F0000
    7D0840F8 80DF0008
    7CC84038 911F0008
    811F0064 4800003D
    80DF0004 7D083378
    911F0004 71060040
    41820010 38C00002
    98DF005E 480000E0
    71060080 418200D8
    88DF005E 68C60002
    98DF005E 480000C8
    38E00000 71060800
    41820008 60E78000
    71060001 41820008
    60E70008 71064000
    41820008 60E70004
    71060002 41820008
    60E70001 71068000
    41820008 60E70002
    71060010 41820008
    60E70800 71060040
    41820008 60E70400
    71060008 41820008
    60E71080 71060020
    41820008 60E70180
    71062000 41820008
    60E70080 71060200
    41820008 60E72000
    71060080 41820008
    60E71040 71060004
    4182000C 60E70050
    48000004 71060400
    41820008 60E70090
    71061000 41820008
    60E70200 7CE83B78
    4E800020 00000000

Button Mapping​

[TABLE=full]
[TR]
[TH]Wii Remote & Nunchuk[/TH]
[TH]Classic Controller[/TH]
[TH]Game Function[/TH]
[/TR]
[TR]
[TD]Wiimote Home[/TD]
[TD]Home
Home Menu works as normal but remember to enable the pointer with L and use the correct stick for your code[/TD]
[TD]Open/Close Home Button Menu[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad[/TD]
[TD]D-Pad[/TD]
[TD]Up: Change Camera
Left/Right: Change Tool
Down: Put Away Tool[/TD]
[/TR]
[TR]
[TD]Wiimote A[/TD]
[TD]A[/TD]
[TD]Confirm
Action[/TD]
[/TR]
[TR]
[TD]Wiimote B[/TD]
[TD]B[/TD]
[TD]Cancel
Run
Pick Up Items[/TD]
[/TR]
[TR]
[TD]Wiimote Plus[/TD]
[TD]Plus
ZR[/TD]
[TD]Open/Close Map
Next Tab[/TD]
[/TR]
[TR]
[TD]Wiimote Minus[/TD]
[TD]X
ZL[/TD]
[TD]Open/Close Inventory
Previous Tab[/TD]
[/TR]
[TR]
[TD]Wiimote 1[/TD]
[TD]Minus[/TD]
[TD]Take Photo[/TD]
[/TR]
[TR]
[TD]Wiimote 2[/TD]
[TD]Y[/TD]
[TD]Open/Close Photos[/TD]
[/TR]
[TR]
[TD]Nunchuk Analog Stick[/TD]
[TD]Left Stick[/TD]
[TD]Movement[/TD]
[/TR]
[TR]
[TD]Nunchuk C[/TD]
[TD]Not mapped
(use A instead)[/TD]
[TD]Confirm
Action[/TD]
[/TR]
[TR]
[TD]Nunchuk Z[/TD]
[TD]R[/TD]
[TD]Cancel
Run
Pick Up Items[/TD]
[/TR]
[TR]
[TD]Wiimote IR Pointer[/TD]
[TD]L (toggle)
Left Stick or Right Stick
(depends on code used)[/TD]
[TD]Move Cursor[/TD]
[/TR]
[/TABLE]

General Notes​

  • Two code varieties for this one, choose whichever feels more natural to you. IR aiming is pretty important to City Folk, with all inventory manipulation being IR-based. If you choose the Left Stick code, the Left Stick toggles between movement and IR input, i.e. you can't move and point at the same time. However, there's rarely any advantage to this, as there's no real multitasking possible. If you choose the Right Stick code, all you can really do is move the stupid cursor around while you run. Whee. If you want my opinion, use the Left Stick code.

  • Where possible, I try to "intelligently" enable/disable the pointer mode. The player can always toggle it on/off with the L button, but some other actions (opening the Inventory, Map or Photos menus) will automatically enable pointer mode for you. Try to remember to exit these menus using the same button you used to open them: e.g. you can press X to open the inventory (pointer turns on automatically) then X again to close it (pointer turns off automatically). If you instead open the menu with X then close it with B, you'll still be in pointer mode, because you didn't close with X. In this case, you should press L to disable the pointer manually. I'm trying here.

  • If the IR pointer movement is too fast/slow for you, you can adjust it by editing the float 0.015 (3C75C28F) about halfway through the code. You could adjust it down to 0.01 (3C23D70A) for a slower cursor, or bump it up to 0.02 (3CA3D70A) for a faster cursor, or whatever other number feels appropriate. There's plenty of hex float converters online, I linked one in a previous post somewhere.

  • It's worth knowing that this game supports USB keyboards. Using an on-screen keyboard with an IR pointer is sort of acceptable, but using an on-screen keyboard with a pointer you control using an analog stick is a bad time. If you have a USB keyboard handy it will hugely improve the experience if you're looking to do any typing (e.g. writing letters or chatting with other players over network play). It doesn't have to be a special Wii keyboard or anything; I use a standard PC Logitech Unifying USB dongle in my Wii. Failing that, if you use the phone in your house you can change the keyboard settings to use an old-school mobile keyboard which you might find easier to use with an analog stick.

  • I got a specific request (elsewhere, not in this thread) for an option where the Right Stick pointer is always enabled, but personally I think it's kind of bad. The game changes a lot of things about how it works when you're pointing at the screen, which don't make sense when playing on a traditional controller. For example, pressing A now makes you walk toward the cursor instead of interacting with whatever is in front of you. Pointing at the screen also causes the HUD to display at all times, which means the screen is cluttered with on-screen buttons the whole time you're playing. If anybody here wants this version, I guess ask for it but I find it offers an inferior experience to either of the codes above and shouldn't really be considered an equal option against those.

Technical Notes​

This game has that same Super Paper Mario issue where the Home Button Menu causes a Classic Controller re-init every 64 frames. I solved it the same way, disabling getInfoAsync() from running. Thinking about it more since last time, I suspect this probably has something to do with checking things like the battery level that displays in the HBM. I do still allow getInfoAsync() to run when you first enter the HBM in both this and Paper Mario, so it's not like the HBM is running blind but if you just leave it open it might not correctly track the battery level or something pointless like that, I don't care.

Briefly, the code is: C2 to allow Classic Controller's left stick to be read for movement, C2 to disable the bad EXT error, 04 disable getInfoAsync(), C2 and C2 actually redirect analog reads to the Classic when needed, C2 custom read_kpad_dpd() (Left Stick code has an additional feature to prevent character movement while in pointer mode) and then the button injector gets inserted into KPADRead() in the last C2.

Credits​

  • mogchamp from the AC: Wiimmfi Folk Discord for advising on the button layout
Thank you so much for this! I'm able to play ACCF on my Wii U with the gamepad now :) Only thing is I can't find the text to slow down the cursor in the text (maybe I'm just being dumb!) I am looking at Europe Rev. 1 so maybe that's it! Honestly it doesn't even matter that much I'm just so happy this has been done after all these years!
 
  • Like
Reactions: Vague Rant

Site & Scene News

Popular threads in this forum