Hacking New Classic Controller Hacks

  • Thread starter Thread starter Vague Rant
  • Start date Start date
  • Views Views 244,480
  • Replies Replies 687
  • Likes Likes 42
Someone make classic controller patch or at least take a look at SpongeBob SquarePants featuring NickToons: Globs of Doo

Wondering about make it so wii ver has controller support is batter ver of game over ps2 port.
 
Reply-O-Rama.

Sounds good! Ill modify your Rhythm Heaven ASM soon and give it better mappings 👍
Post automatically merged:

Hello @Vague Rant ! Here is the modifed ASM that has some example mappings for Max. Make sure to add the extension data stuff 👍
Make sure to change any values aswell if some are incorrect.
Building on your mapping and identifying all the relevant functions (nice work), here's what I've got for Max currently:
Code:
; bypass nunchuk error
; 8002C578 for USA
  lwz r0, 0x8(sp)
  cmpwi r0, 2
  bne- RETURN
  li r0, 1

RETURN:
Code:
; read_kpad_acc
; 8044BF94 for USA
  lfs f1, 0x4DC(r30)

; magic
  bl GRAB
MAGIC:
    CONTINUE:   .int 0
    SHAKE:      .float  3.4
GRAB:
  mflr r4

  lwz r3, CONTINUE-MAGIC(r4)
  cmpwi r3, 0
  ble- NEW_SHAKE
  subi r3, r3, 1
  b DO_SHAKE

NEW_SHAKE:
  lwz r3, 0x4(r30)
  andi. r0, r3, 0x80
  beq- RETURN
  li r3, 5

DO_SHAKE:
  lfs f1, SHAKE-MAGIC(r4)
  cmpwi r20, 1
  bne- RETURN
  stw r3, CONTINUE-MAGIC(r4)

; hold B for player
  lwz r3, 0x0(r30)
  ori r3, r3, 0x400
  stw r3, 0x0(r30)

  lwz r3, 0x8(r30)
  andi. r3, r3, 0xFBFF
  stw r3, 0x8(r30)

RETURN:
Code:
; calc_dpd_variable
; 8044C9D8 for USA
  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
  stb r0, 0x5E(r3)

  cmpwi r20, 0x1
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    GETASPECT:  .int    0x80468490  ; USA 0x80468490
    ASPECT:     .float  1.3333333333
    MULTIPLIER: .float  0.025       ; pointer speed
    MAX_RANGE:  .float  1.0
GRAB:
  mflr r5

DELTA:
  lwz r3, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
  cmplwi r3, 0x1
  ble- CHECK_ASPECT

; run aspect ratio check
  stw r5, 0x0C(sp)      ; save magic pointer
  mtlr r3
  blrl
  lwz r5, 0x0C(sp)      ; restore magic pointer
  stw r3, GETASPECT-MAGIC(r5)

CHECK_ASPECT:
  cmpwi r3, 0x1
  mr r3, r31            ; restore input 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
  lfs f2, MAX_RANGE-MAGIC(r5)
  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
  fcmpu cr0, f0, f2
  blt CHECK_NEGATIVE
  fmr f0, f2
  b IN_RANGE

    CHECK_NEGATIVE:
      fneg f2, f2
      fcmpu cr0, f0, f2
      bgt IN_RANGE
      fmr f0, f2
      
    IN_RANGE:
      blr

NO_CLASSIC:
Code:
read_kpad_ext
stick redirection
USA
0444D8D0 7FC3F378

KPADRead
drop fix
USA
0444E4F8 60000000
0444E648 60000000
Code:
; read_kpad_button
; 8044B9E4 for USA
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x80      ; wiimote shake + B (Erases ALL Ink)

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x400     ; B (Erase Ink)

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
Code:
C202C578 00000003
80010008 2C000002
40820008 38000001
60000000 00000000
C244BF94 0000000D
C03E04DC 4800000D
00000000 4059999A
7C8802A6 80640000
2C030000 4081000C
3863FFFF 48000014
807E0004 70600080
41820030 38600005
C0240004 2C140001
40820020 90640000
807E0000 60630400
907E0000 807E0008
7063FBFF 907E0008
60000000 00000000
C244C9D8 0000001C
90010024 2C040000
408200D0 8803005C
2C000002 408200C4
9803005E 2C140001
40820080 48000015
80468490 3FAAAAAB
3CCCCCCD 3F800000
7CA802A6 80650000
28030001 40810018
90A1000C 7C6803A6
4E800021 80A1000C
90650000 2C030001
7FE3FB78 C0450004
40820008 EC4200B2
C0650008 C0030020
C0230074 FC211024
48000031 D0030020
C0030024 C0230078
FC200850 C045000C
48000019 D0030024
80010024 7C0803A6
38210020 4E800020
FC0100FA FC001000
4180000C FC001090
48000014 FC401050
FC001000 41810008
FC001090 4E800020
60000000 00000000
0444D8D0 7FC3F378
0444E4F8 60000000
0444E648 60000000
C244B9E4 00000020
7D2802A6 4800000D
00000000 00000000
7D4802A6 7D2803A6
5729083C 7D4A4A14
2808FFFF 4082000C
A10A0000 48000014
2C040002 408200C0
38800001 B10A0000
71090800 41820008
60E78000 71090001
41820008 60E70008
71094000 41820008
60E70004 71090002
41820008 60E70001
71098000 41820008
60E70002 71090010
41820008 60E70800
71090040 41820008
60E72000 71090008
41820008 60E70080
71090020 41820008
60E74000 71092000
41820008 60E74000
71090200 41820008
60E72000 71090080
41820008 60E70400
71090004 41820008
60E70800 71090400
41820008 60E70010
71091000 41820008
60E71000 7CC63B78
70C99FFF 00000000
I found out that this game got a sequel on Xbox 360, so I did look at that a little and edited the mapping a tiny bit (swapped X and Y IIRC?) to match that game. For L and R, I mapped them as C and Z again, so that you can in theory play entirely with the shoulder buttons and never need to take your thumb off the Right Stick.

The accelerometer stuff for this game requires a swing that last at least 5 frames. I also set it up to hold B for those 5 frames as well, because otherwise you could easily hold the button for <5 frames and the shake would work but it would fail on the button press. This way everything seems to work reliably.

I made the IR pointer quite slow for this game because you do need to do things like draw a circle then color it in, and the fine motions are very tough at full speed. I think everything should be working with this, I was able to run through the first stage without any issues. If you could test this and see if everything works right and/or make any changes you feel like, I'll see if I can port it to EUR/JPN and create IPS patches for people playing via injection.

Since you've done Mater-National i assume you're also going to do Race-o-rama right? I've wanted to try that one for a while.
Me too. Race-O-Rama is definitely the most complicated of the Cars trilogy because a bunch of the minigames are motion-controlled QTEs. But there's a pretty good chance it'll happen.

Hello, thank you for the amazing work you've done on these hacks (along with the contributions of the other members as well)!

For the case of the missing shake support in super paper mario, can i still utilize the shake of the wiimote while using the classic control hack? and is there a way any one of us can help add it to the classic control hack? thanks again.
The original Wiimote shake should definitely still work for the times when it's needed. Anybody with knowledge of assembly hacking Wii games could get it implemented. Obviously I've let it sit in my backlog for quite a while but I don't think it should be an extremely complex game. As I understand it, it tilting side-to-side for one minigame and generic shaking for a badge that lets you do extra damage by jumping on enemies or something?

A lot of games use the value at 0x58(r3) for horizontal Wiimote tilting (e.g. steering), so if Paper Mario works like that, then it's basically a matter of reading in the X axis of the Right Stick (a range from -1 to +1) from 0x74(r3), maybe multiplying it by 0.5 or something then writing it to the tilt address. The accelerometer tilt is also from -1 to +1, but most games don't expect you to tilt the full 180 degrees, so you also want to reduce the value of the stick.

It might also require a bit of remapping of the buttons, because your right thumb is now "stuck" on the Right Stick managing the tilt controls (and your left thumb is doing movement on the Left Stick), so only the L/R/ZL/ZR buttons are really usable while you're doing that. So depending on how many buttons are needed in the tilt minigame, you'd probably need to map some of those (e.g. Jump?) up there so that you can move, jump and tilt simultaneously.

Assuming it works in roughly the same way, the tilt stuff I did for New Super Mario Bros. Wii might be relatively close. That would look something like this:
Code:
; calc_acc_vertical
; note: these are NSMBW addresses, not Paper Mario
; 801EB038 for USA (Rev 1/2)
; 801EB178 for EUR (Rev 2)
; 801EAE48 for JPN (Rev 2)
; 801EB578 for KOR
  stw r0, 0x44(r1)

; check if this is a classic controller
  lbz r0, 0x5C(r3)
  cmpwi r0, 0x2
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    RANGE:  .float   0.5
GRAB:
  mflr r5

  lfs f0, RANGE-MAGIC(r5)

; load in right stick, constrain and write
  lfs f1, 0x74(r3)
  fmuls f0, f0, f1
  stfs f0, 0x58(r3)

; restore lr and stack then get outta here
  lwz r0, 0x44(sp)
  mtlr r0
  addi sp, sp, 0x40
  blr

RETURN:

Hello, I would like to map the B of the Wiimote to the B of the Classic Controller in Epic Mickey. I think it's okay to only jump with A and in return be able to cancel with B in the menu. How do I do that?
To remap B to B in Epic Mickey, you'll want to Ctrl+F for this part in the code:
Code:
60C60800 71000040
41820008 60C60800
... and replace the second 0800 (A), the one at the end, with 0400 (B), so you've got this:
Code:
60C60800 71000040
41820008 60C60400
Just to be clear, you're only changing a single digit, an 8 to a 4, the rest is just so you know which 8 is the right one to change.

hi there, I had a question about mario kart wii's MK8 controller hack:

if using a mix of classic controller and classic controller pro, should i leave controls to default, or is there a compromise that can be used to improve the experience on both? thanks.
I included a couple of extra options in the Technical Notes section for Mario Kart Wii which you might like better when using a mix of Classic Controller generations. The "main" version of the code I made definitely assumes you have easy access to the ZL/ZR buttons which are obviously not very convenient on the original Classic. However, in the Technical Notes there's a code which swaps L/R with ZL/ZR. I labelled it as L Item, R Drift, ZL/ZR/D-Pad Wheelie. I think that one is probably ideal when using both types of CC simultaneously, because all of them have reasonably easy access to L/R. With that version, you can still wheelie with the Z buttons or D-Pad but otherwise the control layout is much closer to Mario Kart 8.

Hello again @Vague Rant Im running into a new issue with the pointer / buttons.
For some reason, Adding the pointer code is causing everything to drag to the right of the screen. It also causes some buttons (I think) to be held for some reason. Any idea why everything is breaking when the Pointer code is added?

EDIT: I dont know if its specificially the pointer code, but its very weird. It also breaks WPAD inputs (Wii Remote)
EDIT 2: Its not the pointer problem. But it seems to be with the games that use KPAD differently. The one below

On a seperate note, how do you handle games with andi. r6, r9, 0x9FFF? Games that handle KPAD way differently. Im trying to finish one of my hacks but it handles KPAD differently, and that instruction in read_kpad_button looks different. Thanks.
Post automatically merged:

Update: Max and the Magic Marker seems to use andi. r6, r9, 0x9FFF aswell 😬 That will make things complicated if the same issue arises
Aha, yeah, the registers are not always consistent across SDK versions. The button mapper needs a "garbage" register it can replace over and over while doing button checks. Each of the andi. instructions in the button injector replaces the value in the first register. The button mapping code I gave in the tutorial, for Rhythm Heaven, uses r0 as the garbage register, because after the button injection finishes, the game populates r0 itself, so it doesn't matter what we left behind.

Max and the Magic Marker is using r9 where other games would use r0, so we need to make r9 our garbage register instead. If you scroll back up to the start of this post, you can look at the button injector code I used for Max and see that I've made r9 the garbage register, so that's the one we dump the output in each time we check a button.

@Vague Rant I am currently trying to replicate the button-hack for Lego Star Wars - The Complete Saga from your guide. (I want to get familiar with creating gecko hacks, so that i eventually might be able to fix Lego Star Wars 3, Back To The Future and some others if i stumble upon issues. (I have no idea if that will be possible with my skillset, i am currently in the hubris-phase ;))

The problem with my own hack is, that it does not work. I have identified the adress (8032f380) of the andi-instruction, but it differs from the one in your hack (which does work, as far as i can tell)

The adress in your hack is 8019AC18 which seems to be inside the parent call.

Is this expected, as you chose a better location for the hack for that game, or is the guide only "very" barebones?

There is also the question what happens if it is not easy to find the kpad-functions when the symbols are not recognized. (Both BTTF and LSW3 dont show any results for either kpad or select_1obj_continue).

Do you have any hints on how to approach this? Or is this simply too hard (for me)?

