- Joined
- Aug 7, 2008
- Messages
- 2,538
- Solutions
- 1
- Reaction score
- 1,520
- Trophies
- 2
- Location
- Melbourne
- Website
- vaguerant.tumblr.com
- XP
- 4,165
- Country

MadWorld is definitely at the upper-end of complicated, with lots of unique motions the game wants you to pull off. Ordinarily, I'd say "too hard", but MadWorld is one that I've kept on my list anyway because it would be so huge for that game to have traditional controls. It's never been re-released on anything else, so motion controls (or emulating motion controls) are the only option, and I think they turned a lot of people away from a game they'd otherwise enjoy. It's definitely a bit of a holy grail title for me.Oh yeah, out of curiosity how complex is Madworld's use of motion to convert into a classic controller scheme? It'd be great to have an alternative control option for that game, i remember it being fun but it's heavy use of motion control made it kind of tiring to play.
So obviously it varies from title to title, but here's an example from a recent hack, Rygar. I'll add some comments for good places to do some code insertions. This is specifically the USA version, EUR is different again.Do you know the insertion address for some game's Accelerometer data? I know this is a silly question since motion controls are super hard to implement, but I think i am getting close to getting my hack to work!
Code:
801B7374 lwz r6, 0x000C (r3) read_kpad_acc ; this is what i use for complex games
801B7378 addi r4, r30, 12 read_kpad_acc
801B737C lwz r5, 0x0010 (r3) read_kpad_acc
801B7380 lwz r0, 0x0014 (r3) read_kpad_acc
801B7384 stfs f4, 0x04AC (r3) read_kpad_acc ; the Z axis gets written here
801B7388 mr r3, r30 read_kpad_acc
801B738C lfs f1, 0x04A4 (r30) read_kpad_acc ; this reads in the X axis
801B7390 stw r6, 0x0014 (sp) read_kpad_acc
801B7394 stw r5, 0x0018 (sp) read_kpad_acc
801B7398 stw r0, 0x001C (sp) read_kpad_acc
801B739C bl ->0x801B6EA8 --> calc_acc
801B73A0 lfs f1, 0x04A8 (r30) read_kpad_acc ; this reads in the Y axis (good for simple games)
801B73A4 mr r3, r30 read_kpad_acc
801B73A8 addi r4, r30, 16 read_kpad_acc
801B73AC bl ->0x801B6EA8 --> calc_acc
801B73B0 lfs f1, 0x04AC (r30) read_kpad_acc ; this reads in the Z axis (")
801B73B4 mr r3, r30 read_kpad_acc
801B73B8 addi r4, r30, 20 read_kpad_acc
801B73BC bl ->0x801B6EA8 --> calc_acc
r0, r4, r5 and r6 available to do GPR stuff and f0, f1, f2 and f3 to do FPR stuff.The value that's currently in
f4 is the Z axis about to be written out (see comment), so you can just load some other value into f4 to replace the real accelerometer data. To replace the X and Y axes, you'll need to write to 0x???? (r30) (offset varies by SDK version but if you find something like the above, you can see the offsets the game is using). In this case, you need to write to 0x04A4 (r30) for the X axis and 0x04A8 (r30) for the Y axis.If the game you're looking at only needs you to work with a single axis (in particular Y or Z), you can use the points where the Y and Z axes get read in from
0x04A8 (r30) and 0x04AC (r30). In this case, r0, r3 and r4 are definitely free and f1 needs to be replaced with fake data.I never actually played World of Goo back in the day, so I'm not sure how it'd go, but IIRC they did end up porting it to a bunch of traditionally-controlled platforms, right? I think it's on Xbox and stuff now? That's a pretty good sign, sort of suggests that the controls are workable without infra-red. Hopefully something similar to other platforms would work on Wii, so I'll add it to my investigate list.Any chance for a cc hack of "world of goo"? I mean yes, it's an IR pointer driven game, but I like the art style and humour of it. And since it has no shaking components in it, it should be easy to do. The IR emulation in the cc hacks is pretty on point and smooth
Lego Batman: The Videogame was TT Games' first foray into adapting comic book media into Lego form. In fact, Lego Batman pulls from a variety of sources, especially the Tim Burton/Joel Schumacher Batman movies and the '90s animated series. Introducing the concept of changeable suits to the series allows Batman and the whole Bat-Family to alternate abilities in the middle of a stage, meaning this entry has perhaps the greatest variety in gameplay within individual stages so far in the franchise. Other enhancements over previous games include camera control and the ability to target when using projectile weapons.
Another Lego game, another highlight for @NestorM.
USAEUR (Rev 1)
-
Code:
Classic Controller Support [Vague Rant] C2196344 00000002 28030001 41820008 28030002 00000000 040B9E64 48000024 040B9EC0 4E800020 C201AE8C 00000034 90010024 2C040000 40820190 8803005C 2C000002 40820184 2C0F0001 40820140 48000021 8054FB68 00000000 00000000 8005EA5C 3FAAAAAB 3D4CCCCD 3F800000 7CA802A6 7C85DA14 80E50000 5760103A 7CE70214 80E70000 2C070000 4182002C 88E709DB 88C40004 98E40004 2C07004D 4182000C 2C070052 40820010 7C073000 41820044 48000024 80C50008 80830004 70808000 41820020 68C60001 90C50008 2C060001 418200B8 38000000 90030020 90030024 2C060001 4182000C 98C3005E 4800009C 38000002 9803005E 8065000C 28030001 40810018 90A1000C 7C6803A6 4E800021 80A1000C 9065000C 2C030001 7FE3FB78 C0450010 40820008 EC4200B2 C0650014 C0030020 C0230060 FC211024 4800005D D0030020 80030020 68000001 90030020 C0030024 C0230064 FC200850 4800003D D0030024 80030024 68000001 90030024 2C070052 40820014 C0030074 D0030060 C0030078 D0030064 80010024 7C0803A6 38210020 4E800020 FC0100FA C0250018 FC000800 4180000C FC000890 48000014 FC200850 FC000800 41810008 FC000890 4E800020 60000000 00000000 0401BD44 7FC3F378 C201BD7C 00000012 4E800421 2C0F0001 40820080 4800000D 3F000000 00000000 7C6802A6 C0430000 C0630004 809EFFA0 80BEFFA4 80DEFFA8 C03E0014 39000001 48000021 C03E0018 39000004 48000015 909EFFA0 90BEFFA4 90DEFFA8 48000034 FC000A10 FC001040 4D800020 FC011840 41800008 5508083C 7CC04039 40820008 7CA54378 7C844378 7CC64079 4E800020 60000000 00000000 C201C434 0000001F 4800000D 00000000 00000000 7C6802A6 5760083C 7C630214 2C0400FD 4082000C A1230000 48000014 2C040002 408200C4 38800001 B1230000 71200800 41820008 61088000 71200001 41820008 61080008 71204000 41820008 61080004 71200002 41820008 61080001 71208000 41820008 61080002 71200010 41820008 61082000 71200040 41820008 61080800 71200008 41820008 61084000 71200020 41820008 61080400 71202000 41820008 61080200 71200200 41820008 61080100 71200080 41820008 61082000 71200004 41820008 61080400 71200400 41820008 61080010 71201000 41820008 61081000 7CE74378 70E09FFF 00000000 -
Code:
Classic Controller Support [Vague Rant] C219636C 00000002 28030001 41820000 28030002 00000000 040B9E64 48000024 040B9EC0 4E800020 C201AE8C 00000034 90010024 2C040000 40820190 8803005C 2C000002 40820184 2C0F0001 40820140 48000021 8054FBA8 00000000 00000000 8005EA5C 3FAAAAAB 3D4CCCCD 3F800000 7CA802A6 7C85DA14 80E50000 5760103A 7CE70214 80E70000 2C070000 4182002C 88E709DB 88C40004 98E40004 2C07004D 4182000C 2C070052 40820010 7C073000 41820044 48000024 80C50008 80830004 70808000 41820020 68C60001 90C50008 2C060001 418200B8 38000000 90030020 90030024 2C060001 4182000C 98C3005E 4800009C 38000002 9803005E 8065000C 28030001 40810018 90A1000C 7C6803A6 4E800021 80A1000C 9065000C 2C030001 7FE3FB78 C0450010 40820008 EC4200B2 C0650014 C0030020 C0230060 FC211024 4800005D D0030020 80030020 68000001 90030020 C0030024 C0230064 FC200850 4800003D D0030024 80030024 68000001 90030024 2C070052 40820014 C0030074 D0030060 C0030078 D0030064 80010024 7C0803A6 38210020 4E800020 FC0100FA C0250018 FC000800 4180000C FC000890 48000014 FC200850 FC000800 41810008 FC000890 4E800020 60000000 00000000 0401BD44 7FC3F378 C201BD7C 00000012 4E800421 2C0F0001 40820080 4800000D 3F000000 00000000 7C6802A6 C0430000 C0630004 809EFFA0 80BEFFA4 80DEFFA8 C03E0014 39000001 48000021 C03E0018 39000004 48000015 909EFFA0 90BEFFA4 90DEFFA8 48000034 FC000A10 FC001040 4D800020 FC011840 41800008 5508083C 7CC04039 40820008 7CA54378 7C844378 7CC64079 4E800020 60000000 00000000 C201C434 0000001F 4800000D 00000000 00000000 7C6802A6 5760083C 7C630214 2C0400FD 4082000C A1230000 48000014 2C040002 408200C4 38800001 B1230000 71200800 41820008 61088000 71200001 41820008 61080008 71204000 41820008 61080004 71200002 41820008 61080001 71208000 41820008 61080002 71200010 41820008 61082000 71200040 41820008 61080800 71200008 41820008 61084000 71200020 41820008 61080400 71202000 41820008 61080200 71200200 41820008 61080100 71200080 41820008 61082000 71200004 41820008 61080400 71200400 41820008 61080010 71201000 41820008 61081000 7CE74378 70E09FFF 00000000
Button Mapping
| Wii Remote/Nunchuk | Classic Controller | Function |
|---|---|---|
| Wiimote Home | Home Remember that B is your A button | Open/Close Home Menu |
| Wiimote D-Pad | D-Pad Right Stick | Menus Navigation Gameplay Camera Control |
| Wiimote A | B | Menus Confirm Gameplay Jump |
| Wiimote B | Y ZR | Menus Cancel Gameplay Attack |
| Wiimote 1 | L | Gameplay Switch Character (Free Play) |
| Wiimote 2 | R | Gameplay Switch Character (Free Play) |
| Wiimote Plus | Plus | Gameplay Pause |
| Wiimote Minus | Minus | Not used? |
| Wiimote Pointer | Left Stick | Gameplay Aiming Home Button Menu Navigation |
| Nunchuk Stick | Left Stick | Menus Navigation Gameplay Movement |
| Nunchuk C | X | Gameplay Switch Character (Story) |
| Nunchuk Z | A ZL | Gameplay Interact (Build, Pull Levers, etc.) |
General Notes
- This hack will not work on EUR (Rev 0). I didn't hack that version, only the later EUR (Rev 1). If playing the EUR version game, you will need to have the later release. Thanks to @Gomza for confirming this.
- This one definitely marks the end of doing Lego games as an easy break from more complex games, the IR pointer implementation here was probably the most difficult of any hack to date. I'll talk about it more in the Technical Notes if you like that kind of thing.
- Besides that, these are pretty standard at this point. Same control setup from Lego Star Wars and Indiana Jones, so your Confirm/Cancel are a little iffy (Y/B) but gameplay controls how you'd expect if you've played a Lego game on any platform but the Wii.
Technical Notes
Code breakdown:
Before I get to the IR pointer shenanigans, this game helped me understand the lag frame issue I've been working with on the last few games. Lego Batman has a really odd quirk where the extension controller loses its connection for a couple of frames every single time you pause the game. This has nothing to do with me, it did it before I started modifying the game at all. But this allowed me to understand the situation where a controller has dropped for a few frames and what input occurs in that situation. The button injector now includes a handler for this situation (see the source above if you're interested). It works the same way Nintendo solved this issue: read in a copy of the inputs from the previous frame and use those instead.
All right, the IR pointer. Certainly, it would have been possible to just put the pointer on the Right Stick and move on, but this game added camera controls as well (on D-Pad for Wii) and I wanted those on the Right Stick. Initially, I figured I could just have the Left Stick do both simultaneously. Aiming in Lego games requires you to press and hold a button and you can't walk and aim at the same time anyway, so maybe I can just make that an "enable pointer" button? Not really. For one thing, Lego games are infamous for their poor framerates and everything in these hacks is frame-based. The aiming button is also your main attack button, so I needed to wait for you to hold the button for a while before switching to aiming mode, but "a while" is hugely variable in this game for performance reasons. Sometimes the pointer would trigger early, or late, and you'd be pointing off to the edge until it "woke up", etc.
Before I get to my solution, let's also talk about how weird the Lego games are about their pointer support. For one thing, the pointers in this game are always on, even if you're not currently pointing at the screen. Presumably related to this is a feature TT includes in their Lego games to manually adjust the pointer position if it is unchanged for a few frames. Basically, if you stop moving the pointer, either because you're being impossibly perfectly still or because you aren't pointing at the TV any more, they move the pointer to the edge of the screen. Not off the screen, just in a corner somewhere. Why not just turn the pointer off? Great question! Let's continue.
Because we're controlling the pointer with an analog stick, it's very possible to have it sit completely still: just stop touching the analog stick. Assuming you don't have any drift issues, the pointer will stop moving. It's really confusing and distracting to have the pointer moving around like it has a mind of its own, so on every frame, I jiggle the pointer on both the X and Y axes (important if you're rammed against the edge of the screen so only one "jiggle" does anything) by the smallest possible 32-bit floating point value, 0.000...1 (pretend there's 44 zeroes there). This prevents the game from messing with the pointer for as long as you're using it and is not visible in game because that's a tiny fraction of a pixel that it's moving. Once you exit aiming mode, I stop jiggling it and let the game do whatever it wants with the cursor.
Finally, let's get to how I solved managing the pointer. It basically amounts to identifying a value in memory that indicates the current pointer state and using that value to toggle whether the pointer is enabled. If the current player is throwing a Batarang (or Robinrang, whatever he ... you know what I mean) or aiming the Attract Suit's vacuum, the Left Stick takes control of the IR pointer. This required a pointer to each player's state, which I eventually found mostly through trial and error switching to target mode and using the cheat search, then working backward to find a pointer to that value since it's not constant.
This still wasn't quite enough, because for whatever reason, TT made another remarkably weird choice, and the Nunchuk Stick switches to camera control when you're using the Attract Suit. Why? No idea, that doesn't make any sense, you already established that camera control is on the D-Pad. Is this ... a mistake? Whatever. Now we need to check if the pointer is currently in Attract Suit mode and switch up the analog sticks so that now the Classic Right Stick is controlling the Nunchuk Stick so that you get to keep your Right Stick camera controls.
C2: read Nunchuk Stick when Classic Controller is connected04and04insetKpad(): disable real CC support in HBMC2incalc_dpd_variable(): IR pointer emulation with some trickiness04andC2inread_kpad_stick(): redirect Classic Left Stick into Nunchuk Stick, D-Pad emulation on Right StickKPADRead(): button injector, includes lag frame fix directly
Code:
; KPADRead
; drop dupe frames
; KPADRead
; 8001C434 for USA/EUR (Rev 1)
; r4 holds extType
; r7 holds wiimote bitfield
; r8 holds wiimote+nunchuk bitfield
; r9 holds classic bitfield
; magic
bl GRAB
MAGIC:
HELD: .int 0
HELD2: .int 0
GRAB:
mflr r3
slwi r0, r27, 1
add r3, r3, r0
; check dropped extension
cmpwi r4, 0xFD
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, 0x2000 ; z
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, 0x200 ; 1
CLASSIC_R:
andi. r0, r9, 0x200
beq- CLASSIC_ZL
ori r8, r8, 0x100 ; 2
CLASSIC_ZL:
andi. r0, r9, 0x80
beq- CLASSIC_ZR
ori r8, r8, 0x2000 ; z
CLASSIC_ZR:
andi. r0, r9, 0x4
beq- CLASSIC_PLUS
ori r8, r8, 0x400 ; b
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
Before I get to the IR pointer shenanigans, this game helped me understand the lag frame issue I've been working with on the last few games. Lego Batman has a really odd quirk where the extension controller loses its connection for a couple of frames every single time you pause the game. This has nothing to do with me, it did it before I started modifying the game at all. But this allowed me to understand the situation where a controller has dropped for a few frames and what input occurs in that situation. The button injector now includes a handler for this situation (see the source above if you're interested). It works the same way Nintendo solved this issue: read in a copy of the inputs from the previous frame and use those instead.
All right, the IR pointer. Certainly, it would have been possible to just put the pointer on the Right Stick and move on, but this game added camera controls as well (on D-Pad for Wii) and I wanted those on the Right Stick. Initially, I figured I could just have the Left Stick do both simultaneously. Aiming in Lego games requires you to press and hold a button and you can't walk and aim at the same time anyway, so maybe I can just make that an "enable pointer" button? Not really. For one thing, Lego games are infamous for their poor framerates and everything in these hacks is frame-based. The aiming button is also your main attack button, so I needed to wait for you to hold the button for a while before switching to aiming mode, but "a while" is hugely variable in this game for performance reasons. Sometimes the pointer would trigger early, or late, and you'd be pointing off to the edge until it "woke up", etc.
Before I get to my solution, let's also talk about how weird the Lego games are about their pointer support. For one thing, the pointers in this game are always on, even if you're not currently pointing at the screen. Presumably related to this is a feature TT includes in their Lego games to manually adjust the pointer position if it is unchanged for a few frames. Basically, if you stop moving the pointer, either because you're being impossibly perfectly still or because you aren't pointing at the TV any more, they move the pointer to the edge of the screen. Not off the screen, just in a corner somewhere. Why not just turn the pointer off? Great question! Let's continue.
Because we're controlling the pointer with an analog stick, it's very possible to have it sit completely still: just stop touching the analog stick. Assuming you don't have any drift issues, the pointer will stop moving. It's really confusing and distracting to have the pointer moving around like it has a mind of its own, so on every frame, I jiggle the pointer on both the X and Y axes (important if you're rammed against the edge of the screen so only one "jiggle" does anything) by the smallest possible 32-bit floating point value, 0.000...1 (pretend there's 44 zeroes there). This prevents the game from messing with the pointer for as long as you're using it and is not visible in game because that's a tiny fraction of a pixel that it's moving. Once you exit aiming mode, I stop jiggling it and let the game do whatever it wants with the cursor.
Finally, let's get to how I solved managing the pointer. It basically amounts to identifying a value in memory that indicates the current pointer state and using that value to toggle whether the pointer is enabled. If the current player is throwing a Batarang (or Robinrang, whatever he ... you know what I mean) or aiming the Attract Suit's vacuum, the Left Stick takes control of the IR pointer. This required a pointer to each player's state, which I eventually found mostly through trial and error switching to target mode and using the cheat search, then working backward to find a pointer to that value since it's not constant.
This still wasn't quite enough, because for whatever reason, TT made another remarkably weird choice, and the Nunchuk Stick switches to camera control when you're using the Attract Suit. Why? No idea, that doesn't make any sense, you already established that camera control is on the D-Pad. Is this ... a mistake? Whatever. Now we need to check if the pointer is currently in Attract Suit mode and switch up the analog sticks so that now the Classic Right Stick is controlling the Nunchuk Stick so that you get to keep your Right Stick camera controls.
Last edited by Vague Rant,











