Register | Login | |||||
Main
| Memberlist
| Active users
| ACS
| Commons
| Calendar
| Online users Ranks | FAQ | Color Chart | Photo album | IRC Chat |
| |
1 user currently in Rom Hacking: |
Acmlm's Board - I2 Archive - Rom Hacking - ASM Hacking Question - Controller Presses | | | |
Pages: 1 2 | Add to favorites | "RSS" Feed | Next newer thread | Next older thread |
User | Post | ||
Rockman Flurry Level: 26 Posts: 162/250 EXP: 96387 For next: 5888 Since: 03-17-04 Since last post: 18 days Last activity: 16 days |
| ||
In the past, there have been some ASM hacks I wanted to do, which I could've done if I knew how to work with the controller presses. I know it has something to do with $4016, or something like that. For example, the select button in Super Mario Bros. 3 doesn't really have a purpose. As practice, I want to try to see if I can make the select button make Mario Tanooki Mario for example. How do I go about doing this? Writing a breakpoint to the controller address I have done, just halts the game. I also wanted to do an ASM hack to Zelda, in which if you hold down the select button, Link can run faster. Any help would be great. Thanks. |
|||
Euclid Cheep-cheep Level: 23 Posts: 152/193 EXP: 65528 For next: 2195 Since: 03-15-04 From: Australia Since last post: 24 days Last activity: 7 days |
| ||
If that's the case then the best bet is not to play around with the $4016. Go find where the controller inputs are stored in memory, then find the routine which tells the game what to do when this button is pressed (usually done by some BIT/CMP then BEQ operations) and work from there. |
|||
DahrkDaiz Red Super Koopa Acmlm's Mosts 2005 Best ROM Hacker Level: 45 Posts: 588/885 EXP: 643520 For next: 16644 Since: 03-15-04 From: K-Town Since last post: 4 hours Last activity: 4 hours |
| ||
Bingo with what Euclid said. Just use the game's controller status bytes instead of messing with the hardware controller status registers. You have to do some funky junk to get what button was held, what button was just pressed and stuff... Just for reference for SMB3: $17 = Controller status of buttons being held down. $18 = Controller status of buttons that have JUST been pressed (resets on every frame). |
|||
Gavin Fuzzy Rhinoceruses don't play games. They fucking charge your ass. Level: 43 Posts: 613/799 EXP: 551711 For next: 13335 Since: 03-15-04 From: IL, USA Since last post: 13 hours Last activity: 13 hours |
| ||
although i do not know the commonality of this method, it's the only one i've really bothered looking at, as it's used in FF1. I make some shitty explination of it a bit ago, and since i'm lazy, i'm using it as basically my whole explination, just organized better. Briefly, the process goes as follows: the LDA $4016 gets the button status, the returned value is then compared to one, which will either set or reset the Carry register. The value in the Carry Regiser is then rotated (ROL) into $20, then (X with initial value 8) is decremented until X equals zero, which will cause a bypass branch (BNE) and RTS ending the process.
Basically the first 4 lines of code ($D7C9 - $D7D0) is a process called "Joystick Strobing". Strobing involves writing ones and zeros into the joystick input register ($4016) and a strobe has to be performed for every read. This joystick register is used to define the type of input and is used to read the status of all current joystick buttons. In this instance of code joystick one is checked for A, SELECT, START, UP, DOWN, LEFT, and RIGHT buttons with the AND bitwise operations later down the routine. All this is detailed in Yoshi's doc, but i'll throw in the relevant info right here: "On a full strobe, the joypad's button status will be returned in a single-bit stream (D0). Multiple reads need to be made to read all the information about the controller." Controller data is sent 1 bit at a time, and thusly $4016 must be read repeatedly to capture all information about the controller being sent, which is why the loop is used. So there isn't really much to do with strobing, just know that it's there and that if you plan on writing any of your own code, that you'll have to include it before every read. So then after it prepares the joystick for being read, the X register is loaded with 8 preparing for the eventual loop that will read and place the status of each processed joypad button into the single ram address. Next, the first actual read of the controller data occurs. Honestly i forget the purpose (if any exists??) for the AND, and it's really not vital in understanding out this process works. So next up is the CMP #$01, which checks to see if the value currently loaded into the accumulator is equal to 1. If it is, the Carry is set (1), and if not, the Carry is reset (0). The status of all 8 buttons is loaded into one zero-page RAM address: $20. The ROL (Rotate Left) bitwise operand loads the value currently set into the Carry into the first bit (D0) of $20 and shits every other bit left. After the ROL, there is a DEX (Decrement X) operand, lowering the value of X by one. Then next line of code BNE (Branch on Z reset) basically checks the status of the Z (Zero Processor Status Register) which will be set if the result of the last operation performed was zero. So basically, if the last operation (that being the Decrementing of X) resulted in X not being zero, then branch to $D7D5 which will read the status of the other remaining buttons and continue the loop until X does equal zero. And the last command ($D7E1) is of course the RTS (Return to Sub-Routine), basic stack-manipulation command which will return to the address pushed into the Stack either (and most usually) a JSR (Jump to Sub-Routine) command or by some other tricky stack manipulation that really doesn't need to be discussed right here for our purposes. This ends the joystick read info for this particular portion of the Final Fantasy code. |
|||
Rockman Flurry Level: 26 Posts: 163/250 EXP: 96387 For next: 5888 Since: 03-17-04 Since last post: 18 days Last activity: 16 days |
| ||
I figured out how it works! You guys are the best! Thanks plenty. I'm still in practicing mode. As practice, I made it so when Mario jumps, he turns into Raccoon Mario. I'm working on making that happen with the select button. (edited by Rockman on 04-06-05 04:36 PM) (edited by Rockman on 04-06-05 04:38 PM) |
|||
BMF98567 BLACK HAS BUILT A SILLY DICE-MAZE! GO! Current list of BURNING FURY >8( recipients: - Yiffy Kitten (x2) - Xkeeper Level: 53 Posts: 755/1261 EXP: 1094149 For next: 62970 Since: 03-15-04 From: Blobaria Special Move: Rising Meatloaf Backhand Combo Since last post: 21 hours Last activity: 1 hour |
| ||
Friggin' awesome, Gav! I never could figure out exactly how that code worked...for some reason, the whole concept of ROL and the Carry bit went completely over my head. It looked to me like it was constantly rotating the same byte over and over again, and the flags just "magically" appeared there. I feel really stupid now. | |||
DahrkDaiz Red Super Koopa Acmlm's Mosts 2005 Best ROM Hacker Level: 45 Posts: 590/885 EXP: 643520 For next: 16644 Since: 03-15-04 From: K-Town Since last post: 4 hours Last activity: 4 hours |
| ||
As far as a I know, NES only has the 2 registers which you must strobe. Though I rememeber reading something about a "half" strobe, but I never did read any more information on what that exactly did or the results of doing it. | |||
Jathys Red Goomba Level: 11 Posts: 16/48 EXP: 5916 For next: 69 Since: 12-21-04 Since last post: 8 days Last activity: 8 days |
| ||
This was surprizingly informative. Glad I stopped by. | |||
Parasyte Bullet Bill Level: 35 Posts: 420/514 EXP: 267348 For next: 12588 Since: 05-25-04 Since last post: 104 days Last activity: 32 days |
| ||
I suggest not reading directly from the controller regs, if you can avoid it. And you can! Every game will already do the reading for you, so you just have to find where they store the data. A nice advantage of looking for the controller variables is that you'll probably also find some other variables, such as the "down-state" variable. Most games will keep a copy of the "current" and "last" controller variables (meaning the buttons currently, and last held, respectively) and use these values along with an AND and EOR operation to check if a button has JUST been pressed since the last frame. (EG, this algorithm will disregard any buttons that are still being held since the last frame -- these bits are set to zero) This little algorithm is what I call the down-state algorithm. It's useful when you don't want your code to execute EVERY frame when you push a button. A good example is during a menu screen -- if your menu handler simply checks the D-pad each frame and moves a cursor depending on the state, you'll find the cursor moving FAR too fast, simply because the code doesn't know when to stop. For this, you can use the down-state variable, which will ensure the cursor will only move one position until the button is release and pressed again. (There are also ways to impliment a "timer" to continue moving the cursor as long as the button is held, while still managing the speed. Even similar to how your keyboard acts when holding a key; the key is typed, then there is a 'long' delay. If you continue holding the key, it will begin typing the key with 'short' delays. However, these ideas are beyond the scope of this post.) The point I am getting at is that the game will do a LOT of work for you. You just need to tap into the resources. And if you can make use of things like the down-state variables, you just have to find them! For SNES, the controller reading is a lot different. (*cough*) All you have to do is read a word (16-bit word!) from one of the following registers: $4218: Controller 1 $421A: Controller 2 $421C: Controller 3 $421E: Controller 4 This will give you a nice 16-bit value containing all of the controller data as follows: bitmask: abcdefghijkl0000 There it is! No need for any 1-bit (serial) reads, like you do on NES. You should still look for the joypad vars, rather than reading these registers directly, because that data is only "proper" when read during VBlank. Also, you'll get access to any down-state variables if you just set a single breakpoint and do a little looking around. (*ahem* Meaning search for the variables!) |
|||
Dish Spiny Level: 38 Posts: 328/596 EXP: 355646 For next: 14801 Since: 03-15-04 From: Disch Since last post: 18 days Last activity: 18 days |
| ||
FF1's method is actually roundabout and wasteful (AND + CMP is silly -- a simple LSR would be much easier and more effective). Something like this makes more sense to me (probably is in more games):
Originally posted by DahrkDaiz I heard from somewhere (can't remember where -- and I doubt it's accurate) that reading $4016/7 on a half strobe (writing 1 but not 0) will access the Famicom expansion port rather than joypad data. Although I find that to be rather unlikely. I'd imagine reading either reg on an incomplete strobe would just give you garbage joypad data. Other terminology I've seen thrown around is writing 1 is called "resetting the strobe", and writing 0 is called "clearing the strobe". To me this would imply that writing 1 make it so the next button read will be the A button. And that writing 0 would clear out current joy data and fetch new data from the gamepad. So I'd guess that if you did something like the following:
I'd think you'd just get the status of the A button over and over every time you read -- and it would never change (it would never refresh with whatever's currently being pressed, since you're never clearing the strobe). This is all a complete guess though -- I really don't know. edit: but, erm, yeah. As Para and others have mentioned -- you shouldnt' be doing this. If the game is already strobing and fetching joypad data (which it IS) you shouldn't - since that is unnecessary work and could even cause problems. DD already posted those offsets to where key state is stored in RAM. (edited by Disch on 04-07-05 04:10 AM) |
|||
Rockman Flurry Level: 26 Posts: 165/250 EXP: 96387 For next: 5888 Since: 03-17-04 Since last post: 18 days Last activity: 16 days |
| ||
Originally posted by BMF54123I felt a little stupid yesterday too, after I found out that it wasn't really that hard to begin with, and I can't believe that I didn't pick it up before. |
|||
Gavin Fuzzy Rhinoceruses don't play games. They fucking charge your ass. Level: 43 Posts: 614/799 EXP: 551711 For next: 13335 Since: 03-15-04 From: IL, USA Since last post: 13 hours Last activity: 13 hours |
| ||
Originally posted by Disch ah yes, correct you are. I think i remember you alerting me to this fact way back when i was messing with controller stuff and working with FF1. I had typed up that small ff1 controller workings a while ago and only changed it grammatically and organizationally really. you're method is much much better. and as an aside: i'm not saying it's best to write you're own controller handling routines for an existing game (because as everyone has pointed out, it's pointless and overly-complicated), just showing one way one game handles it, so someone might have a better understanding of it |
|||
Rockman Flurry Level: 26 Posts: 169/250 EXP: 96387 For next: 5888 Since: 03-17-04 Since last post: 18 days Last activity: 16 days |
| ||
Okay, now I'm having a little bit of trouble. I'm trying to write my own code for SMB3, so when you press the select button, it increases your lives by one. This, I'm doing for practice. What I'm doing, setting a breakpoint of read, to $18. Then, I press run to get to the section that has the NOP'd out code. That is where I'm putting my code. A5 18 29 20 F0 00 EE 36 07 Those are the bytes above. The actual code: LDA $18 AND #$20 BEQ [next line] INC $736 I looked at the RAM in the memory viewer. When you press select, the number 20 comes up. Meaning, that the number 20 means select. So, I looked at code I saw for the jump button, and I tried to write my own. But its not working correctly. Instead of select, it increase the lives by about 20 when you press the Start button. Its weird. |
|||
Dish Spiny Level: 38 Posts: 329/596 EXP: 355646 For next: 14801 Since: 03-15-04 From: Disch Since last post: 18 days Last activity: 18 days |
| ||
[edit] My previous theory seems to have been wrong -- I'm looking at the area you're talking about now it does only seem to be called once per frame. [edit again] your branch is screwey -- that might be part of your problem BEQ $00 <-- is a null branch. It will not branch anywhere regardless of the state of the Z flag (although it will burn extra cycles depending on the Z flag). If you're wanting to skip the following instruction, you'd want: BEQ $03 (skip 3 bytes -- the following INC is 3 bytes long) [edit a 3rd time] I put in your same code at the start of the NOP chunks I think you were talking about ($3CE8E in the (PRG 0) rom) -- with the corrected BEQ command. And it seems to *kind of* be working. It seems like that NOP chunk is only run when the game is paused -- so it will only add lives when you press select while the game is paused. That's how it worked for me. One life per press -- but the life count in the status bar didn't change until you unpause. (edited by Disch on 04-07-05 01:36 PM) (edited by Disch on 04-07-05 01:39 PM) (edited by Disch on 04-07-05 01:45 PM) |
|||
Rockman Flurry Level: 26 Posts: 170/250 EXP: 96387 For next: 5888 Since: 03-17-04 Since last post: 18 days Last activity: 16 days |
| ||
You were right Disch. Thanks. My Branch wasn't correct, and the code section with the NOPs was the pause screen. I noticed that in the RAM viewer, pressing the start button shows up as 10, and the code shown there was AND #$10, meaning that pressing start executed the code for the pause. So, I now know what I was doing wrong, however, even with the proper code I have, I couldn't find free space within the limits to put the code, so I had to go over the Pause routine. I'll have to figure out where to find some free space to my new code tomorrow. There is lots of free space in the ROM, but it has to be within that area, or it won't work. I have tried many times. So, I managed to do what I wanted to do, initially as practice. Press select... And Tanooki Mario you become! http://www.geocities.com/heavencloud7777/smb3.zip I even made a patch if anyone wants to try it out. Remember, until I figure out how to do it a better way, you can't pause in the game. But the ASM hack works perfectly fine. You need to right click and select save target as if you want to download it. |
|||
KP9000 Flurry Level: 27 Posts: 202/261 EXP: 102741 For next: 13418 Since: 03-18-04 From: Wherever you saw me last... Since last post: 22 days Last activity: 2 days |
| ||
I believe it needs to be within the same bank... I'm probably not correct but I know its something along those lines. I'm in the process of learning ASM right now and I'm just taking a wild shot at it. Anyways, that is looking pretty cool Rockman! You should make a tutorial on this also! |
|||
iamhiro1112 Armos Level: 35 Posts: 361/487 EXP: 259927 For next: 20009 Since: 03-27-04 From: sd Since last post: 18 days Last activity: 7 days |
| ||
Here's a question. Would it be possible to fix up the control in Super Mario World NES at all? One of the games biggest flaws is that a running jump goes the same length, height and speed as a walking jump. It kind of kills the flow of the gameplay. The run speed needs to be brought down a notch too cause you usually wind up running into enemies if you try to run. Also the cape has no float functions which it should. (edited by iamhiro1112 on 04-07-05 07:28 PM) |
|||
DahrkDaiz Red Super Koopa Acmlm's Mosts 2005 Best ROM Hacker Level: 45 Posts: 594/885 EXP: 643520 For next: 16644 Since: 03-15-04 From: K-Town Since last post: 4 hours Last activity: 4 hours |
| ||
iamhiro: your post has NOTHING to do with the topic of this conversation, and is thus, deemed off topic. Controller press routines and the physics of SMW NES have very little to do with each other. Others who frequent this forum agree that you seemed to make off topic comments and posts like this all the time. Please remain on topic or say nothing at all, you have been warned. |
|||
bbitmaster Koopa Level: 18 Posts: 75/103 EXP: 25264 For next: 4633 Since: 03-28-04 From: Knoxville, tTN Since last post: 12 days Last activity: 7 days |
| ||
Originally posted by iamhiro1112 It's been my personal experience that anytime someone asks "is x possible?," what they really want is someone to do it for them. I sure hope you aren't trying to ask someone to do such a big hack for you, because anyone with enough skill probably has their own projects to be working on. In any case, this is a very bad question to ask, anything (within reason) is possible if you have enough time and effort to put into it. Do you? If so, messing with the game in FCEUXD, and reading this thread are good starting points. All I can say is good luck! (edited by bbitmaster on 04-08-05 10:53 AM) |
|||
eb_h4x0r Micro-Goomba Level: 6 Posts: 4/12 EXP: 600 For next: 307 Since: 04-08-05 Since last post: 133 days Last activity: 24 days |
| ||
Is it possible to ASM hack other games for the controller thing? |
Pages: 1 2 | Add to favorites | "RSS" Feed | Next newer thread | Next older thread |
Acmlm's Board - I2 Archive - Rom Hacking - ASM Hacking Question - Controller Presses | | | |