Thank you very much anyway, both for the existing hacks and the guide!
Whoops, you've spotted an error in the Technical Notes I wrote up for Lego Star Wars. That was a pretty early Wii game, before read_kpad_button() existed, so the injector goes directly in KPADRead(), but my notes say read_kpad_button() incorrectly I'll go back and edit that, thanks for spotting it.

IIRC, Lego Star Wars 3 was pretty late in the Wii life cycle, so without looking at it, I suspect that it actually would use read_kpad_button(). I'll answer the second part below, since it's on the same subject.

You mean search for the symbol "WPADProbe"?

The WPADProbe only calls externally to manage interrupts, otherwise it is pretty much self-contained. Is WPADProbe a child function of KPADRead?
awesomeee did mean to breakpoint it once you've found it rather than just searching for it. Really sorry if you already know this, but a breakpoint is a feature in debuggers that pauses the application when a specific state occurs. An execution breakpoint means pausing when an instruction gets executed. In Dolphin, you can toggle an execution breakpoint by clicking to the left of the address. In this screenshot you can see where I've set a breakpoint at the beginning of WPADProbe(), because there's a little circle indicating an execution breakpoint, which is where I clicked.
wpadbreak.png
So the idea when using this method to locate KPADRead() is to pause Dolphin, search for WPADProbe(), set a breakpoint at the start, then resume execution in Dolphin. It will stop again almost instantly, because WPADProbe() usually runs 3, 4 or more times on each frame, called from all over the place. As you correctly guessed, one of those callers is KPADRead().

Each time you resume execution in Dolphin, it will run until the next time WPADProbe() gets called. If you're in the situation where the select_1obj_continue() approach isn't working, it's most likely that Dolphin has not recognized KPADRead() as a function at all, so in the Callstack panel in the top left, KPADRead() will show up as ---.

There's no guarantee that the first --- you see is KPADRead() as there may be multiple unrecognized functions, but basically you just want to keep resuming Dolphin until you see --- as caller, then click it in the Callstack and try to figure out whether you're looking at KPADRead() by scrolling down and seeing if you recognize anything from the tutorial, like the three read calls in a row (stick/ext, acc and dpd), although obviously with autogenerated names, not the real ones.

It absolutely looks like you know what you're doing and are grasping all the concepts, so it doesn't sound like this is outside of your skillset to me.

Any chance you could try with Tenchu: Shadow Assassins? Since the game was ported to PSP maybe it could serve as a prompt guideline for the Classic Controller.
It does look like a pretty complicated one, with different motions for attacks and finishers and stuff. I'll add it to my list, but it's going in the complicated section with other games I've either struggled or failed with.

Someone make classic controller patch or at least take a look at SpongeBob SquarePants featuring NickToons: Globs of Doo

Wondering about make it so wii ver has controller support is batter ver of game over ps2 port.
I've literally never heard of this game, interesting one. I actually just successfully looked at another game from Incinerator Studios which also had things triggered by motions, so while it does look somewhat complex, maybe we'll get lucky and I can leverage previous work on it. Fingers crossed.



cars1_presents_cars3.png


As previously established, Cars Race-O-Rama is the real third entry in the Cars trilogy. Although development moved from Rainbow Studios to Incinerator Studios (who had worked on the Wii ports of the first two Cars...es), this game was built on Rainbow's engine from the first two games and continues in a similar vein, with a mix of racing and minigames taking on the roles of several "car"-acters. Race-O-Rama is a bit of an odd case: it's often regarded as the best Cars game in the trilogy and/or the entire series, with highlights being a greater focus on racing, the new drift-boost mechanic and the massively expanded open world environments compared to the first two games. At the same time, it seems to have been the most rushed entry, with performance issues, wonkier crash physics than ever, and occasional bugs marring the effort, even on the ports to more powerful consoles. Can it be the best in the series and also a bit rushed and sloppy?

Highlight for @frankybuster_, who was interested in this game.

USAEUR

  1. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDAC 00000002
    28000001 41820008
    28000002 00000000
    C227CF54 00000002
    28000001 41820008
    28000002 00000000
    C227D4B4 00000002
    28000001 41820008
    28000002 00000000
    C23650D8 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B48 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320E50 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A40 7FC3F378
    043677B0 60000000
    04367900 60000000
    C2364B54 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDEC 00000002
    28000001 41820008
    28000002 00000000
    C227CF94 00000002
    28000001 41820008
    28000002 00000000
    C227D4F4 00000002
    28000001 41820008
    28000002 00000000
    C2365128 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B98 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320EA0 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A90 7FC3F378
    04367800 60000000
    04367950 60000000
    C2364BA4 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000

Button Mapping​

Wii Remote/NunchukClassic ControllerFunction
Wiimote HomeHomeOpen/Close Home Menu
Wiimote D-PadD-PadMenus
Navigation
Wiimote D-Pad UpLGameplay
Tilt Vehicle
Wiimote D-Pad DownYGameplay
E-Brake
Wiimote D-Pad LeftRGameplay
Reverse Camera
Wiimote AAMenus
Confirm
Gameplay
Brake/Reverse
Wiimote BBMenus
Cancel
Gameplay
Accelerate
Wiimote 1XGameplay
Switch Camera
Wiimote 2AMenus
Confirm (Wiimote mode)
Wiimote PlusPlusGameplay
Pause
Wiimote MinusMinusGameplay
Switch Garage
Wiimote MotionsRight StickGameplay
Various Minigame QTEs
Wiimote PointerLeft StickHome Button Menu
Navigation
Nunchuk StickLeft StickMenus
Navigation
Gameplay
Steering
Nunchuk CZRGameplay
Nitro
Nunchuk ZZLGameplay
Powerslide

General Notes​

  • Cars Race-O-Rama boots into sideways Wiimote mode (Configuration 1 in the Options menu) by default, regardless of what extension controller is connected. That's bad news for our purposes, because the mapping used here is all wrong for sideways Wiimote. I improved on this somewhat by automatically switching to Nunchuk mode (Configuration 2) if a Nunchuk or Classic Controller is connected when you boot the game or when starting a new save file. If you don't do anything goofy, you should be fine. Goofy things include:

    • Booting up the game before you connect a Nunchuk/Classic Controller.

    • Loading a previously created save file which is set to Wiimote mode.

    • Going into Options > Control Options and switching to Wiimote mode (Configuration 1).

      • Any of the above will make the game run in sideways Wiimote mode (Configuration 1). If you get yourself into Wiimote mode, the Classic Controller D-Pad will be rotated. You will just have to deal with that until you switch back to Nunchuk mode (Configuration 2). Use the X and A buttons as 1 and 2 to navigate the menus.

  • As mentioned in the intro, Race-O-Rama is from a different developer to the previous two Cars games and introduces some of its own mechanics. Incinerator's control scheme for the game is pretty radically different to Rainbow's setup for the first two. Even on the HD console versions with traditional controllers, the button mapping doesn't have much in common with the controls of Cars/Mater-National. I considered reverting the layout to make it match the earlier games, but I decided to take this game on its own terms and map it like the other console ports, even though that means it's completely different to the previous Mater-National hack.

    • The most significant change is probably that Incinerator has inverted the accelerate/brake controls from previous games, so it's B to accelerate and A to brake. This is definitely pretty weird and I never entirely wrapped my head around it, but this hack respects that setup (which was the same on other consoles as well). If you don't like it, the assembly is in the Technical Notes for you to come up with your own mapping.

Technical Notes​

Code breakdown:
  • C2: check extension controller on boot, switch to Config 2 if Nunchuk/Classic
  • C2 and 04: check extension controller when creating a new save, switch to Config 2 if Nunchuk/Classic
  • C2: bypass Nunchuk error
  • C2 and C2: accept Classic Controller as Nunchuk-type controller
  • C2 in read_kpad_acc(): fake accelerometer motions on Right Stick
  • C2 in calc_dpd_variable(): simulate IR pointer on Left Stick
  • 04 in read_kpad_ext(): stick redirection
  • 04 and 04 in KPADRead(): dropped connection fix
  • C2 in read_kpad_button(): button injector
Code:
; read_kpad_button
; 80364B54 for USA
; 80364BA4 for EUR (En,Fr,Es,It)/EUR (Fr,De)
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right (v) / up (h)

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x900     ; a + 2

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x400     ; b

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x200     ; 1

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x2000    ; z

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x4000    ; c

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
 
Reply-O-Rama.


Building on your mapping and identifying all the relevant functions (nice work), here's what I've got for Max currently:
Code:
; bypass nunchuk error
; 8002C578 for USA
  lwz r0, 0x8(sp)
  cmpwi r0, 2
  bne- RETURN
  li r0, 1

RETURN:
Code:
; read_kpad_acc
; 8044BF94 for USA
  lfs f1, 0x4DC(r30)

; magic
  bl GRAB
MAGIC:
    CONTINUE:   .int 0
    SHAKE:      .float  3.4
GRAB:
  mflr r4

  lwz r3, CONTINUE-MAGIC(r4)
  cmpwi r3, 0
  ble- NEW_SHAKE
  subi r3, r3, 1
  b DO_SHAKE

NEW_SHAKE:
  lwz r3, 0x4(r30)
  andi. r0, r3, 0x80
  beq- RETURN
  li r3, 5

DO_SHAKE:
  lfs f1, SHAKE-MAGIC(r4)
  cmpwi r20, 1
  bne- RETURN
  stw r3, CONTINUE-MAGIC(r4)

; hold B for player
  lwz r3, 0x0(r30)
  ori r3, r3, 0x400
  stw r3, 0x0(r30)

  lwz r3, 0x8(r30)
  andi. r3, r3, 0xFBFF
  stw r3, 0x8(r30)

RETURN:
Code:
; calc_dpd_variable
; 8044C9D8 for USA
  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
  stb r0, 0x5E(r3)

  cmpwi r20, 0x1
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    GETASPECT:  .int    0x80468490  ; USA 0x80468490
    ASPECT:     .float  1.3333333333
    MULTIPLIER: .float  0.025       ; pointer speed
    MAX_RANGE:  .float  1.0
GRAB:
  mflr r5

DELTA:
  lwz r3, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
  cmplwi r3, 0x1
  ble- CHECK_ASPECT

; run aspect ratio check
  stw r5, 0x0C(sp)      ; save magic pointer
  mtlr r3
  blrl
  lwz r5, 0x0C(sp)      ; restore magic pointer
  stw r3, GETASPECT-MAGIC(r5)

CHECK_ASPECT:
  cmpwi r3, 0x1
  mr r3, r31            ; restore input 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
  lfs f2, MAX_RANGE-MAGIC(r5)
  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
  fcmpu cr0, f0, f2
  blt CHECK_NEGATIVE
  fmr f0, f2
  b IN_RANGE

    CHECK_NEGATIVE:
      fneg f2, f2
      fcmpu cr0, f0, f2
      bgt IN_RANGE
      fmr f0, f2
     
    IN_RANGE:
      blr

NO_CLASSIC:
Code:
read_kpad_ext
stick redirection
USA
0444D8D0 7FC3F378

KPADRead
drop fix
USA
0444E4F8 60000000
0444E648 60000000
Code:
; read_kpad_button
; 8044B9E4 for USA
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x80      ; wiimote shake + B (Erases ALL Ink)

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x400     ; B (Erase Ink)

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
Code:
C202C578 00000003
80010008 2C000002
40820008 38000001
60000000 00000000
C244BF94 0000000D
C03E04DC 4800000D
00000000 4059999A
7C8802A6 80640000
2C030000 4081000C
3863FFFF 48000014
807E0004 70600080
41820030 38600005
C0240004 2C140001
40820020 90640000
807E0000 60630400
907E0000 807E0008
7063FBFF 907E0008
60000000 00000000
C244C9D8 0000001C
90010024 2C040000
408200D0 8803005C
2C000002 408200C4
9803005E 2C140001
40820080 48000015
80468490 3FAAAAAB
3CCCCCCD 3F800000
7CA802A6 80650000
28030001 40810018
90A1000C 7C6803A6
4E800021 80A1000C
90650000 2C030001
7FE3FB78 C0450004
40820008 EC4200B2
C0650008 C0030020
C0230074 FC211024
48000031 D0030020
C0030024 C0230078
FC200850 C045000C
48000019 D0030024
80010024 7C0803A6
38210020 4E800020
FC0100FA FC001000
4180000C FC001090
48000014 FC401050
FC001000 41810008
FC001090 4E800020
60000000 00000000
0444D8D0 7FC3F378
0444E4F8 60000000
0444E648 60000000
C244B9E4 00000020
7D2802A6 4800000D
00000000 00000000
7D4802A6 7D2803A6
5729083C 7D4A4A14
2808FFFF 4082000C
A10A0000 48000014
2C040002 408200C0
38800001 B10A0000
71090800 41820008
60E78000 71090001
41820008 60E70008
71094000 41820008
60E70004 71090002
41820008 60E70001
71098000 41820008
60E70002 71090010
41820008 60E70800
71090040 41820008
60E72000 71090008
41820008 60E70080
71090020 41820008
60E74000 71092000
41820008 60E74000
71090200 41820008
60E72000 71090080
41820008 60E70400
71090004 41820008
60E70800 71090400
41820008 60E70010
71091000 41820008
60E71000 7CC63B78
70C99FFF 00000000
I found out that this game got a sequel on Xbox 360, so I did look at that a little and edited the mapping a tiny bit (swapped X and Y IIRC?) to match that game. For L and R, I mapped them as C and Z again, so that you can in theory play entirely with the shoulder buttons and never need to take your thumb off the Right Stick.

