• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Purin Bow Color Engine

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
Doq, have you gone mad?

Yes... yes I have. I am attempting to manipulate a texture entirely in code.
The finished product will use the L button (which standalone will be incompatible with 20XX HP, unless achilles implements it into 4.0... nudge nudge wink wink) to scroll through colors. I'll likely include only 7 or so, but it can be expanded however far the memory goes.

But first, a comparison of textures:
Recompiled Blue Bow Texture using Melee Toolkit
00 1F 00 00 00 00 00 00 00 00 FF FF FF FF FF FF
00 00 FF FF FF FF FF FF 00 00 FF FF FF FF FF FF
9C F3 31 86 5A FA E0 E0 AD 75 31 A6 D5 F5 2F 09
9D 14 10 82 E0 FA 57 55 84 30 08 41 03 AD F5 D5

Red Bow from the Purin Bow Pack Redux, same offset
F8 02 00 00 00 00 00 00 00 00 FF FF FF FF FF FF
00 00 FF FF FF FF FF FF 00 00 FF FF FF FF FF FF
9C F3 31 86 5A FA E0 E0 AD 75 31 A6 D5 F5 2F 09
9D 14 10 82 E0 FA 57 55 84 30 08 41 03 AD F5 D5

Green Bow from the Purin Bow Pack Redux, same offset
07 C1 00 00 00 00 00 00 00 00 FF FF FF FF FF FF
00 00 FF FF FF FF FF FF 00 00 FF FF FF FF FF FF
9C F3 31 86 5A FA E0 E0 AD 75 31 A6 D5 F5 2F 09
9D 14 10 82 E0 FA 57 55 84 30 08 41 03 AD F5 D5

Look at the above results. Only the first two bytes are different, the other 62 bytes are exactly the same, which means that I only need to change two bytes to change the bow color now! BREAKTHROUGHS! Below here is a list of hex values for the colors in the Purin Bow Pack Redux:
vMelee Blue: 00 1F
Lime Green: A7 C0
Indigo: 38 1F
Hot Pink: F8 11
Green: 07 C1
Green Yellow: DF C0
Green Blue: 07 D6
Gold: FC E0
Dark Orange: F9 40
Redux Blue: 05 DF
Black: FF FF* / 00 00
Yellow: FE C0
White: FF FF
Violet: 70 1F
Sky Green Blue **** (that is the name in the pack, yes): 07 D7
Red: F8 02
Purple: A8 1F
Pink: F8 18
Orange: FB 00
Light Green: 6F C0
Light Blue: 07 DE
Or make your own color: http://reactiveraven.github.io/565/
* Black has a non-unique code because bytes 0x4-0x7 are 55 55 55 55. Setting the code to 00 00 in memory is also black.

It's basically your average 16 bit color.
Original Blue Bow, found at the offset 0x0003e2e0 in PlPrBu.dat
00 1F 08 1F 00 00 00 00 09 02 78 00 5F E0 4A C5
09 02 78 00 5F E0 4A C5 00 6D 27 A0 45 55 56 EA
9C F3 31 86 5A FA E0 E0 AD 75 31 A6 D5 F5 2F 09
9D 14 10 82 E0 FA 57 55 84 30 08 41 03 AD F5 D5

Recompiled Blue Bow Texture using DRGN's PNG to TPL (Texture ripped using Melee Toolkit)
00 20 AF 30 00 00 00 01 00 00 00 0C 00 00 00 14
00 00 00 00 00 04 00 04 00 00 00 0E 00 00 00 40
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 1F 00 1E 55 55 55 55 00 1F 00 1E 55 55 55 55
00 1F 00 1E 55 55 55 55 00 1F 00 1E 55 55 55 55

Recompiled Blue Bow Texture using DRGN's PNG to TPL (Texture converted to PNG from Steelia's PrBu.rar)
00 20 AF 30 00 00 00 01 00 00 00 0C 00 00 00 14
00 00 00 00 00 04 00 04 00 00 00 0E 00 00 00 40
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 1F 00 1E 00 00 00 00 00 1F 00 1E 00 00 00 00
00 1F 00 1E 00 00 00 00 00 1F 00 1E 00 00 00 00
So, depending on the compiler, the output is different. Except for the TPL outputs (96 bytes), the textures are 64 bytes in size.
> I do not know why the TPL outputs are 96 bytes large, likely for headers/footers, etc.
Now how to implement this into code...

