Register | Login
Views: 19364387
Main | Memberlist | Active users | ACS | Commons | Calendar | Online users
Ranks | FAQ | Color Chart | Photo album | IRC Chat
11-02-05 12:59 PM
1 user currently in Rom Hacking: hukka | 2 guests
Acmlm's Board - I2 Archive - Rom Hacking - ASM Hacking Question - Controller Presses | |
Pages: 1 2Add 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
Posted on 04-07-05 03:52 AM Link | Quote
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
Posted on 04-07-05 04:14 AM Link | Quote
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
Posted on 04-07-05 05:00 AM Link | Quote
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
Posted on 04-07-05 07:10 AM Link | Quote
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.


$D7C9 A9 LDA #$01 ;directly loads the Accumulator with 1
$D7CB 8D STA $4016 ;stores the Accumulator value (1) into $4016
$D7CE A8 LDA #$00 ;directly loads the Accumulator with 0
$D7D0 8D STA $4016 ;stores the Accumulator value (0) into $4016

$D7D3 A2 LDX #$08 ;loads 8 so it can loop for each byte
$D7D5 AD LDA $4016 ;loads the info from the joystick
$D7D8 29 AND #$03
$D7DA C9 CMP #$01 ;compares to set/reset carry register
$D7DC 26 ROL $20 ;rotates info into memory...
$D7DE CA DEX ;decrements X, to load next value
$D7DF DO BNE $D7D5 ;loops again if not 0
$D7E1 60 RTS ;returns to main routine


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
Posted on 04-07-05 09:23 AM Link | Quote
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
Posted on 04-07-05 01:08 PM Link | Quote
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
Posted on 04-07-05 04:37 PM Link | Quote
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
Posted on 04-07-05 07:23 PM Link | Quote
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
Posted on 04-07-05 08:55 PM Link | Quote
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
bits:
a: B
b: Y
c: Select
d: Start
e: Up
f: Down
g: Left
h: Right
i: A
j: X
k: L
l: R


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
Posted on 04-07-05 09:07 PM Link | Quote
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):



LDX #$01
STX $4016
DEX
STX $4016 ; strobe joypad

LDX #$08
loop:

LDA $4016 ; get button state (p1)
LSR A ; move low bit to carry flag
ROR joy_data_p1 ; roll carry flag into memory

LDA $4017 ;get button state (p2)
LSR A ; move low bit to C flag
ROR joy_data_p2 ; roll C into mem

DEX
BNE loop ;loop 8 times



Originally posted by DahrkDaiz
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.


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:



LDX #$01

STX $4016
LDA $4016
STX $4016
LDA $4016



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
Posted on 04-07-05 09:27 PM Link | Quote
Originally posted by BMF54123
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.
I 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
Posted on 04-08-05 05:44 AM Link | Quote
Originally posted by Disch
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):



LDX #$01
STX $4016
DEX
STX $4016 ; strobe joypad

LDX #$08
loop:

LDA $4016 ; get button state (p1)
LSR A ; move low bit to carry flag
ROR joy_data_p1 ; roll carry flag into memory

LDA $4017 ;get button state (p2)
LSR A ; move low bit to C flag
ROR joy_data_p2 ; roll C into mem

DEX
BNE loop ;loop 8 times




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
Posted on 04-08-05 06:26 AM Link | Quote
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
Posted on 04-08-05 06:32 AM Link | Quote
[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
Posted on 04-08-05 09:37 AM Link | Quote
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
Posted on 04-08-05 11:02 AM Link | Quote
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
Posted on 04-08-05 11:58 AM Link | Quote
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
Posted on 04-09-05 03:45 AM Link | Quote
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
Posted on 04-09-05 03:48 AM Link | Quote
Originally posted by iamhiro1112
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.


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
Posted on 04-09-05 04:24 AM Link | Quote
Is it possible to ASM hack other games for the controller thing?
Pages: 1 2Add to favorites | "RSS" Feed | Next newer thread | Next older thread
Acmlm's Board - I2 Archive - Rom Hacking - ASM Hacking Question - Controller Presses | |


ABII


AcmlmBoard vl.ol (11-01-05)
© 2000-2005 Acmlm, Emuz, et al



Page rendered in 0.020 seconds.