The accelerometer stuff for this game requires a swing that last at least 5 frames. I also set it up to hold B for those 5 frames as well, because otherwise you could easily hold the button for <5 frames and the shake would work but it would fail on the button press. This way everything seems to work reliably.

I made the IR pointer quite slow for this game because you do need to do things like draw a circle then color it in, and the fine motions are very tough at full speed. I think everything should be working with this, I was able to run through the first stage without any issues. If you could test this and see if everything works right and/or make any changes you feel like, I'll see if I can port it to EUR/JPN and create IPS patches for people playing via injection.


Me too. Race-O-Rama is definitely the most complicated of the Cars trilogy because a bunch of the minigames are motion-controlled QTEs. But there's a pretty good chance it'll happen.


The original Wiimote shake should definitely still work for the times when it's needed. Anybody with knowledge of assembly hacking Wii games could get it implemented. Obviously I've let it sit in my backlog for quite a while but I don't think it should be an extremely complex game. As I understand it, it tilting side-to-side for one minigame and generic shaking for a badge that lets you do extra damage by jumping on enemies or something?

A lot of games use the value at 0x58(r3) for horizontal Wiimote tilting (e.g. steering), so if Paper Mario works like that, then it's basically a matter of reading in the X axis of the Right Stick (a range from -1 to +1) from 0x74(r3), maybe multiplying it by 0.5 or something then writing it to the tilt address. The accelerometer tilt is also from -1 to +1, but most games don't expect you to tilt the full 180 degrees, so you also want to reduce the value of the stick.

It might also require a bit of remapping of the buttons, because your right thumb is now "stuck" on the Right Stick managing the tilt controls (and your left thumb is doing movement on the Left Stick), so only the L/R/ZL/ZR buttons are really usable while you're doing that. So depending on how many buttons are needed in the tilt minigame, you'd probably need to map some of those (e.g. Jump?) up there so that you can move, jump and tilt simultaneously.

Assuming it works in roughly the same way, the tilt stuff I did for New Super Mario Bros. Wii might be relatively close. That would look something like this:
Code:
; calc_acc_vertical
; note: these are NSMBW addresses, not Paper Mario
; 801EB038 for USA (Rev 1/2)
; 801EB178 for EUR (Rev 2)
; 801EAE48 for JPN (Rev 2)
; 801EB578 for KOR
  stw r0, 0x44(r1)

; check if this is a classic controller
  lbz r0, 0x5C(r3)
  cmpwi r0, 0x2
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    RANGE:  .float   0.5
GRAB:
  mflr r5

  lfs f0, RANGE-MAGIC(r5)

; load in right stick, constrain and write
  lfs f1, 0x74(r3)
  fmuls f0, f0, f1
  stfs f0, 0x58(r3)

; restore lr and stack then get outta here
  lwz r0, 0x44(sp)
  mtlr r0
  addi sp, sp, 0x40
  blr

RETURN:


To remap B to B in Epic Mickey, you'll want to Ctrl+F for this part in the code:
Code:
60C60800 71000040
41820008 60C60800
... and replace the second 0800 (A), the one at the end, with 0400 (B), so you've got this:
Code:
60C60800 71000040
41820008 60C60400
Just to be clear, you're only changing a single digit, an 8 to a 4, the rest is just so you know which 8 is the right one to change.


I included a couple of extra options in the Technical Notes section for Mario Kart Wii which you might like better when using a mix of Classic Controller generations. The "main" version of the code I made definitely assumes you have easy access to the ZL/ZR buttons which are obviously not very convenient on the original Classic. However, in the Technical Notes there's a code which swaps L/R with ZL/ZR. I labelled it as L Item, R Drift, ZL/ZR/D-Pad Wheelie. I think that one is probably ideal when using both types of CC simultaneously, because all of them have reasonably easy access to L/R. With that version, you can still wheelie with the Z buttons or D-Pad but otherwise the control layout is much closer to Mario Kart 8.


Aha, yeah, the registers are not always consistent across SDK versions. The button mapper needs a "garbage" register it can replace over and over while doing button checks. Each of the andi. instructions in the button injector replaces the value in the first register. The button mapping code I gave in the tutorial, for Rhythm Heaven, uses r0 as the garbage register, because after the button injection finishes, the game populates r0 itself, so it doesn't matter what we left behind.

Max and the Magic Marker is using r9 where other games would use r0, so we need to make r9 our garbage register instead. If you scroll back up to the start of this post, you can look at the button injector code I used for Max and see that I've made r9 the garbage register, so that's the one we dump the output in each time we check a button.


Whoops, you've spotted an error in the Technical Notes I wrote up for Lego Star Wars. That was a pretty early Wii game, before read_kpad_button() existed, so the injector goes directly in KPADRead(), but my notes say read_kpad_button() incorrectly I'll go back and edit that, thanks for spotting it.

IIRC, Lego Star Wars 3 was pretty late in the Wii life cycle, so without looking at it, I suspect that it actually would use read_kpad_button(). I'll answer the second part below, since it's on the same subject.


awesomeee did mean to breakpoint it once you've found it rather than just searching for it. Really sorry if you already know this, but a breakpoint is a feature in debuggers that pauses the application when a specific state occurs. An execution breakpoint means pausing when an instruction gets executed. In Dolphin, you can toggle an execution breakpoint by clicking to the left of the address. In this screenshot you can see where I've set a breakpoint at the beginning of WPADProbe(), because there's a little circle indicating an execution breakpoint, which is where I clicked.
So the idea when using this method to locate KPADRead() is to pause Dolphin, search for WPADProbe(), set a breakpoint at the start, then resume execution in Dolphin. It will stop again almost instantly, because WPADProbe() usually runs 3, 4 or more times on each frame, called from all over the place. As you correctly guessed, one of those callers is KPADRead().

Each time you resume execution in Dolphin, it will run until the next time WPADProbe() gets called. If you're in the situation where the select_1obj_continue() approach isn't working, it's most likely that Dolphin has not recognized KPADRead() as a function at all, so in the Callstack panel in the top left, KPADRead() will show up as ---.

There's no guarantee that the first --- you see is KPADRead() as there may be multiple unrecognized functions, but basically you just want to keep resuming Dolphin until you see --- as caller, then click it in the Callstack and try to figure out whether you're looking at KPADRead() by scrolling down and seeing if you recognize anything from the tutorial, like the three read calls in a row (stick/ext, acc and dpd), although obviously with autogenerated names, not the real ones.

It absolutely looks like you know what you're doing and are grasping all the concepts, so it doesn't sound like this is outside of your skillset to me.


It does look like a pretty complicated one, with different motions for attacks and finishers and stuff. I'll add it to my list, but it's going in the complicated section with other games I've either struggled or failed with.


I've literally never heard of this game, interesting one. I actually just successfully looked at another game from Incinerator Studios which also had things triggered by motions, so while it does look somewhat complex, maybe we'll get lucky and I can leverage previous work on it. Fingers crossed.



View attachment 481114

As previously established, Cars Race-O-Rama is the real third entry in the Cars trilogy. Although development moved from Rainbow Studios to Incinerator Studios (who had worked on the Wii ports of the first two Cars...es), this game was built on Rainbow's engine from the first two games and continues in a similar vein, with a mix of racing and minigames taking on the roles of several "car"-acters. Race-O-Rama is a bit of an odd case: it's often regarded as the best Cars game in the trilogy and/or the entire series, with highlights being a greater focus on racing, the new drift-boost mechanic and the massively expanded open world environments compared to the first two games. At the same time, it seems to have been the most rushed entry, with performance issues, wonkier crash physics than ever, and occasional bugs marring the effort, even on the ports to more powerful consoles. Can it be the best in the series and also a bit rushed and sloppy?

Highlight for @frankybuster_, who was interested in this game.

USAEUR

  1. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDAC 00000002
    28000001 41820008
    28000002 00000000
    C227CF54 00000002
    28000001 41820008
    28000002 00000000
    C227D4B4 00000002
    28000001 41820008
    28000002 00000000
    C23650D8 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B48 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320E50 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A40 7FC3F378
    043677B0 60000000
    04367900 60000000
    C2364B54 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDEC 00000002
    28000001 41820008
    28000002 00000000
    C227CF94 00000002
    28000001 41820008
    28000002 00000000
    C227D4F4 00000002
    28000001 41820008
    28000002 00000000
    C2365128 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B98 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320EA0 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A90 7FC3F378
    04367800 60000000
    04367950 60000000
    C2364BA4 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000

Button Mapping​