I apologize beforehand if this looks more like an infodump than a code, it'll get better as I progress.

Well let's take a look at this guide written by _glook.
Ohph, it's only documented the PSA files. TODO: FIND PLACE IN RAM WHERE THE MODELS ARE

How the end result should look
Should probably store a color values in RAM somewhere, or in the DOL for loading later, or better: in PlPrBu.dat.
> Actually if the color information is stored in PlPrBu.dat, then it would be simply easier to make a fancy PlPrBu.dat with the other colors appended to the end, and change the texture pointer to the specified color pointer.

Code outline (I'm not entirely sure how the current alternate costume engine is laid out, and it's likely cleaner/different from this outlike)
CSS:
It'll likely be similar to the Alternate Costume engine, but instead of loading a different file name, it'll store a color value at a spot in RAM.
INIT:
Check for game load code (Injection point)
Check for players' characters selection (all of them)
if any player is loading PlPrBu.dat
run offset load code​
else end​
LOAD:
Save pointer in r31 to RAM (Will need to find a good address) [Alternately, find where these pointers are in RAM already]
Check RAM pointer
If word at +0x3e2e0 from pointer is 001F0000
Check CSS selection choice
Inject new RAM value at pointer
run load code normally​
else
run load code normally​

Check for player character selection
if player X is purin
if costume is blue
allow color scroll using R​
else
don't do anything​
else
don't do anything​
end

Check for loading cycle outlined in _glook's guide
if player X is purin
if costume is blue
check current color value
modify texture pointer for that color​
else
don't do anything​
else
don't do anything​
end

* I am p sure I can meld these two ifs by simply putting "if player X is loading plprbu.dat"


This is all I know until I get the above TODO offset.
TO THE LAB
 
Last edited:

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
Crown plz :b:
Soon. Very soon.

Although I've already made progress. If anybody needs an explanation, let me know. It's in the OP though.

I could use some assistance with core Gecko ASM though (like how to hook into a function)
Halp me Melee Coding Gods. :confused:
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
http://geckocodes.org/index.php?arsenal=1

Essentially, with C2s, you pick an address within the function to overwrite (the func to start a match is @ 8016E730).

Example:
Code:
C216E730 00000002 # Gecko will place a branch from the address you've chosen to the Gecko region. The NNNNNNNN is how many lines of code you'll have.
111111111 11111111 #This is the ASM function you're inserting
222222222 00000000 #This is the original ASM function from 8016E730 followed by a 00000000 (which is replaced by Gecko automatically with a branch back to the function @ 8016E734)
80031AD0 (SetupPlayer (int slot)) is called by StartMelee for each player slot to determine what to load. r3, I believe, is the player slot index.

The function calls 80068E98, which allocates the region for a given player pointer and initializes it. The costume data and such would either be here or in the previous function. If Ice Climbers is chosen, the function will be called again for Nana.

Edit:
Wait, I was thinking of an alternate costume type code. You could probably search for that ".dat" name in memory and find where it's stored, then search for that byte range. Then just modify it with some 04s. I just couldn't tell you where it is, but for Jigglypuff you'd check for the character ID in either Allocate or in SetupPlayer, one of the function's locals (registers) should be 0F for Jigglypuff.
 
