shanus
Smash Hero
- Joined
- Nov 17, 2005
- Messages
- 6,055
Fighter.pac injections follow a simple protocol:
STRATEGY
Say we have an action in fighter.pac, such as taunts. Say we want to make a code for taunt canceling a la 64 where you can cancel the taunt by entering the "teeter" animation at the edge. What I want to do is the following:
-Overwrite a safe location inside of taunt action in fighter.pac with a Go to line.
-This Go to line points to a data parameter in my code whose offset points to the start of my PSA commands to inject.
-At the end of my PSA commands, I write another Go to line which points back to fighter.pac to return to the next command after what I wrote over (or commands later in the same action)
Now for the structure of fighter.pac injections:
HEADER
DATA
COMMANDS
FOOTER
The header describes where in memory you overwrite.
The data section is what the PSA commands refer to in memory.
The commands section is a sequential list, in order, which refer to the data section (IF THEY HAVE parameters).
The footer section is where you overwrite in fighter.pac with a go to line.
SECTION 1. Commands
1. In PSA, write out the code you wish to inject for ALL characters. You need to make sure this code is finalized, as writing these codes requires significant structure control and rewriting it can be a pain and time consuming.
So for taunt canceling, I want to do the following simple code.
Change Action: 7C, req=3A
Or in command language:
02010200 XXXXXXXX where XXXXXXXX will be the data section we point to in memory.
Note the number of parameters this code calls for, 2. If this number is 0, replace the X's with ALL ZEROES.
SECTION 2. DATA
Writing the data is very simple. As I described before, i wanted to write:
So we call the change action, but need the data to tell it 7C, req 3A.
The data format for each parameter is as follows:
V is the format the data takes.
0 - Value
1- Scalar
2- Pointer
3- Boolean
4 - ???
5- Variable
6- Requirement
DATADATA is the actual data you wish to write.
So for our code:
The data would be:
But, let us not forget that we also need to have data for the two "Go to" statements this code uses.
So, we neeed two data sets which are pointers such as:
That brings our total data section up to:
So now we need to begin constructing the code.
We have the following:
To keep progressing, we need to choose an area in memory to write to, and also figure out our injection point.
SECTION 3. FOOTER
Within fighter.pac, viewable through OpenSA2 [download: http://opensa.dantarion.com/wiki/Main_Page]
Step 1: Find the action of interest for your code. A very rough (some of these are wrong) list of action IDs are located here: http://www.smashboards.com/showthread.php?t=239768
Step 2: Find a safe injection point for your code. What happens is that a line in fighter.pac must be replaced with a Go To line. As such, when you are choosing your area to inject, you don't want to overwrite an Else statement and break the flow of l]ogic. It's best to overwrite something simple, especially when you are learning.
Step 3: After you know the line you wish to replace, note its "command offset" in OSA2. This is going to be the point in memory that you wish to overwrite.
Fighter.pac starts at offset: 80F9FC20 in RAM. So to find the true memory location you wish to overwrite, you ADD your command offset to 80F9FC20. A good tool to do this quickly: http://www.csgnetwork.com/hexaddsubcalc.html
So for the case of our code, I choose to inject over the very first line
07020000 of action 10C. This is a nice choice because it has no additional requirements and is not an if statement or else or anything else like that. Its command offset is 23AE0. So, doing the math on it, its true location in memory is: 80F9FC20 + 23AE0 = 80FC3700.
So because we will be replacing that line, 07020000, we need to put it back in our commands within our injection. So our injection code now looks like:
Now we have a bit more work to do. We need to put a Go to command at the end of our commands to instruct to go back to fighter.pac:
Now, here is an important stepping point. Count how many lines we have here: 7. Each line takes up 8 bytes of memory. So to calculate a byte count, take 7*8, then convert to hex. Our byte count would be 0x38.
Now, I'm going to cheat a little and show you a tip on how to save memory. In a specific portion of fighter.pac, 0xBA6C, I found a line which already has Change Action: 7C, req=3A. I can use the parameters called by that command already, and save two lines of memory! The params as listed in OSA2 are at 0xBA2C, so doing the classic math gets me the following command:
02010200 80FAB64C
So now, our code:
With a new byte count of: 0x28
SECTION 4. HEADER
So now, lets keep pressing. We need to make the HEADER, and FOOTER. So I happened to know that 9019A500 was free in memory for at least 28 bytes (I'll post free areas in memory later).
So to go to 9019A500, I use the following command:
4A000000 DDDDDDDD
16EEEEEE 000000FF
DDDDDDDD is the initial pointer. You instruct it to point to 90000000.
EEEEEE is what you add to the pointer, in this case 19A500.
FF is the byte count.
So, the result:
Now we need to add in the footer. Remember that area in memory I told you to remember where the command 07020000 was? 80FC3700.
We remove the first two numbers with a pointer to 80, 06.
The result:
06FC3700 000000FF
Where FF is the byte count of how many lines we are replacing in fighter.pac (in this case, 1, with a Go to command).
The result:
Now, lets add it all together:
So now for the part where good organization pays off. I strongly recommend you this in excel as long codes need good organization.
I did this already, so please observe:
Our first data line sits at 9019A500 which happens to be one of our go to commands parameters.
So, notice that I populated memory addresses and color coded. My Go to return in fighter.pac is where I overwrote + 8 bytes since I want to return 1 line later than I overwrote. My other go to location points to the parameter which points to the START OF THE COMMANDS.
So to make it clear, here is how this code truly works:
Taunt action is called when you press taunt.
At the beginning, instead of running 07020000, we overwrote it with the orange Go to line. This points to our parameter which says to go to the start of our commands. From there, it runs 07020000 and the change action command when near edge. Then it runs the green Go to command to return back to the line after I replaced in fighter.pac.
So now that we know how long our code will take in memory, we need to find an area which is unoccupied.
Yes, that code works for taunt cancels. However, you'll need codes to allow taunts during dashes and runs to make it behave like 64 smash. You'll need to wait for Project M for those ;-)
Free memory:
93573000 - 935E0000
STRATEGY
Say we have an action in fighter.pac, such as taunts. Say we want to make a code for taunt canceling a la 64 where you can cancel the taunt by entering the "teeter" animation at the edge. What I want to do is the following:
-Overwrite a safe location inside of taunt action in fighter.pac with a Go to line.
-This Go to line points to a data parameter in my code whose offset points to the start of my PSA commands to inject.
-At the end of my PSA commands, I write another Go to line which points back to fighter.pac to return to the next command after what I wrote over (or commands later in the same action)
Now for the structure of fighter.pac injections:
HEADER
DATA
COMMANDS
FOOTER
The header describes where in memory you overwrite.
The data section is what the PSA commands refer to in memory.
The commands section is a sequential list, in order, which refer to the data section (IF THEY HAVE parameters).
The footer section is where you overwrite in fighter.pac with a go to line.
SECTION 1. Commands
1. In PSA, write out the code you wish to inject for ALL characters. You need to make sure this code is finalized, as writing these codes requires significant structure control and rewriting it can be a pain and time consuming.
So for taunt canceling, I want to do the following simple code.
Change Action: 7C, req=3A
Or in command language:
02010200 XXXXXXXX where XXXXXXXX will be the data section we point to in memory.
Note the number of parameters this code calls for, 2. If this number is 0, replace the X's with ALL ZEROES.
SECTION 2. DATA
Writing the data is very simple. As I described before, i wanted to write:
Code:
Change Action: 7C, req=3A
The data format for each parameter is as follows:
Code:
0000000V DATADATA
0 - Value
1- Scalar
2- Pointer
3- Boolean
4 - ???
5- Variable
6- Requirement
DATADATA is the actual data you wish to write.
So for our code:
Code:
Change Action: 7C, req=3A
Code:
00000000 0000007C
00000006 0000003A
So, we neeed two data sets which are pointers such as:
Code:
00000002 YYYYYYYY
00000002 ZZZZZZZZ
Code:
00000000 0000007C
00000006 0000003A
00000002 YYYYYYYY
00000002 ZZZZZZZZ
We have the following:
Code:
---DATA---
00000000 0000007C
00000006 0000003A
00000002 YYYYYYYY
00000002 ZZZZZZZZ
---Commands---
02010200 XXXXXXXX
SECTION 3. FOOTER
Within fighter.pac, viewable through OpenSA2 [download: http://opensa.dantarion.com/wiki/Main_Page]
Step 1: Find the action of interest for your code. A very rough (some of these are wrong) list of action IDs are located here: http://www.smashboards.com/showthread.php?t=239768
Step 2: Find a safe injection point for your code. What happens is that a line in fighter.pac must be replaced with a Go To line. As such, when you are choosing your area to inject, you don't want to overwrite an Else statement and break the flow of l]ogic. It's best to overwrite something simple, especially when you are learning.
Step 3: After you know the line you wish to replace, note its "command offset" in OSA2. This is going to be the point in memory that you wish to overwrite.
Fighter.pac starts at offset: 80F9FC20 in RAM. So to find the true memory location you wish to overwrite, you ADD your command offset to 80F9FC20. A good tool to do this quickly: http://www.csgnetwork.com/hexaddsubcalc.html
So for the case of our code, I choose to inject over the very first line
07020000 of action 10C. This is a nice choice because it has no additional requirements and is not an if statement or else or anything else like that. Its command offset is 23AE0. So, doing the math on it, its true location in memory is: 80F9FC20 + 23AE0 = 80FC3700.
So because we will be replacing that line, 07020000, we need to put it back in our commands within our injection. So our injection code now looks like:
Code:
---DATA---
00000000 0000007C
00000006 0000003A
00000002 YYYYYYYY
00000002 ZZZZZZZZ
---Commands---
07020000 00000000
02010200 XXXXXXXX
Code:
00000000 0000007C
00000006 0000003A
00000002 YYYYYYYY
00000002 ZZZZZZZZ
07020000 00000000
02010200 XXXXXXXX
00090100 AAAAAAAA
Now, I'm going to cheat a little and show you a tip on how to save memory. In a specific portion of fighter.pac, 0xBA6C, I found a line which already has Change Action: 7C, req=3A. I can use the parameters called by that command already, and save two lines of memory! The params as listed in OSA2 are at 0xBA2C, so doing the classic math gets me the following command:
02010200 80FAB64C
So now, our code:
Code:
00000002 YYYYYYYY
00000002 ZZZZZZZZ
07020000 00000000
02010200 80FAB64C
00090100 AAAAAAAA
SECTION 4. HEADER
So now, lets keep pressing. We need to make the HEADER, and FOOTER. So I happened to know that 9019A500 was free in memory for at least 28 bytes (I'll post free areas in memory later).
So to go to 9019A500, I use the following command:
4A000000 DDDDDDDD
16EEEEEE 000000FF
DDDDDDDD is the initial pointer. You instruct it to point to 90000000.
EEEEEE is what you add to the pointer, in this case 19A500.
FF is the byte count.
So, the result:
Code:
4A000000 90000000
1619A500 00000028
00000002 YYYYYYYY
00000002 ZZZZZZZZ
07020000 00000000
02010200 80FAB64C
00090100 AAAAAAAA
We remove the first two numbers with a pointer to 80, 06.
The result:
06FC3700 000000FF
Where FF is the byte count of how many lines we are replacing in fighter.pac (in this case, 1, with a Go to command).
The result:
Code:
06FC3700 00000008
00090100 GGGGGGGG
Code:
4A000000 90000000
1619A500 00000028
00000002 YYYYYYYY
00000002 ZZZZZZZZ
07020000 00000000
02010200 80FAB64C
00090100 AAAAAAAA
06FC3700 00000008
00090100 GGGGGGGG
I did this already, so please observe:
Our first data line sits at 9019A500 which happens to be one of our go to commands parameters.
Code:
Taunt Canceling v2.1 [Shanus,Camelot,WindOwl]
IGNORE00 4A000000 90000000
IGNORE00 1619A500 00000028
9019A500 00000002 [COLOR="SeaGreen"]80FC3708[/COLOR] Area to return
9019A508 [COLOR="Orange"]00000002 9019A510[/COLOR] Start of code
9019A510 07020000 00000000 Line I overwrote
9019A518 02010200 80FAB64C Change Act: 7C, req=3A
9019A520 00090100 [COLOR="SeaGreen"]9019A500[/COLOR] Go to return
IGNORE00 06FC3700 00000008
IGNORE00 00090100 [COLOR="Orange"]9019A508[/COLOR] Go to start
So to make it clear, here is how this code truly works:
Taunt action is called when you press taunt.
At the beginning, instead of running 07020000, we overwrote it with the orange Go to line. This points to our parameter which says to go to the start of our commands. From there, it runs 07020000 and the change action command when near edge. Then it runs the green Go to command to return back to the line after I replaced in fighter.pac.
So now that we know how long our code will take in memory, we need to find an area which is unoccupied.
Yes, that code works for taunt cancels. However, you'll need codes to allow taunts during dashes and runs to make it behave like 64 smash. You'll need to wait for Project M for those ;-)
Free memory:
93573000 - 935E0000