[TABLE=full]
[TR]
[TH]Wii Remote/Nunchuk[/TH]
[TH]Classic Controller[/TH]
[TH]Function[/TH]
[/TR]
[TR]
[TD]Wiimote Home[/TD]
[TD]Home[/TD]
[TD]Open/Close Home Menu[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad[/TD]
[TD]D-Pad[/TD]
[TD]Menus
Navigation[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Up[/TD]
[TD]L[/TD]
[TD]Gameplay
Tilt Vehicle[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Down[/TD]
[TD]Y[/TD]
[TD]Gameplay
E-Brake[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Left[/TD]
[TD]R[/TD]
[TD]Gameplay
Reverse Camera[/TD]
[/TR]
[TR]
[TD]Wiimote A[/TD]
[TD]A[/TD]
[TD]Menus
Confirm
Gameplay
Brake/Reverse[/TD]
[/TR]
[TR]
[TD]Wiimote B[/TD]
[TD]B[/TD]
[TD]Menus
Cancel
Gameplay
Accelerate[/TD]
[/TR]
[TR]
[TD]Wiimote 1[/TD]
[TD]X[/TD]
[TD]Gameplay
Switch Camera[/TD]
[/TR]
[TR]
[TD]Wiimote 2[/TD]
[TD]A[/TD]
[TD]Menus
Confirm (Wiimote mode)[/TD]
[/TR]
[TR]
[TD]Wiimote Plus[/TD]
[TD]Plus[/TD]
[TD]Gameplay
Pause[/TD]
[/TR]
[TR]
[TD]Wiimote Minus[/TD]
[TD]Minus[/TD]
[TD]Gameplay
Switch Garage[/TD]
[/TR]
[TR]
[TD]Wiimote Motions[/TD]
[TD]Right Stick[/TD]
[TD]Gameplay
Various Minigame QTEs[/TD]
[/TR]
[TR]
[TD]Wiimote Pointer[/TD]
[TD]Left Stick[/TD]
[TD]Home Button Menu
Navigation[/TD]
[/TR]
[TR]
[TD]Nunchuk Stick[/TD]
[TD]Left Stick[/TD]
[TD]Menus
Navigation
Gameplay
Steering[/TD]
[/TR]
[TR]
[TD]Nunchuk C[/TD]
[TD]ZR[/TD]
[TD]Gameplay
Nitro[/TD]
[/TR]
[TR]
[TD]Nunchuk Z[/TD]
[TD]ZL[/TD]
[TD]Gameplay
Powerslide[/TD]
[/TR]
[/TABLE]

General Notes​

  • Cars Race-O-Rama boots into sideways Wiimote mode (Configuration 1 in the Options menu) by default, regardless of what extension controller is connected. That's bad news for our purposes, because the mapping used here is all wrong for sideways Wiimote. I improved on this somewhat by automatically switching to Nunchuk mode (Configuration 2) if a Nunchuk or Classic Controller is connected when you boot the game or when starting a new save file. If you don't do anything goofy, you should be fine. Goofy things include:
    • Booting up the game before you connect a Nunchuk/Classic Controller.

    • Loading a previously created save file which is set to Wiimote mode.

    • Going into Options > Control Options and switching to Wiimote mode (Configuration 1).
      • Any of the above will make the game run in sideways Wiimote mode (Configuration 1). If you get yourself into Wiimote mode, the Classic Controller D-Pad will be rotated. You will just have to deal with that until you switch back to Nunchuk mode (Configuration 2). Use the X and A buttons as 1 and 2 to navigate the menus.

  • As mentioned in the intro, Race-O-Rama is from a different developer to the previous two Cars games and introduces some of its own mechanics. Incinerator's control scheme for the game is pretty radically different to Rainbow's setup for the first two. Even on the HD console versions with traditional controllers, the button mapping doesn't have much in common with the controls of Cars/Mater-National. I considered reverting the layout to make it match the earlier games, but I decided to take this game on its own terms and map it like the other console ports, even though that means it's completely different to the previous Mater-National hack.
    • The most significant change is probably that Incinerator has inverted the accelerate/brake controls from previous games, so it's B to accelerate and A to brake. This is definitely pretty weird and I never entirely wrapped my head around it, but this hack respects that setup (which was the same on other consoles as well). If you don't like it, the assembly is in the Technical Notes for you to come up with your own mapping.

Technical Notes​

Code breakdown:
  • C2: check extension controller on boot, switch to Config 2 if Nunchuk/Classic
  • C2 and 04: check extension controller when creating a new save, switch to Config 2 if Nunchuk/Classic
  • C2: bypass Nunchuk error
  • C2 and C2: accept Classic Controller as Nunchuk-type controller
  • C2 in read_kpad_acc(): fake accelerometer motions on Right Stick
  • C2 in calc_dpd_variable(): simulate IR pointer on Left Stick
  • 04 in read_kpad_ext(): stick redirection
  • 04 and 04 in KPADRead(): dropped connection fix
  • C2 in read_kpad_button(): button injector
Code:
; read_kpad_button
; 80364B54 for USA
; 80364BA4 for EUR (En,Fr,Es,It)/EUR (Fr,De)
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right (v) / up (h)

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x900     ; a + 2

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x400     ; b

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x200     ; 1

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x2000    ; z

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x4000    ; c

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
No see me game for used most normal button beside shake for some combio moves again see one more different thing get done but do hope it won't two hard of task do unsure really work all know someone make code and game they magical work with classic controller on Dophin emulator
SpongeBob SquarePants featuring NickToons: Globs of Doo
 
Update, Max uses and A and B button at the same time to trigger a pause mode (Not pause menu), Ill see what would be a good mapping for that.
Post automatically merged:

@Vague Rant Your max code seems to be corrupting the ingame audio on Dolphin emulator! Whenever its enabled the audio is super choppy and corrupted! I can make out some of the music but its very broken. Whats going on?

As for the controls, they are good as is. A and B can be triggered with ZL and ZR, lol.

So the max code should be ready! Of course we need to test EUR and JPN soon.
 
Last edited by awesomeee,
@Vague Rant

There's no guarantee that the first --- you see is KPADRead() as there may be multiple unrecognized functions, but basically you just want to keep resuming Dolphin until you see --- as caller, then click it in the Callstack and try to figure out whether you're looking at KPADRead() by scrolling down and seeing if you recognize anything from the tutorial, like the three read calls in a row (stick/ext, acc and dpd), although obviously with autogenerated names, not the real ones.

Yes, thank you! That did the trick, in SW3 i could identify the appropriate section. You were right, it wasn't identified at all. (By the way, it seems to use the newer sdk)

However after that: weirdness occured:

It seems that the language-selector does support the classic controller with my gecko code (at least i can use the dpad and a to continue), but not after that. It seems that the same function is beeing called in the menu aswell. (I did the same procedure identifying kpad in the main menu)

The thing is, i am not sure how it is working at all. I can enter a "random" starting adress for the gecko code, and it will still behave the same weird way:

- If i enable my code, usually the mapped classic controls work and seemingly press a button. (Button A, for selecting the lang)
- Disabling the code does not reliably disable that behaviour. (I have to restart dolphin to get back to the "buttons dont do anything"-state). Also changing the controls does not reliably change them for the emulator, the only surefire way to do that is to restart the emulator.

The only way i can explain this is that dolphin caches some instructions somewhere. Is this normal or is dolphin (flatpak, ubuntu) broken?

look ahead one instruction to find the following: andi. r0, r6, 0x9FFF
(from the guide, for the new sdk)

Does this have to be 0x9fff? Also, is this inside the bl call/read_kpad_button or above it? (the one inside is not the second instruction, but the thuird, and it uses different registers and 0x0800 as a constant)


I tried the same for Lego Lord of the Rings as a sanity check, and while i could find what i assume are the proper calls, this time it didn't work at all. Though i didn't spend much time figuring out why, first SW3, then the next thing!


It absolutely looks like you know what you're doing and are grasping all the concepts, so it doesn't sound like this is outside of your skillset to me.
Yeah, i did have some x86 assembly/computer architecture courses in uni (versity), and we did build (virtual) 8 bit cpu's from scratch.
Though my assembler was very barebones, and we generally didn't do reverse-engineering. Was quite a fun few courses.

Edit: Weird. I cannot fully post the word "u n i v e r s i t y" otherwise the spamprotection prevents me from posting xD
 
  • Like
Reactions: Vague Rant
A few more questions related to these hacks:
1. How do you locate read_kpad_ext, and if a game does not use that, are there any further instructions to finding KPADStatus? It seems a little confusing

2. Do you have the knowledge of modifying existing controls? (EX: Modifying metroid other M to remap DPAD down for the wiimote tilt, etc)

If I get more knowledge I would be interested in enhancing some CC hacks to support nunchuk aswell, but its a maybe. It probably wont even happen aswell, but It is good for documentation.

Of course, no hassle. I already have been replying A lot so no need to rush anything 👍
 
@Vague Rant On a different topic, do you know how hard it would be to "fix" the call of duty games? Some have classic support natively (which works *flawless*).

Some others have "pointing" control, where you point the rifle where you want to shoot, while the camera follows the pointer.

From what i tried in that game, it should be nicely playable with a classic controller *if* it is possible to decouple the camera from the pointer, and fix the rifle in the center of the screen. I guess this would be quite a bit more involved than just figuring out buttonmappings.
 
Has anyone requested Crash of the Titans and Mind Over Mutant yet? it'd be very cool to have classic controller mods for these games since they're better looking than the PS2 versions, especially the latter which almost matches the 360 version in asset quality but without being as demanding to emulate and having a 60fps hack.

I'm requesting this mainly for because these games require pointer and waggle usage for certain things, like for projectile based mutants and for using their super attacks (not to mention that the TK mutant has a strafe only seen in the Wii version). If possible it'd be great if a classic controller setup somewhat matched the controller layouts seen in the other versions

Oh yeah, and classic controller codes for the Skylanders games would be really cool too if it could be done sometime in the future, those games have pretty basic waggle and pointer usage, with the waggle stuff being simplified to mashing the X button in the Wii U ports.
Crash of the Titans was one of my favorite games as a child. I tried the Wii version, but was disappointed with the controls. A CC hack would be awesome.
 
Reply-O-Rama.


Building on your mapping and identifying all the relevant functions (nice work), here's what I've got for Max currently:
Code:
; bypass nunchuk error
; 8002C578 for USA
  lwz r0, 0x8(sp)
  cmpwi r0, 2
  bne- RETURN
  li r0, 1

RETURN:
Code:
; read_kpad_acc
; 8044BF94 for USA
  lfs f1, 0x4DC(r30)

; magic
  bl GRAB
MAGIC:
    CONTINUE:   .int 0
    SHAKE:      .float  3.4
GRAB:
  mflr r4

  lwz r3, CONTINUE-MAGIC(r4)
  cmpwi r3, 0
  ble- NEW_SHAKE
  subi r3, r3, 1
  b DO_SHAKE

NEW_SHAKE:
  lwz r3, 0x4(r30)
  andi. r0, r3, 0x80
  beq- RETURN
  li r3, 5

DO_SHAKE:
  lfs f1, SHAKE-MAGIC(r4)
  cmpwi r20, 1
  bne- RETURN
  stw r3, CONTINUE-MAGIC(r4)

; hold B for player
  lwz r3, 0x0(r30)
  ori r3, r3, 0x400
  stw r3, 0x0(r30)

  lwz r3, 0x8(r30)
  andi. r3, r3, 0xFBFF
  stw r3, 0x8(r30)

RETURN:
Code:
; calc_dpd_variable
; 8044C9D8 for USA
  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
  stb r0, 0x5E(r3)

  cmpwi r20, 0x1
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    GETASPECT:  .int    0x80468490  ; USA 0x80468490
    ASPECT:     .float  1.3333333333
    MULTIPLIER: .float  0.025       ; pointer speed
    MAX_RANGE:  .float  1.0
GRAB:
  mflr r5

DELTA:
  lwz r3, GETASPECT-MAGIC(r5)  ; SCGetAspectRatio()
  cmplwi r3, 0x1
  ble- CHECK_ASPECT

; run aspect ratio check
  stw r5, 0x0C(sp)      ; save magic pointer
  mtlr r3
  blrl
  lwz r5, 0x0C(sp)      ; restore magic pointer
  stw r3, GETASPECT-MAGIC(r5)

CHECK_ASPECT:
  cmpwi r3, 0x1
  mr r3, r31            ; restore input 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
  lfs f2, MAX_RANGE-MAGIC(r5)
  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
  fcmpu cr0, f0, f2
  blt CHECK_NEGATIVE
  fmr f0, f2
  b IN_RANGE

    CHECK_NEGATIVE:
      fneg f2, f2
      fcmpu cr0, f0, f2
      bgt IN_RANGE
      fmr f0, f2
     
    IN_RANGE:
      blr

NO_CLASSIC:
Code:
read_kpad_ext
stick redirection
USA
0444D8D0 7FC3F378

KPADRead
drop fix
USA
0444E4F8 60000000
0444E648 60000000
Code:
; read_kpad_button
; 8044B9E4 for USA
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x80      ; wiimote shake + B (Erases ALL Ink)

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x4000    ; Nunchuk C (Push and Pull objects)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x2000    ; Z (Jump)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x400     ; B (Erase Ink)

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x800     ; A (Draw Ink)

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
Code:
C202C578 00000003
80010008 2C000002
40820008 38000001
60000000 00000000
C244BF94 0000000D
C03E04DC 4800000D
00000000 4059999A
7C8802A6 80640000
2C030000 4081000C
3863FFFF 48000014
807E0004 70600080
41820030 38600005
C0240004 2C140001
40820020 90640000
807E0000 60630400
907E0000 807E0008
7063FBFF 907E0008
60000000 00000000
C244C9D8 0000001C
90010024 2C040000
408200D0 8803005C
2C000002 408200C4
9803005E 2C140001
40820080 48000015
80468490 3FAAAAAB
3CCCCCCD 3F800000
7CA802A6 80650000
28030001 40810018
90A1000C 7C6803A6
4E800021 80A1000C
90650000 2C030001
7FE3FB78 C0450004
40820008 EC4200B2
C0650008 C0030020
C0230074 FC211024
48000031 D0030020
C0030024 C0230078
FC200850 C045000C
48000019 D0030024
80010024 7C0803A6
38210020 4E800020
FC0100FA FC001000
4180000C FC001090
48000014 FC401050
FC001000 41810008
FC001090 4E800020
60000000 00000000
0444D8D0 7FC3F378
0444E4F8 60000000
0444E648 60000000
C244B9E4 00000020
7D2802A6 4800000D
00000000 00000000
7D4802A6 7D2803A6
5729083C 7D4A4A14
2808FFFF 4082000C
A10A0000 48000014
2C040002 408200C0
38800001 B10A0000
71090800 41820008
60E78000 71090001
41820008 60E70008
71094000 41820008
60E70004 71090002
41820008 60E70001
71098000 41820008
60E70002 71090010
41820008 60E70800
71090040 41820008
60E72000 71090008
41820008 60E70080
71090020 41820008
60E74000 71092000
41820008 60E74000
71090200 41820008
60E72000 71090080
41820008 60E70400
71090004 41820008
60E70800 71090400
41820008 60E70010
71091000 41820008
60E71000 7CC63B78
70C99FFF 00000000
I found out that this game got a sequel on Xbox 360, so I did look at that a little and edited the mapping a tiny bit (swapped X and Y IIRC?) to match that game. For L and R, I mapped them as C and Z again, so that you can in theory play entirely with the shoulder buttons and never need to take your thumb off the Right Stick.

The accelerometer stuff for this game requires a swing that last at least 5 frames. I also set it up to hold B for those 5 frames as well, because otherwise you could easily hold the button for <5 frames and the shake would work but it would fail on the button press. This way everything seems to work reliably.

I made the IR pointer quite slow for this game because you do need to do things like draw a circle then color it in, and the fine motions are very tough at full speed. I think everything should be working with this, I was able to run through the first stage without any issues. If you could test this and see if everything works right and/or make any changes you feel like, I'll see if I can port it to EUR/JPN and create IPS patches for people playing via injection.


Me too. Race-O-Rama is definitely the most complicated of the Cars trilogy because a bunch of the minigames are motion-controlled QTEs. But there's a pretty good chance it'll happen.


The original Wiimote shake should definitely still work for the times when it's needed. Anybody with knowledge of assembly hacking Wii games could get it implemented. Obviously I've let it sit in my backlog for quite a while but I don't think it should be an extremely complex game. As I understand it, it tilting side-to-side for one minigame and generic shaking for a badge that lets you do extra damage by jumping on enemies or something?

A lot of games use the value at 0x58(r3) for horizontal Wiimote tilting (e.g. steering), so if Paper Mario works like that, then it's basically a matter of reading in the X axis of the Right Stick (a range from -1 to +1) from 0x74(r3), maybe multiplying it by 0.5 or something then writing it to the tilt address. The accelerometer tilt is also from -1 to +1, but most games don't expect you to tilt the full 180 degrees, so you also want to reduce the value of the stick.

It might also require a bit of remapping of the buttons, because your right thumb is now "stuck" on the Right Stick managing the tilt controls (and your left thumb is doing movement on the Left Stick), so only the L/R/ZL/ZR buttons are really usable while you're doing that. So depending on how many buttons are needed in the tilt minigame, you'd probably need to map some of those (e.g. Jump?) up there so that you can move, jump and tilt simultaneously.

Assuming it works in roughly the same way, the tilt stuff I did for New Super Mario Bros. Wii might be relatively close. That would look something like this:
Code:
; calc_acc_vertical
; note: these are NSMBW addresses, not Paper Mario
; 801EB038 for USA (Rev 1/2)
; 801EB178 for EUR (Rev 2)
; 801EAE48 for JPN (Rev 2)
; 801EB578 for KOR
  stw r0, 0x44(r1)

; check if this is a classic controller
  lbz r0, 0x5C(r3)
  cmpwi r0, 0x2
  bne- RETURN

; magic
  bl GRAB
MAGIC:
    RANGE:  .float   0.5
GRAB:
  mflr r5

  lfs f0, RANGE-MAGIC(r5)

; load in right stick, constrain and write
  lfs f1, 0x74(r3)
  fmuls f0, f0, f1
  stfs f0, 0x58(r3)

; restore lr and stack then get outta here
  lwz r0, 0x44(sp)
  mtlr r0
  addi sp, sp, 0x40
  blr

RETURN:


To remap B to B in Epic Mickey, you'll want to Ctrl+F for this part in the code:
Code:
60C60800 71000040
41820008 60C60800
... and replace the second 0800 (A), the one at the end, with 0400 (B), so you've got this:
Code:
60C60800 71000040
41820008 60C60400
Just to be clear, you're only changing a single digit, an 8 to a 4, the rest is just so you know which 8 is the right one to change.


I included a couple of extra options in the Technical Notes section for Mario Kart Wii which you might like better when using a mix of Classic Controller generations. The "main" version of the code I made definitely assumes you have easy access to the ZL/ZR buttons which are obviously not very convenient on the original Classic. However, in the Technical Notes there's a code which swaps L/R with ZL/ZR. I labelled it as L Item, R Drift, ZL/ZR/D-Pad Wheelie. I think that one is probably ideal when using both types of CC simultaneously, because all of them have reasonably easy access to L/R. With that version, you can still wheelie with the Z buttons or D-Pad but otherwise the control layout is much closer to Mario Kart 8.


Aha, yeah, the registers are not always consistent across SDK versions. The button mapper needs a "garbage" register it can replace over and over while doing button checks. Each of the andi. instructions in the button injector replaces the value in the first register. The button mapping code I gave in the tutorial, for Rhythm Heaven, uses r0 as the garbage register, because after the button injection finishes, the game populates r0 itself, so it doesn't matter what we left behind.

Max and the Magic Marker is using r9 where other games would use r0, so we need to make r9 our garbage register instead. If you scroll back up to the start of this post, you can look at the button injector code I used for Max and see that I've made r9 the garbage register, so that's the one we dump the output in each time we check a button.


Whoops, you've spotted an error in the Technical Notes I wrote up for Lego Star Wars. That was a pretty early Wii game, before read_kpad_button() existed, so the injector goes directly in KPADRead(), but my notes say read_kpad_button() incorrectly I'll go back and edit that, thanks for spotting it.

IIRC, Lego Star Wars 3 was pretty late in the Wii life cycle, so without looking at it, I suspect that it actually would use read_kpad_button(). I'll answer the second part below, since it's on the same subject.


awesomeee did mean to breakpoint it once you've found it rather than just searching for it. Really sorry if you already know this, but a breakpoint is a feature in debuggers that pauses the application when a specific state occurs. An execution breakpoint means pausing when an instruction gets executed. In Dolphin, you can toggle an execution breakpoint by clicking to the left of the address. In this screenshot you can see where I've set a breakpoint at the beginning of WPADProbe(), because there's a little circle indicating an execution breakpoint, which is where I clicked.
So the idea when using this method to locate KPADRead() is to pause Dolphin, search for WPADProbe(), set a breakpoint at the start, then resume execution in Dolphin. It will stop again almost instantly, because WPADProbe() usually runs 3, 4 or more times on each frame, called from all over the place. As you correctly guessed, one of those callers is KPADRead().

Each time you resume execution in Dolphin, it will run until the next time WPADProbe() gets called. If you're in the situation where the select_1obj_continue() approach isn't working, it's most likely that Dolphin has not recognized KPADRead() as a function at all, so in the Callstack panel in the top left, KPADRead() will show up as ---.

There's no guarantee that the first --- you see is KPADRead() as there may be multiple unrecognized functions, but basically you just want to keep resuming Dolphin until you see --- as caller, then click it in the Callstack and try to figure out whether you're looking at KPADRead() by scrolling down and seeing if you recognize anything from the tutorial, like the three read calls in a row (stick/ext, acc and dpd), although obviously with autogenerated names, not the real ones.

It absolutely looks like you know what you're doing and are grasping all the concepts, so it doesn't sound like this is outside of your skillset to me.


It does look like a pretty complicated one, with different motions for attacks and finishers and stuff. I'll add it to my list, but it's going in the complicated section with other games I've either struggled or failed with.


I've literally never heard of this game, interesting one. I actually just successfully looked at another game from Incinerator Studios which also had things triggered by motions, so while it does look somewhat complex, maybe we'll get lucky and I can leverage previous work on it. Fingers crossed.



View attachment 481114

As previously established, Cars Race-O-Rama is the real third entry in the Cars trilogy. Although development moved from Rainbow Studios to Incinerator Studios (who had worked on the Wii ports of the first two Cars...es), this game was built on Rainbow's engine from the first two games and continues in a similar vein, with a mix of racing and minigames taking on the roles of several "car"-acters. Race-O-Rama is a bit of an odd case: it's often regarded as the best Cars game in the trilogy and/or the entire series, with highlights being a greater focus on racing, the new drift-boost mechanic and the massively expanded open world environments compared to the first two games. At the same time, it seems to have been the most rushed entry, with performance issues, wonkier crash physics than ever, and occasional bugs marring the effort, even on the ports to more powerful consoles. Can it be the best in the series and also a bit rushed and sloppy?

Highlight for @frankybuster_, who was interested in this game.

USAEUR

  1. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDAC 00000002
    28000001 41820008
    28000002 00000000
    C227CF54 00000002
    28000001 41820008
    28000002 00000000
    C227D4B4 00000002
    28000001 41820008
    28000002 00000000
    C23650D8 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B48 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320E50 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A40 7FC3F378
    043677B0 60000000
    04367900 60000000
    C2364B54 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C209A8C4 00000005
    880DE234 2C000002
    40820008 38000001
    2C000001 41820008
    38000000 901D0544
    60000000 00000000
    C20AE100 00000005
    88ADE234 2C050002
    40820008 38A00001
    2C050001 41820008
    38A00000 98BF006C
    60000000 00000000
    040AE11C 60000000
    C227CDEC 00000002
    28000001 41820008
    28000002 00000000
    C227CF94 00000002
    28000001 41820008
    28000002 00000000
    C227D4F4 00000002
    28000001 41820008
    28000002 00000000
    C2365128 00000008
    8803005C 2C000002
    40820030 48000009
    4059999A 7CA802A6
    C0250000 C0030074
    EC000072 D01E04D8
    C0830078 EC840072
    FC002050 D01E04DC
    80C3000C 00000000
    C2365B98 0000001F
    90010024 2C040000
    408200E8 8803005C
    2C000002 408200DC
    9803005E 2C140001
    40820094 48000015
    80320EA0 3FAAAAAB
    3D4CCCCD 3F800000
    7CA802A6 80030004
    70008000 41820010
    38000000 90030020
    90030024 80650000
    28030001 40810018
    90A1000C 7C6803A6
    4E800021 80A1000C
    90650000 2C030001
    7FE3FB78 C0450004
    40820008 EC4200B2
    C0650008 C0030020
    C0230060 FC211024
    4800002D D0030020
    C0030024 C0230064
    FC200850 48000019
    D0030024 80010024
    7C0803A6 38210020
    4E800020 FC0100FA
    C025000C FC000800
    4180000C FC000890
    48000014 FC200850
    FC000800 41810008
    FC000890 4E800020
    60000000 00000000
    04366A90 7FC3F378
    04367800 60000000
    04367950 60000000
    C2364BA4 00000020
    7D2802A6 4800000D
    00000000 00000000
    7D4802A6 7D2803A6
    5729083C 7D4A4A14
    2808FFFF 4082000C
    A10A0000 48000014
    2C040002 408200C0
    38800001 B10A0000
    71090800 41820008
    60E78000 71090001
    41820008 60E70008
    71094000 41820008
    60E70004 71090002
    41820008 60E70001
    71098000 41820008
    60E70002 71090010
    41820008 60E70900
    71090040 41820008
    60E70400 71090008
    41820008 60E70200
    71090020 41820008
    60E70004 71092000
    41820008 60E70008
    71090200 41820008
    60E70001 71090080
    41820008 60E72000
    71090004 41820008
    60E74000 71090400
    41820008 60E70010
    71091000 41820008
    60E71000 7CC63B78
    70C99FFF 00000000

Button Mapping​

[TABLE=full]
[TR]
[TH]Wii Remote/Nunchuk[/TH]
[TH]Classic Controller[/TH]
[TH]Function[/TH]
[/TR]
[TR]
[TD]Wiimote Home[/TD]
[TD]Home[/TD]
[TD]Open/Close Home Menu[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad[/TD]
[TD]D-Pad[/TD]
[TD]Menus
Navigation[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Up[/TD]
[TD]L[/TD]
[TD]Gameplay
Tilt Vehicle[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Down[/TD]
[TD]Y[/TD]
[TD]Gameplay
E-Brake[/TD]
[/TR]
[TR]
[TD]Wiimote D-Pad Left[/TD]
[TD]R[/TD]
[TD]Gameplay
Reverse Camera[/TD]
[/TR]
[TR]
[TD]Wiimote A[/TD]
[TD]A[/TD]
[TD]Menus
Confirm
Gameplay
Brake/Reverse[/TD]
[/TR]
[TR]
[TD]Wiimote B[/TD]
[TD]B[/TD]
[TD]Menus
Cancel
Gameplay
Accelerate[/TD]
[/TR]
[TR]
[TD]Wiimote 1[/TD]
[TD]X[/TD]
[TD]Gameplay
Switch Camera[/TD]
[/TR]
[TR]
[TD]Wiimote 2[/TD]
[TD]A[/TD]
[TD]Menus
Confirm (Wiimote mode)[/TD]
[/TR]
[TR]
[TD]Wiimote Plus[/TD]
[TD]Plus[/TD]
[TD]Gameplay
Pause[/TD]
[/TR]
[TR]
[TD]Wiimote Minus[/TD]
[TD]Minus[/TD]
[TD]Gameplay
Switch Garage[/TD]
[/TR]
[TR]
[TD]Wiimote Motions[/TD]
[TD]Right Stick[/TD]
[TD]Gameplay
Various Minigame QTEs[/TD]
[/TR]
[TR]
[TD]Wiimote Pointer[/TD]
[TD]Left Stick[/TD]
[TD]Home Button Menu
Navigation[/TD]
[/TR]
[TR]
[TD]Nunchuk Stick[/TD]
[TD]Left Stick[/TD]
[TD]Menus
Navigation
Gameplay
Steering[/TD]
[/TR]
[TR]
[TD]Nunchuk C[/TD]
[TD]ZR[/TD]
[TD]Gameplay
Nitro[/TD]
[/TR]
[TR]
[TD]Nunchuk Z[/TD]
[TD]ZL[/TD]
[TD]Gameplay
Powerslide[/TD]
[/TR]
[/TABLE]

General Notes​

  • Cars Race-O-Rama boots into sideways Wiimote mode (Configuration 1 in the Options menu) by default, regardless of what extension controller is connected. That's bad news for our purposes, because the mapping used here is all wrong for sideways Wiimote. I improved on this somewhat by automatically switching to Nunchuk mode (Configuration 2) if a Nunchuk or Classic Controller is connected when you boot the game or when starting a new save file. If you don't do anything goofy, you should be fine. Goofy things include:
    • Booting up the game before you connect a Nunchuk/Classic Controller.

    • Loading a previously created save file which is set to Wiimote mode.

    • Going into Options > Control Options and switching to Wiimote mode (Configuration 1).
      • Any of the above will make the game run in sideways Wiimote mode (Configuration 1). If you get yourself into Wiimote mode, the Classic Controller D-Pad will be rotated. You will just have to deal with that until you switch back to Nunchuk mode (Configuration 2). Use the X and A buttons as 1 and 2 to navigate the menus.

  • As mentioned in the intro, Race-O-Rama is from a different developer to the previous two Cars games and introduces some of its own mechanics. Incinerator's control scheme for the game is pretty radically different to Rainbow's setup for the first two. Even on the HD console versions with traditional controllers, the button mapping doesn't have much in common with the controls of Cars/Mater-National. I considered reverting the layout to make it match the earlier games, but I decided to take this game on its own terms and map it like the other console ports, even though that means it's completely different to the previous Mater-National hack.
    • The most significant change is probably that Incinerator has inverted the accelerate/brake controls from previous games, so it's B to accelerate and A to brake. This is definitely pretty weird and I never entirely wrapped my head around it, but this hack respects that setup (which was the same on other consoles as well). If you don't like it, the assembly is in the Technical Notes for you to come up with your own mapping.

Technical Notes​

Code breakdown:
  • C2: check extension controller on boot, switch to Config 2 if Nunchuk/Classic
  • C2 and 04: check extension controller when creating a new save, switch to Config 2 if Nunchuk/Classic
  • C2: bypass Nunchuk error
  • C2 and C2: accept Classic Controller as Nunchuk-type controller
  • C2 in read_kpad_acc(): fake accelerometer motions on Right Stick
  • C2 in calc_dpd_variable(): simulate IR pointer on Left Stick
  • 04 in read_kpad_ext(): stick redirection
  • 04 and 04 in KPADRead(): dropped connection fix
  • C2 in read_kpad_button(): button injector
Code:
; read_kpad_button
; 80364B54 for USA
; 80364BA4 for EUR (En,Fr,Es,It)/EUR (Fr,De)
; r4 holds extType
; r6 holds wiimote bitfield
; r7 holds wiimote+nunchuk bitfield
; r8 holds classic bitfield

; magic
  mflr r9
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r10
  mtlr r9
  slwi r9, r25, 1
  add r10, r10, r9

; check dropped extension
  cmplwi r8, 0xFFFF
  bne- CLASSIC
  lhz r8, HELD-MAGIC(r10)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r8, HELD-MAGIC(r10)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r9, r8, 0x800
      beq- CLASSIC_UP
      ori r7, r7, 0x8000    ; home

    CLASSIC_UP:
      andi. r9, r8, 0x1
      beq- CLASSIC_DOWN
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_DOWN:
      andi. r9, r8, 0x4000
      beq- CLASSIC_LEFT
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_LEFT:
      andi. r9, r8, 0x2
      beq- CLASSIC_RIGHT
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_RIGHT:
      andi. r9, r8, 0x8000
      beq- CLASSIC_A
      ori r7, r7, 0x2       ; right (v) / up (h)

    CLASSIC_A:
      andi. r9, r8, 0x10
      beq- CLASSIC_B
      ori r7, r7, 0x900     ; a + 2

    CLASSIC_B:
      andi. r9, r8, 0x40
      beq- CLASSIC_X
      ori r7, r7, 0x400     ; b

    CLASSIC_X:
      andi. r9, r8, 0x8
      beq- CLASSIC_Y
      ori r7, r7, 0x200     ; 1

    CLASSIC_Y:
      andi. r9, r8, 0x20
      beq- CLASSIC_L
      ori r7, r7, 0x4       ; down (v) / right (h)

    CLASSIC_L:
      andi. r9, r8, 0x2000
      beq- CLASSIC_R
      ori r7, r7, 0x8       ; up (v) / left (h)

    CLASSIC_R:
      andi. r9, r8, 0x200
      beq- CLASSIC_ZL
      ori r7, r7, 0x1       ; left (v) / down (h)

    CLASSIC_ZL:
      andi. r9, r8, 0x80
      beq- CLASSIC_ZR
      ori r7, r7, 0x2000    ; z

    CLASSIC_ZR:
      andi. r9, r8, 0x4
      beq- CLASSIC_PLUS
      ori r7, r7, 0x4000    ; c

    CLASSIC_PLUS:
      andi. r9, r8, 0x400
      beq- CLASSIC_MINUS
      ori r7, r7, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r9, r8, 0x1000
      beq- RETURN
      ori r7, r7, 0x1000    ; minus

RETURN:
  or r6, r6, r7
  andi. r9, r6, 0x9FFF
OK someone games people asking form should work base on the quality of the game order should be.

1. Crash Bandicoot Crash of the Titans
2. Crash bandicoot Mind Over Mutant
3. SpongeBob SquarePants featuring Nicktoons: Globs of Doom

Also should do patch for cars 1 unsure different that whould be in itself as batter og ver should focused games people asking form first as take quite some time for patch to be made.
 
Its time to get Fit! (Plus)
Wii Fit Plus was another game. (why)

SI_Wii_WiiFitPlus_image1600w.jpg

This hack is a joke hack, nothing big. Lol, Its honestly pointless aswell, like Vague said, making a hack for Mario party, lol. So please dont stir any drama over this, thanks.

This hack is unfinished aswell. You must unplug the Classic Controller if the game tells you to do so.

Unfinished Classic Controller Support (awesomeee, Vague Rant)


C2137004 00000019
2C040002 408200B8
71090800 41820008
60C68000 71090001
41820008 60C60008
71094000 41820008
60C60004 71090002
41820008 60C60001
71098000 41820008
60C60002 71090010
41820008 60C60800
71090040 41820008
60C60400 71090008
41820008 60C60100
71090020 41820008
60C60200 71092000
41820008 60C60800
71090200 41820008
60C60800 71090080
41820008 60C60800
71090004 41820008
60C60800 71090400
41820008 60C60010
71091000 41820008
60C61000 70C99FFF
60000000 00000000
C2137FF8 00000029
90010024 2C040000
4082013C 8803005C
2C000002 40820130
48000021 801529F0
3FAAAAAB 3C75C28F
00000000 00000000
3DCCCCCD 3F800000
7CA802A6 90A1000C
5727083C 38E7000C
C0030074 FC000210
C0230078 FC200A10
C083006C FC802210
C0A30070 FCA02A10
FC00082A FC84282A
FC00202A C0450014
FC001040 4180000C
38C0012C 48000014
7CC53AAE 28060000
408100B4 38C6FFFF
7CC53B2E 38C00002
98C3005E 81850000
7D8803A6 4E800021
2C030001 7FE3FB78
80A1000C C0450004
40820008 EC4200B2
C0650008 C0030020
C0230074 C083006C
FC21202A FC211024
48000039 D0030020
C0030024 C0230078
FC200850 C0830070
FC802050 FC21202A
48000019 D0030024
80010024 7C0803A6
38210020 4E800020
FC0100FA C0250018
FC000800 4180000C
FC000890 48000014
FC200850 FC000800
41810008 FC000890
4E800020 00000000

Another thanks to Vague Rant for helping fix the weird instruction! (andi. r6, r9, 0x9FFF)
 
This is amazing and I’ve loved the games so far. Is there any way you could take a peek at Thrillville: Off The Rails? PSP/PS2 lacks features, Wii is perfect and is the 360 version of the game but there’s some incredibly iffy motion controls for mini games.
 
  • Like
Reactions: saud and Vague Rant
This is amazing and I’ve loved the games so far. Is there any way you could take a peek at Thrillville: Off The Rails? PSP/PS2 lacks features, Wii is perfect and is the 360 version of the game but there’s some incredibly iffy motion controls for mini games.
Here order focused on do Game quality

1. Cars 2006
2. Crash Bandicoot Crash of the Titans
3. Crash bandicoot Mind Over Mutant
4. SpongeBob SquarePants featuring Nicktoons: Globs of Doom

How keep mind games list are 3nd party and alot ps2 ver feel should get emulate playable best way keep in mind at times look batter they ps2.
 
Globs of Replies.

@Vague Rant Your max code seems to be corrupting the ingame audio on Dolphin emulator! Whenever its enabled the audio is super choppy and corrupted! I can make out some of the music but its very broken. Whats going on?
Huh, very weird, I'll have to double-check what's going on there.

It seems that the language-selector does support the classic controller with my gecko code (at least i can use the dpad and a to continue), but not after that. It seems that the same function is beeing called in the menu aswell. (I did the same procedure identifying kpad in the main menu)
This might be a case where the language menu is set up to support a solo Wiimote (you could try unplugging the CC entirely and see if the Wiimote works standalone) but the game after that point only responds while a Nunchuk is connected. I just had this situation with the game in this post, where the controls would work initially but then once the game starts checking if the Nunchuk is available, they quit. Fixing it was a similar process to fixing Nunchuk error messages, trying to identify some code that checks that the extension byte is 1 and misbehaves when it isn't.

If you're lucky, you can sometimes fix this by patching places where the result of a WPADProbe() run is checked. That function doesn't return the result in r3, instead the way it works is that you pass it an address and it writes the extension byte to that address. If you go back to my previous post where I screenshotted WPADProbe(), you can see the instruction at 80325638: stw r0, 0 (r30). That's where the extension is being written out (as a 32-bit value, so generally 00000002 in our case). If you breakpoint that address (the equivalent in your game, I mean), then copy the address from r30 and paste it into the top right of the Memory tab, you can see that address in memory, right click it and set a read breakpoint, to pause execution any time the game reads that value. This can sometimes be a quick way to find what's looking for a 1, because if something reads that address then immediately compares it against 1, you can be sure it's some type of Nunchuk check, and then you can insert your own code something like this, replacing the compare instruction:
Code:
; bypass nunchuk check
  cmplwi r0, 1
  beq- RETURN
  cmplwi r0, 2

RETURN:
(Change register as necessary. Also, some games use cmpwi for this comparison and others use cmplwi; for our purposes either is fine but just match whatever the OG game does for safety.)

You can usually safely ignore the very first call to WPADProbe() which will often be part of the WPAD library itself, as well as ignoring the call that comes from KPADRead() itself. We don't want to mess with the extension byte this early, because KPAD relies on knowing the real extension to handle reading the Classic Controller. That's why we jump in after KPAD is done for this frame to start patching extension checks.

However, a lot of games don't use WPADProbe() directly to grab the extension byte. They might grab it out of the KPADStatus struct or anywhere else that the extension byte has previously been copied to outside of either. Another approach that's sometimes decent is to set a breakpoint at the start of KPADRead() and explore the parent function to see if there's any cmpwi rX, 1s within the function after KPADRead() runs. Again, no guarantees, but sometimes that's a handy way to find extension checks. You can set a breakpoint on that compare and make sure that it's coming in as 2. If you want to be extra sure, you can change the extension in the controller settings and see if it changes on the next break as well--keep in mind, Dolphin spends a few frames reporting that the extension was removed and such before it actually updates to the new extension type.

If neither of those work, you start getting into the really heavy duty stuff, basically:
  1. Switch extension to Nunchuk in the Dolphin settings

  2. Hold down a button or button combo that you know the button values for

    • e.g. A+B together is 0x0C00

  3. Breakpoint the start of read_kpad_button()

  4. Take the address from r3 and paste that into the Memory tab

    • This is a pointer to KPADStatus

  5. Set a read breakpoint on the first word

    • It should contain the buttons you're holding; if not, you're in the wrong place

  6. Follow where the button values get copied to

    • Usually 3+ times within KPADRead() itself, possibly some more copies after that before they start being read for gameplay purposes

  7. In the case we're talking about here, where buttons aren't registering because the game wants a Nunchuk connected, you should eventually find some code that's doing a compare against 1 and skipping a section if it's not equal

    • If you think you've found it, breakpoint it, switch back to Classic and see if you're right
The thing is, i am not sure how it is working at all. I can enter a "random" starting adress for the gecko code, and it will still behave the same weird way:

- If i enable my code, usually the mapped classic controls work and seemingly press a button. (Button A, for selecting the lang)
- Disabling the code does not reliably disable that behaviour. (I have to restart dolphin to get back to the "buttons dont do anything"-state). Also changing the controls does not reliably change them for the emulator, the only surefire way to do that is to restart the emulator.

The only way i can explain this is that dolphin caches some instructions somewhere. Is this normal or is dolphin (flatpak, ubuntu) broken?
This is normal Dolphin behavior. As far as I understand it, turning off a Gecko code in Dolphin means "stop writing this piece of code into memory." However, it doesn't un-write the code, so any code that you've already inserted/replaced this session is still being applied, unless or until the game itself writes over that memory. As a general rule, nothing ever writes to the area of memory where the binary is held, so patches to code like we're doing are essentially "permanent" for as long as the current session lasts.

Also, if you add a new code or modify an existing one, you'll need to toggle it off and on again to get Dolphin to update its cached instructions. If your PC is beefy enough, you won't notice any difference, but performance in theory tanks while Dolphin is regenerating the instruction cache, so if you toggle your code off and on and the game runs slow for a couple of seconds, that's a good sign that it worked and your updated codes are now active.

If you need to test from a clean slate multiple times, it can be useful to disable all your codes (from the right click -> Properties menu, before launching the game), run the game up to a sensible test point, e.g. gameplay, using regular Wiimote/Nunchuk controls, create a save state in Dolphin (Emulation -> Save State), then enable your codes in Dolphin. This way, you can load state to get the game back to its original unmodified condition (basically, what you were aiming for by turning your codes off originally). Note that you will need to toggle your codes off and on again in this situation to get them running, because they weren't enabled when you saved state and even though they're still checked in the menu, they're not enabled any more once you load state.

(from the guide, for the new sdk)

Does this have to be 0x9fff? Also, is this inside the bl call/read_kpad_button or above it? (the one inside is not the second instruction, but the thuird, and it uses different registers and 0x0800 as a constant)


I tried the same for Lego Lord of the Rings as a sanity check, and while i could find what i assume are the proper calls, this time it didn't work at all. Though i didn't spend much time figuring out why, first SW3, then the next thing!
That is inside read_kpad_button(). In my experience it's absolutely always 0x9FFF. This code is specifically separating out the Nunchuk buttons C and Z (the two highest bits, 0x4000 and 0x2000 in hex) from the rest of the bits (0x9FFF) so that there's a register that's holding only the lower 14 bits which represent the Wiimote's buttons (plus three empty spaces where buttons theoretically could be but aren't). If it's not doing that, you might be looking at the wrong place.

A few more questions related to these hacks:
1. How do you locate read_kpad_ext, and if a game does not use that, are there any further instructions to finding KPADStatus? It seems a little confusing

2. Do you have the knowledge of modifying existing controls? (EX: Modifying metroid other M to remap DPAD down for the wiimote tilt, etc)

If I get more knowledge I would be interested in enhancing some CC hacks to support nunchuk aswell, but its a maybe. It probably wont even happen aswell, but It is good for documentation.

Of course, no hassle. I already have been replying A lot so no need to rush anything 👍
read_kpad_ext() is basically the same thing as read_kpad_stick(), it's found in the same place and does mostly the same stuff. They just renamed it in some later SDK versions, probably in line with adding some extra functionality or something. I haven't actually looked into it, but technically there are other things that plug into the EXT port on the base of the Wiimote, so maybe a new accessory launched and they expanded the functionality of read_kpad_stick() and renamed it in the process. Nothing about how we interact with it changes, because we're just messing with the analog sticks, not any of the later additions.

It's also worth mentioning that I'm like 70% guessing whether I call it read_kpad_stick() or read_kpad_ext() for each hack. Basically if a game is relatively late in the Wii's lifespan I say ext, otherwise stick. I guarantee there are times where I've incorrectly guessed what the function was called internally as I go through labelling what I'm looking at, but they're basically synonymous so it's not very important to know which is which.

I haven't done much remapping of original game controls besides Mario Kart Wii which was Classic Controller, but the idea would essentially be that you'd want to build your remapped layout in another register then move it back into the register you read the real button values from. So I think you'd want something like this ...
Code:
; KPADRead
; r4 holds extType
; r7 holds wiimote bitfield
; r8 holds wiimote+nunchuk bitfield
; r9 holds classic bitfield
  li r7, 0  ; blank out real wiimote buttons

    WIIMOTE_HOME:
      andi. r0, r8, 0x8000
      beq- WIIMOTE_UP
      ori r7, r7, 0x8000    ; home

    WIIMOTE_UP:
      andi. r0, r8, 0x8
      beq- WIIMOTE_DOWN
      ori r7, r7, 0x8       ; up (v) / left (h)

    WIIMOTE_DOWN:
      andi. r0, r8, 0x4
      beq- WIIMOTE_LEFT
      ori r7, r7, 0x4       ; down (v) / right (h)

    WIIMOTE_LEFT:
      andi. r0, r8, 0x1
      beq- WIIMOTE_RIGHT
      ori r7, r7, 0x1       ; left (v) / down (h)

    WIIMOTE_RIGHT:
      andi. r0, r8, 0x2
      beq- WIIMOTE_A
      ori r7, r7, 0x2       ; right (v) / up (h)

    WIIMOTE_A:
      andi. r0, r8, 0x800
      beq- WIIMOTE_B
      ori r7, r7, 0x800     ; a

    WIIMOTE_B:
      andi. r0, r8, 0x400
      beq- WIIMOTE_1
      ori r7, r7, 0x400     ; b

    WIIMOTE_1:
      andi. r0, r8, 0x200
      beq- WIIMOTE_2
      ori r7, r7, 0x200     ; 1

    WIIMOTE_2:
      andi. r0, r8, 0x100
      beq- WIIMOTE_PLUS
      ori r7, r7, 0x100     ; 2

    WIIMOTE_PLUS:
      andi. r0, r8, 0x10
      beq- WIIMOTE_MINUS
      ori r7, r7, 0x10      ; plus

    WIIMOTE_MINUS:
      andi. r0, r8, 0x1000
      beq- NUNCHUK_C
      ori r7, r7, 0x1000    ; minus

    NUNCHUK_C:
      andi. r0, r8, 0x4000
      beq- NUNCHUK_Z
      ori r7, r7, 0x4000    ; c

    NUNCHUK_Z:
      andi. r0, r8, 0x2000
      beq- WIIMOTE_DONE
      ori r7, r7, 0x2000    ; z

    WIIMOTE_DONE:
      mr r8, r7

RETURN:
  andi. r0, r7, 0x9FFF
This is completely untested, expect typos or anything going on here, but ideally it should work basically the way the injector you're used to does. In the above snippet every button is just mapped back to itself, so the code does literally nothing, but you can rearrange the buttons (e.g. ori r7, r7, 0x800 ; a to change which button they virtually press. For newer games you'd need to adjust the registers (r7/r8 would be r6/r7 in read_kpad_button(), and the same rules apply to the garbage register as usual. If the first argument to the andi. where you're injecting the code is a different number than r0, you need to replace all the r0s with that register.

@Vague Rant On a different topic, do you know how hard it would be to "fix" the call of duty games? Some have classic support natively (which works *flawless*).

Some others have "pointing" control, where you point the rifle where you want to shoot, while the camera follows the pointer.

From what i tried in that game, it should be nicely playable with a classic controller *if* it is possible to decouple the camera from the pointer, and fix the rifle in the center of the screen. I guess this would be quite a bit more involved than just figuring out buttonmappings.
Yeah, that is definitely something that would be more complicated and not something you could do via just KPAD hacks. You'd need to find where the individual game handles its control scheme and decouple the camera and pointer as you mention. The way we're handling the pointer in these hacks is basically just tricking the games into thinking we're pointing the Wii Remote, so we can't do anything that a real pointer can't do. It would definitely be possible, but it's not something I know how to do or would be much help with.

OK someone games people asking form should work base on the quality of the game order should be.

1. Crash Bandicoot Crash of the Titans
2. Crash bandicoot Mind Over Mutant
3. SpongeBob SquarePants featuring Nicktoons: Globs of Doom

Also should do patch for cars 1 unsure different that whould be in itself as batter og ver should focused games people asking form first as take quite some time for patch to be made.
I definitely keep quality in mind as a metric for which games to look at (except when I don't; Flip's Twisted World), but there's a lot of other factors that go into it as well. For example, the previous game I did was by Incinerator Studio, so I decided to stick with that developer for the next game, just in the hope that I could recognize some similarities while the previous game was fresh in my memory--ultimately, I didn't, but that was the plan. :D

Cars 1 is definitely one I would like to come back to. I suspect it will be quite similar to Mater-National (moreso than Race-o-Rama was), so hopefully I can apply some of that knowledge to the original game.

This is amazing and I’ve loved the games so far. Is there any way you could take a peek at Thrillville: Off The Rails? PSP/PS2 lacks features, Wii is perfect and is the 360 version of the game but there’s some incredibly iffy motion controls for mini games.
Neat, this is another one I've never heard of, sounds like a pretty cool game though. Depending on the complexity of the motions needed, it might be a tough one, but I'll definitely add it to my investigation list.



globsofdoo.png


For the final game in the Nicktoons Unite!/SpongeBob SquarePants and Friends quadrilogy of co-op action games, our friends at Incinerator Studios once again took over development. The new studio created a game that aimed to fuse the combat and platforming from the previous entries into a title with a bit more variety. Incinerator ended up with what kind of amounts to another light action-platform-puzzler in the style of the TT Lego games. With a healthy dose of Nicktoons characters and worlds including SpongeBob, Jimmy Neutron, Tak and all the others that I definitely recognize, Globs is a solid crossover that doesn't break any new ground. Instead, it's content to be a goofy team-up of Nicktoons heroes and villains that's, you know, fine. It's also very easy.
I did not figure out the motion controls for this game.

Use the Skip Gadget Combo Motion Controls code to bypass these screens.

USAEUR (En,Fr)EUR (De,Es,It)SCNKOR

  1. Code:
    Classic Controller Support [Vague Rant]
    C20C2138 00000002
    28000001 41820008
    28000002 00000000
    C20C2C3C 00000002
    28000001 41820008
    28000002 00000000
    C20EC900 00000002
    28000001 41820008
    28000002 00000000
    0414F6A4 41820034
    C2086874 00000028
    90010024 2C040000
    40820134 8803005C
    2C000002 40820128
    2C0F0001 408200E4
    48000021 80097D5C
    3FAAAAAB 3D4CCCCD
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4080001C
    7CC53AAE 28060000
    408100C4 80030000
    70000800 4182000C
    38C0012C 48000008
    38C6FFFF 7CC53B2E
    38C00002 98C3005E
    80650000 28030001
    40810018 90A1000C
    7C6803A6 4E800021
    80A1000C 90650000
    2C030001 7FE3FB78
    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 00000000
    0408772C 7FC3F378
    04087E18 60000000
    C2087E1C 0000001F
    4800000D 00000000
    00000000 7C6802A6
    5760083C 7C630214
    2809FFFF 4082000C
    A1230000 48000014
    2C040002 408200C4
    38800001 B1230000
    71200800 41820008
    61088000 71200001
    41820008 61080008
    71204000 41820008
    61080004 71200002
    41820008 61080001
    71208000 41820008
    61080002 71200010
    41820008 61080800
    71200040 41820008
    61080800 71200008
    41820008 61084000
    71200020 41820008
    61080400 71202000
    41820008 61081000
    71200200 41820008
    61081000 71200080
    41820008 61080001
    71200004 41820008
    61082000 71200400
    41820008 61080010
    71201000 41820008
    61081000 7CE74378
    70E09FFF 00000000
    Code:
    Skip Gadget Combo Motion Controls [Vague Rant]
    063324C8 00000014
    806DC928 38000001
    98030011 98030012
    48000078 00000000
  2. Code:
    Classic Controller Support [Vague Rant]
    C20C1B04 00000002
    28000001 41820008
    28000002 00000000
    C20C2684 00000002
    28000001 41820008
    28000002 00000000
    C20EBC4C 00000002
    28000001 41820008
    28000002 00000000
    0414F22C 48000038
    C2086874 00000028
    90010024 2C040000
    40820134 8803005C
    2C000002 40820128
    2C0F0001 408200E4
    48000021 80097D5C
    3FAAAAAB 3D4CCCCD
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4080001C
    7CC53AAE 28060000
    408100C4 80030000
    70000800 4182000C
    38C0012C 48000008
    38C6FFFF 7CC53B2E
    38C00002 98C3005E
    80650000 28030001
    40810018 90A1000C
    7C6803A6 4E800021
    80A1000C 90650000
    2C030001 7FE3FB78
    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 00000000
    0408772C 7FC3F378
    04087E18 60000000
    C2087E1C 0000001F
    4800000D 00000000
    00000000 7C6802A6
    5760083C 7C630214
    2809FFFF 4082000C
    A1230000 48000014
    2C040002 408200C4
    38800001 B1230000
    71200800 41820008
    61088000 71200001
    41820008 61080008
    71204000 41820008
    61080004 71200002
    41820008 61080001
    71208000 41820008
    61080002 71200010
    41820008 61080800
    71200040 41820008
    61080800 71200008
    41820008 61084000
    71200020 41820008
    61080400 71202000
    41820008 61081000
    71200200 41820008
    61081000 71200080
    41820008 61080001
    71200004 41820008
    61082000 71200400
    41820008 61080010
    71201000 41820008
    61081000 7CE74378
    70E09FFF 00000000
    Code:
    Skip Gadget Combo Motion Controls [Vague Rant]
    063325E0 00000014
    806DC948 38000001
    98030011 98030012
    48000078 00000000
  3. Code:
    Classic Controller Support [Vague Rant]
    C20C1B04 00000002
    28000001 41820008
    28000002 00000000
    C20C2684 00000002
    28000001 41820008
    28000002 00000000
    C20EBC4C 00000002
    28000001 41820008
    28000002 00000000
    0414F240 48000038
    C2086874 00000028
    90010024 2C040000
    40820134 8803005C
    2C000002 40820128
    2C0F0001 408200E4
    48000021 80097D5C
    3FAAAAAB 3D4CCCCD
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4080001C
    7CC53AAE 28060000
    408100C4 80030000
    70000800 4182000C
    38C0012C 48000008
    38C6FFFF 7CC53B2E
    38C00002 98C3005E
    80650000 28030001
    40810018 90A1000C
    7C6803A6 4E800021
    80A1000C 90650000
    2C030001 7FE3FB78
    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 00000000
    0408772C 7FC3F378
    04087E18 60000000
    C2087E1C 0000001F
    4800000D 00000000
    00000000 7C6802A6
    5760083C 7C630214
    2809FFFF 4082000C
    A1230000 48000014
    2C040002 408200C4
    38800001 B1230000
    71200800 41820008
    61088000 71200001
    41820008 61080008
    71204000 41820008
    61080004 71200002
    41820008 61080001
    71208000 41820008
    61080002 71200010
    41820008 61080800
    71200040 41820008
    61080800 71200008
    41820008 61084000
    71200020 41820008
    61080400 71202000
    41820008 61081000
    71200200 41820008
    61081000 71200080
    41820008 61080001
    71200004 41820008
    61082000 71200400
    41820008 61080010
    71201000 41820008
    61081000 7CE74378
    70E09FFF 00000000
    Code:
    Skip Gadget Combo Motion Controls [Vague Rant]
    063325F4 00000014
    806DC948 38000001
    98030011 98030012
    48000078 00000000
  4. Code:
    Classic Controller Support [Vague Rant]
    C20C1B04 00000002
    28000001 41820008
    28000002 00000000
    C20C2684 00000002
    28000001 41820008
    28000002 00000000
    C20EBC4C 00000002
    28000001 41820008
    28000002 00000000
    0414F258 48000038
    C2086874 00000028
    90010024 2C040000
    40820134 8803005C
    2C000002 40820128
    2C0F0001 408200E4
    48000021 80097D5C
    3FAAAAAB 3D4CCCCD
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4080001C
    7CC53AAE 28060000
    408100C4 80030000
    70000800 4182000C
    38C0012C 48000008
    38C6FFFF 7CC53B2E
    38C00002 98C3005E
    80650000 28030001
    40810018 90A1000C
    7C6803A6 4E800021
    80A1000C 90650000
    2C030001 7FE3FB78
    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 00000000
    0408772C 7FC3F378
    04087E18 60000000
    C2087E1C 0000001F
    4800000D 00000000
    00000000 7C6802A6
    5760083C 7C630214
    2809FFFF 4082000C
    A1230000 48000014
    2C040002 408200C4
    38800001 B1230000
    71200800 41820008
    61088000 71200001
    41820008 61080008
    71204000 41820008
    61080004 71200002
    41820008 61080001
    71208000 41820008
    61080002 71200010
    41820008 61080800
    71200040 41820008
    61080800 71200008
    41820008 61084000
    71200020 41820008
    61080400 71202000
    41820008 61081000
    71200200 41820008
    61081000 71200080
    41820008 61080001
    71200004 41820008
    61082000 71200400
    41820008 61080010
    71201000 41820008
    61081000 7CE74378
    70E09FFF 00000000
    Code:
    Skip Gadget Combo Motion Controls [Vague Rant]
    0633260C 00000014
    806DC948 38000001
    98030011 98030012
    48000078 00000000
  5. Code:
    Classic Controller Support [Vague Rant]
    C20C2024 00000002
    28000001 41820008
    28000002 00000000
    C20C2BA4 00000002
    28000001 41820008
    28000002 00000000
    C20EC0D8 00000002
    28000001 41820008
    28000002 00000000
    0414F710 41820034
    C2086834 00000028
    90010024 2C040000
    40820134 8803005C
    2C000002 40820128
    2C0F0001 408200E4
    48000021 80097D1C
    3FAAAAAB 3D4CCCCD
    00000000 00000000
    3DCCCCCD 3F800000
    7CA802A6 90A1000C
    5727083C 38E7000C
    C0030074 FC000210
    C0230078 FC200A10
    FC00082A C0450014
    FC001040 4080001C
    7CC53AAE 28060000
    408100C4 80030000
    70000800 4182000C
    38C0012C 48000008
    38C6FFFF 7CC53B2E
    38C00002 98C3005E
    80650000 28030001
    40810018 90A1000C
    7C6803A6 4E800021
    80A1000C 90650000
    2C030001 7FE3FB78
    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 00000000
    040876EC 7FC3F378
    04087DD8 60000000
    C2087DDC 0000001F
    4800000D 00000000
    00000000 7C6802A6
    5760083C 7C630214
    2809FFFF 4082000C
    A1230000 48000014
    2C040002 408200C4
    38800001 B1230000
    71200800 41820008
    61088000 71200001
    41820008 61080008
    71204000 41820008
    61080004 71200002
    41820008 61080001
    71208000 41820008
    61080002 71200010
    41820008 61080800
    71200040 41820008
    61080800 71200008
    41820008 61084000
    71200020 41820008
    61080400 71202000
    41820008 61081000
    71200200 41820008
    61081000 71200080
    41820008 61080001
    71200004 41820008
    61082000 71200400
    41820008 61080010
    71201000 41820008
    61081000 7CE74378
    70E09FFF 00000000
    Code:
    Skip Gadget Combo Motion Controls [Vague Rant]
    06332CB8 00000014
    806DC948 38000001
    98030011 98030012
    48000078 00000000

Button Mapping​

Wii Remote/NunchukClassic ControllerFunction
Wiimote HomeHome
Remember: Right Stick as pointer
Open/Close Home Menu
Wiimote D-PadD-Pad
ZL
Menus
Navigation
Gameplay
Gadget Combo
Wiimote AA
B
Menus
Confirm
Gameplay
Jump
Wiimote BYMenus
Cancel
Gameplay
Attack
Wiimote 1 & 2Not mappedNot used?
Wiimote PlusPlusGameplay
Pause
Drop In (player 2)
Wiimote MinusMinus
L/R
Gameplay
Switch Character
Drop Out (player 2)
Wiimote PointerRight StickMenus
Navigation
Home Button Menu
Navigation
Nunchuk StickLeft StickGameplay
Movement
Nunchuk CXGameplay
Interact (pull levers, etc.)
Nunchuk ZZRGameplay
Gadget Attack

General Notes​

  • I did not figure out the motion controls for this game. However, I was able to bypass the motion control gameplay entirely and have included a separate code above for this purpose. In the base game, once the Combo Meter is full, you press the Gadget Combo button and the game freezes for a few seconds while you match the on-screen motion prompts. The above code skips this entire phase so that pressing the Gadget Combo button immediately triggers a Gadget Combo.

    • I'm not even sorry, this is better.

  • The button mapping here is mostly cribbed from the PS2 version of the game. The only major change is that the PS2 version used the D-Pad to navigate the menu and toggle characters, while the Wii version uses the D-Pad to navigate the menu and trigger Gadget Combos. Since we can't lose menu navigation, we had to leave the D-Pad as-is and cycling characters is now done with L/R while Gadget Combos are on ZL. I think it's fine, shouldn't bother anybody.

  • This game is infamous for its save corruption bug. If you encounter save corruption while playing this game, it's not because of anything I did. THQ acknowledged the bug and recommended that you never exit the game from the hub world. When you want to stop playing, enter a stage of your choice and shut down/exit from there. I know this sucks, tell THQ. Actually never mind, they went out of business. Stuff like this probably didn't help.

Technical Notes​

This is another one with a symbol map left over on the disc. Thanks, Incinerator.

Code breakdown:
  • C2 in InGameDevicesCheck(): bypass Nunchuk check
  • C2 in AreAllAttachmentsAttached(): bypass Nunchuk check (again)
  • C2 in FormatDeviceMessage(): fffff are you fu--yes, it's another one
  • 04 in Update: read Classic Controller as Nunchuk-type controller
  • C2 in calc_dpd_variable(): simulate IR pointer on Right Stick
  • 04 in read_kpad_stick(): stick redirection
  • 04 and C2 in KPADRead(): dropped connection fix and button injector
Code:
; KPADRead
; button injector
; 80087E1C for USA/EUR (En,Fr)/EUR (De,Es,It)/SCN
; 80087DDC for KOR
; r4 holds extType
; r7 holds wiimote bitfield
; r8 holds wiimote+nunchuk bitfield
; r9 holds classic bitfield

; magic
  bl GRAB
MAGIC:
    HELD:   .double 0
GRAB:
  mflr r3
  slwi r0, r27, 1
  add r3, r3, r0

; check dropped extension
  cmplwi r9, 0xFFFF
  bne- CLASSIC
  lhz r9, HELD-MAGIC(r3)
  b DROPPED_CONNECTION

CLASSIC:
  cmpwi r4, 0x2
  bne- RETURN

  li r4, 0x1            ; i'm a nunchuk
  sth r9, HELD-MAGIC(r3)

DROPPED_CONNECTION:
    CLASSIC_HOME:
      andi. r0, r9, 0x800
      beq- CLASSIC_UP
      ori r8, r8, 0x8000    ; home

    CLASSIC_UP:
      andi. r0, r9, 0x1
      beq- CLASSIC_DOWN
      ori r8, r8, 0x8       ; up (v) / left (h)

    CLASSIC_DOWN:
      andi. r0, r9, 0x4000
      beq- CLASSIC_LEFT
      ori r8, r8, 0x4       ; down (v) / right (h)

    CLASSIC_LEFT:
      andi. r0, r9, 0x2
      beq- CLASSIC_RIGHT
      ori r8, r8, 0x1       ; left (v) / down (h)

    CLASSIC_RIGHT:
      andi. r0, r9, 0x8000
      beq- CLASSIC_A
      ori r8, r8, 0x2       ; right (v) / up (h)

    CLASSIC_A:
      andi. r0, r9, 0x10
      beq- CLASSIC_B
      ori r8, r8, 0x800     ; a

    CLASSIC_B:
      andi. r0, r9, 0x40
      beq- CLASSIC_X
      ori r8, r8, 0x800     ; a

    CLASSIC_X:
      andi. r0, r9, 0x8
      beq- CLASSIC_Y
      ori r8, r8, 0x4000    ; c

    CLASSIC_Y:
      andi. r0, r9, 0x20
      beq- CLASSIC_L
      ori r8, r8, 0x400     ; b

    CLASSIC_L:
      andi. r0, r9, 0x2000
      beq- CLASSIC_R
      ori r8, r8, 0x1000    ; minus

    CLASSIC_R:
      andi. r0, r9, 0x200
      beq- CLASSIC_ZL
      ori r8, r8, 0x1000    ; minus

    CLASSIC_ZL:
      andi. r0, r9, 0x80
      beq- CLASSIC_ZR
      ori r8, r8, 0x1       ; left (v) / down (h)

    CLASSIC_ZR:
      andi. r0, r9, 0x4
      beq- CLASSIC_PLUS
      ori r8, r8, 0x2000    ; z

    CLASSIC_PLUS:
      andi. r0, r9, 0x400
      beq- CLASSIC_MINUS
      ori r8, r8, 0x10      ; plus

    CLASSIC_MINUS:
      andi. r0, r9, 0x1000
      beq- CLASSIC_DONE
      ori r8, r8, 0x1000    ; minus

    CLASSIC_DONE:
      or r7, r7, r8

RETURN:
  andi. r0, r7, 0x9FFF
The debug symbol map was an enormous help in bypassing the motion control sections, there's no chance in hell I could have figured that out otherwise. It's so many layers of stuff from the multiple menu layers, the sounds and graphical effects that are triggered when you open the Gadget Combo menu and the code for performing a Gadget Combo is nowhere near the stuff that manages the Gadget Combo QTE minigames. Extremely fortunate that debug map was available or this one would probaby have been canned.
 
This is completely untested, expect typos or anything going on here, but ideally it should work basically the way the injector you're used to does. In the above snippet every button is just mapped back to itself, so the code does literally nothing, but you can rearrange the buttons (e.g. ori r7, r7, 0x800 ; a to change which button they virtually press. For newer games you'd need to adjust the registers (r7/r8 would be r6/r7 in read_kpad_button(), and the same rules apply to the garbage register as usual. If the first argument to the andi. where you're injecting the code is a different number than r0, you need to replace all the r0s with that register.
Okay, thank you! Ill look into remapping Rhythm Heaven to support the Horizontal remote soon as a test.

@Vague Rant Bad news, your KPAD Wiimote mapper does not work. I tried changing the bytes for Rhythm Heaven Fever (A read_kpad_button game) And it does not seem to care, it just stays as it is, the original controls. Is the insertion address 8016c4d4 correct for that game?

If a game does not use the Nunchuk inputs, do I delete both nunchuk assembly lines and make WIIMOTE_MINUS branch to WIIMOTE_DONE?
 
Last edited by awesomeee,
Thank you very much, but the batch file fails with "ERROR: Could not find 00000007.app file." Any idea how to remedy this?

View attachment 475483

I appreciate the quick reply!
Here's what I got by verifying with the latest version of Dolphin:
View attachment 475679

The European WAD shows the same messages except "key index is 20 but should be 0."

I then tried WADs from different sources but got the same result as before, the USA WAD saying "key index is 199" and European "key index is 20."
Ever get a chance to look at Blaster Master: Overdrive again btw? If not no worries!

and thanks again for all that you've done.
 
  • Like
Reactions: Vague Rant
@Honkinghard Im sorry I got mad at you like that, Please dont take it too hard. But just please dont do that next time, as you could get in trouble from law enforcement or something like that.

As for the issue, I think its the WAD builder issue, not your wad.
 

Site & Scene News

Popular threads in this forum