Last edited:

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
I figured it out. The only real thing on hold is the CSP background colors (which haven't been posted anywhere, I searched multiple times)

There are a few core hurdles with the PBCE though:
  • Characters are loaded dynamically into RAM, and after every match they are moved.
  • Unlike the Alternate Costume Engine, which injects a new filename to load; the PBCE requires that the file be loaded before modifying it, which kinda sucks because of the above, meaning now I have to find which function actually loads files, and grab a RAM location to where the file (in this case and throughout the PBCE: PlPrBu.dat) is placed.
  • Throughout this entire project I am using a modified PlPrBu.dat file, so this will never actually work with pure vMelee.
  • This is my first code, so anything that isn't documented in the Workshop already I don't know.
To be honest, I could search the entire RAM block where the character data is stored for 001F0000, but that would be ineffective.

On an unrelated note, the Bow color can be changed in a match. (Stock Dependent Purin Bow Colors???, Rain-Bow?)
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
You would search for more than those bytes if you need it. You'd want to check for the largest number to make it as unique as possible, so even the surrounding bytes.

Given that the region for character data probably stays the same, you could also breakpoint that memory location and view the callstack.
 
Last edited:

CeLL

Smash Lord
Joined
Jan 26, 2014
Messages
1,026
Location
Washington
Actually character file patching has been accomplished by @Glook. You could use his codes and variably patch the file for the texture.
 

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
You would search for more than those bytes if you need it. You'd want to check for the largest number to make it as unique as possible, so even the surrounding bytes.

Given that the region for character data probably stays the same, you could also breakpoint that memory location and view the callstack.
lol no
The character data location changes after every match (likely because it's reloaded, dunno why). Which is why my plan is to hook into the function that loads files and grab the address there; which is what I've done, albeit very poorly and should probably find a better way. Also causes black screens on startup.
Actually character file patching has been accomplished by @Glook. You could use his codes and variably patch the file for the texture.
Did you mean: @ _glook _glook
Yes I'm actually using his process to gather file information, but unlike the character moveset data (which he said is static but variable), there is no static on the model files, which leads me to think that either:
A: After matches, character files are reloaded at random, which means Blue Bow Purin might not be loaded first, despite it being loaded first on the CSS before.
or B: ... well actually there is no B. I would have to find a proper place to find the RAM offset regardless.

Right now it's laid out like this:
asm inject on loading function (the second instruction with the magic RAM value)
store this value at a place in RAM
check this RAM value with the loaded data
if it is PlPrBu.dat (we'd know by checking 0x3e2e0 from the magic address for 001F0000) we then store that address (the modified one) into another place in RAM (around the same place)
And since it's already loaded to RAM, we can straight modify it now OR modify it before the game starts.
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
I meant that there's a static region where that data is loaded, even of it's not the same ordering. That's exactly how character in - match data works AFAIK with a function that grabs each pointer. Software doesn't usually change pointers until it's recompiled, it may just change ordering of data in-memory.

At the very least, you can find the region, then use the call stack to see what cleans it since the destructor is likely called by the function that uses malloc or something nearby.
 

_glook

Got a Passion for Smashin'
Joined
Sep 30, 2005
Messages
802
Location
Not UC Berkeley anymore
Code:
At instruction 80018104:
0x4(r30) = 02000301 for Jiggly's PlPr.dat file?
0x4(r30) = 01000303 for Jiggly's PlPrBu.dat file?
r4 = location in RAM where the file is stored
I did a breakpoint on 80018104. If 0x4(r30) is 01000303, r4 is the location of PlPrBu.dat in RAM. There should be 001F081F at offset 0x0003e2e0 from there. When I replace it with f802081f, it gives me a red bow instead of a blue one. This was done in Dolphin using the Memory viewer.

It should be noted that the costume file seems to be reloaded each time, even if you haven't change costumes or characters (the next match gave me a blue bow). This seems to go along with your findings that the location in memory constantly changes.
 
Last edited:

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
Code:
At instruction 80018104:
0x4(r30) = 02000301 for Jiggly's PlPr.dat file?
0x4(r30) = 01000303 for Jiggly's PlPrBu.dat file?
r4 = location in RAM where the file is stored
I did a breakpoint on 80018104. If 0x4(r30) is 01000303, r4 is the location of PlPrBu.dat in RAM. There should be 001F081F at offset 0x0003e2e0 from there. When I replace it with f802081f, it gives me a red bow instead of a blue one. This was done in Dolphin using the Memory viewer.

It should be noted that the costume file seems to be reloaded each time, even if you haven't change costumes or characters (the next match gave me a blue bow). This seems to go along with your findings that the location in memory constantly changes.
What is instruction 80018104 anyway?
Does this mean that I have the wrong offset? My state save has PrBu at logical location 811cffc0.

It also seems you use vanilla bow and not the modified one, does that mean the other values are irrelevant?
 
Last edited:

_glook

Got a Passion for Smashin'
Joined
Sep 30, 2005
Messages
802
Location
Not UC Berkeley anymore
What is instruction 80018104 anyway?
Does this mean that I have the wrong offset? My state save has PrBu at logical location 811cffc0.

It also seems you use vanilla bow and not the modified one, does that mean the other values are irrelevant?
In v1.02, instruction 80018104 has bytes 80 BE 00 0C for me. This translates to lwz r5, 0xC(r30). This is right before the function call bl sub_80016A54, which from what I can gather either sets up the character data for gameplay or sets up some structures to be read later to set up the character data for gameplay. At this point, r30 contains data about the file that's about to be read. 0x4 of r30 is unique for each file, and can be used as an identifier. r4 at this point points to the Pl*.dat file. If 0x4(r30) is 0x01000303, it should be reading PlPrBu.dat. r4 therefore points to where PlPrBu.dat is stored in RAM. My PlPrBu.dat is unmodified, so at the address pointed by r4, it shows 0003F183, which is the first word in PlPrBu.dat. If you go to r4 + 0x0003e2e0, it should take you to the spot where the ribbon data is. Mine PlPrBu.dat is unmodified, so it has 0x001F081F at that location. I use dolphin to set that to 0xf802081f. Then I clear the breakpoint and continue the game, and Jigglypuff loads up with a red ribbon.

Instruction 80018104 is useful because it happens after you select a stage but before the actual match starts. It is called once per player slot per character file (example: if you have P2 Jiggly Crown, P3 Jiggly Bow, and P4 Kirby normal, it 80018104 is hit in order PlPr.dat, PlPrYe.dat (crown costume), PlPr.dat (again), PlPrBu.dat (blue bow), PlKb.dat, PlKbNr.dat (neutral Kirby), PlKbPr.dat (Kirby's Jigglypuff Cap). When it is hit for PlPrBu.dat, 0x4(r30) contains the value 0x01000303. r4 then points to the start location of PlPrBu.dat in memory, and you just have to add 0x0003e2e0 to get to the bow color.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Great info by Glook.

So what you want to do now, Doq, is at that injection point, have it load the flag that represents the color number.

Store all your colors back to back in a table at some free location in the RAM. So in your list from above, it will be something like:

001FA7C0 381FF811 07C1DFC0 etc...

Each color is two bytes long, so take your color flag and multiply by 0x2. Load the start of the table into a register and then add the result from the color flag multiplied by two. You will now be at the start of the color data you need, so then load the halfword at that address (lhz instruction).

Then do what Glook says to get to the start of the ribbon data and store the halfword. (sth instruction). Doneski.
 

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Also, this is...maybe old and slightly outdated...but this is what was give to me by Sham Rock a long time ago to switch the colors of the CSP background. [just a portion of code that you would want to run at the CSS in conjunction with something else].

Code:
# inputs:
# r17 = player counter (P1 = 1, P2 = 2, etc.)
# this was used in a function that loops through every player, checking button inputs, etc.

#set r22 = RRGGBB00 = CSP background
#set r23 = RRGGBB00 = CSP little trim line


COLOR:
lis r16,0x804c
cmpwi r17,1
bne- 0x08
ori r16,r16,0x24ec
cmpwi r17,2
bne- 0x08
ori r16,r16,0x2458
cmpwi r17,3
bne- 0x08
ori r16,r16,0x2558
cmpwi r17,4
bne- 0x08
ori r16,r16,0x24c4
cmpwi r17,2
bgt- 0x08
lwz r16,0(r16)
lwz r16,0(r16)
lwz r16,0(r16)
lwz r16,8(r16)
lwz r16,24(r16)
lwz r16,8(r16)
lwz r16,28(r16)
lwz r16,4(r16)
lwz r16,8(r16)
stw r22,0(r16) 
stw r23,4(r16) 
b CHECK_TO_END_LOOP_OR_KEEP_GOING
 

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
I still don't think I'm understanding this right:

There is no 01000303 at r30 at all. And I know that's the correct one because savestates and 811cffc0 is the RAM address for that state for PlPrBu.dat.

Is it because Dolphin 3? Don't tell me it is.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
I still don't think I'm understanding this right:

There is no 01000303 at r30 at all. And I know that's the correct one because savestates and 811cffc0 is the RAM address for that state for PlPrBu.dat.

Is it because Dolphin 3? Don't tell me it is.
Take that value in r30, add 4 to it, then go to that address in the memory viewer.
 

_glook

Got a Passion for Smashin'
Joined
Sep 30, 2005
Messages
802
Location
Not UC Berkeley anymore
I still don't think I'm understanding this right:

There is no 01000303 at r30 at all. And I know that's the correct one because savestates and 811cffc0 is the RAM address for that state for PlPrBu.dat.

Is it because Dolphin 3? Don't tell me it is.
0x4(r30) contains the value 0x01000303. So according to the screenshot above, the value at address 0x804321D0 would contain 0x01000303.
In PowerPC Assembly, load and store memory functions often have the format "lwz[/stw/lba/etc] rD, 0x[offset](rS)". rS is the source register. So when I say 0x4(r30), what I'm saying is "take the value in general register 30, add 0x4 to it, then retrieve the value at the place pointed to by the resulting address".

Edit: What achilles said.
 
Last edited:

_glook

Got a Passion for Smashin'
Joined
Sep 30, 2005
Messages
802
Location
Not UC Berkeley anymore
Here's a coding example:

Gecko hook function at 80018104:
Code:
lis r12, 0x0100
ori r12, r12, 0x0303 # r12 = file ID for PlPrBu.dat
lwz r11, 0x4(r30) #  r11 = file ID for currently read file
cmpw r12, r11 # See if they're the same
bne END # If not equal, skip to the end
lis r12, 0x0003
ori r12, r12, 0xe2e0 # 0x0003e2e0, which is the offset to the bow color
add r12, r12, r4 # Add the offset with the address of file in RAM
ori r11, 0, 0xf802 # The color red for the ribbon [REPLACE THIS WITH YOUR CODE]
sth r11, 0(r12) # Store the color into the file area
END:
lwz r5, 0xC(r30)  # Do what it did before
I haven't tested this code, but this is basically what you want to do.

Edit: Saw your edit. Hehe, I see. Okey doke.
 
Last edited:

Doq

Smash Lord
Joined
Dec 28, 2012
Messages
1,037
Location
The Lab, Sweet Home, OR
So I am redesigning how I'm tackling the injection process of the Bow. It's a bit more complex, but it'll allow more customization. Bare with me here.

Here is the vMelee bow color, PBCE White, PBCE Black, PBCE Red, and PBCE Green
0 0 1 F
F F F F
0 0 0 0
F 8 0 2
0 7 C 1

Now I'm going to explain every byte as best I can, with screenshots too. I will be referring to each byte with the value it has in the PBCE Red color (can't use vMelee as there's two "0" values).

Control value: Black Bow [ 0 0 0 0 ]

The F byte controls the Red accent. This value can be anywhere between 0 and F and the color is different between 0 and F. The higher this value, the greater the Red accent is.
Values: 3 (~25%), 7 (50%), B (75%), F (100%)
The 8 byte controls the Green accent. This value can be anywhere between 0 and 7, 8 through F are copies of 0 through 7. The higher this value, the greater the Green accent is.
Values: 1/9 (~25%), 3/B (50%), 5/D (75%), 7/F (100%)
The 2 byte controls the Blue accent. This value can be anywhere between 0 and F and the color is different between 0 and F. The higher this value, the greater the Blue accent is.
Values: 3 (~25%), 7 (50%), B (75%), F (100%)
What gives? Blue is significantly darker than Red even at F even though they're modified similarly? No. Here's why.
The 0 byte is what I call the "Blue-Green Modifier". This value can be any odd number between 1 and F, however the difference is nonexistant in Blue and negligible in Green.
Values: F (Green 7), F (Blue F)
So what does this mean, Doq? It means I can not only modify the Bow color, but even give an extent of customization to it too! Here's how I thought about it:
We using the D-pad for this. This will also break compatibility with 20XX but that didn't matter much anyway.
D-pad left controls Red. Red will increase in increments of 2 starting from 1, and returning to 1 after F.
D-pad down controls Green. Green will increase in increments of 1 starting from 0. It doesn't matter where it returns to because 8-F are copies of 0-7.
D-pad right controls Blue. Blue will increase in increments of 2 starting from 1, and returning to 1 after F.
Left trigger controls the Blue-Green Modifier. Modifier will either be 0 or F, no in between.

If this actually works then not only have I successfully changed a texture in code but I will have provided the first in-game customizable costume.

Here's to customization! And Melee Modding! But mostly customization!
-----
Some extra technical details:
The 565 format is based on how many bits each color posesses (16-bits)
Here is the bit layout of each value in the PBCE Red Bow, with color values overlaying each bit:
1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0
1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0
Meaning...
31 red (max), 0 green, 2 blue
The reason why the Blue-Green Modifier exists is because that value there is actually part of both Green and Blue. That's also why there's a negligible difference when the value is for Green, but a lot of difference for Blue.
Take the color 07 D7 (Sky Blue Green ****). It's bitwise is:
0 0 0 0 0 1 1 1 1 1 0 1 0 1 1 1
0 0 0 0 0 1 1 1 1 1 0 1 0 1 1 1
0 red, 62 green, 23 blue
It makes heavy use of the Blue-Green Modifier to achieve it's specific color.
 
Last edited:
Top Bottom