Users browsing this thread: 1 Guest(s)
Spell Graphics Document

#11
Posts: 3,966
Threads: 279
Thanks Received: 233
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
I will quote myself and answer my own question since it was left in the mist...

(01-20-2013, 01:48 PM)Ⓐ Mᴀᴅsɪᴜʀ Ⓐ Wrote: Zeemis, is your first post an accurate translation of the japanese web page ?

No. Zeemis is still looking for an accurate translation: http://pastebin.com/j38anPEV

Therefore, we cannot rely 100% on the google translation, although it gives us a good idea.
  Find
Quote  

#12
Posts: 1,261
Threads: 250
Thanks Received: 11
Thanks Given: 7
Joined: Jun 2009
Status
Traitor
This document was translated by a member of Rom Hacking.net who does a lot of fan translations by request.
  Find
Quote  

#13
Posts: 3,966
Threads: 279
Thanks Received: 233
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
For those interested, LightPhoenix documented the control code of the animations :D (see this thread)

So this is the code for 00C1, which is the Fire animation:

40 00 Animation Speed
90 00 Clear Sprite Flag #40, Set XX
EB 58 5D 5E 5D 65 5D Branch Based On Subsprite Number
C9 00 Play Sound
80 3B Subcommand 3B (Show Target Mask)
83 99 Move Sprite
8B 04 While Loop XX Times
00 Next frame?
80 3C Subcommand 3C (Clear Target Mask)
8C Iterate While Loop
FF End Animation
83 79 Move Sprite
8B 04 While Loop XX Times
00 Next frame?
8C Iterate While Loop
FF End Animation

Running through it with brief notes:
1) First two bytes are animation speed and an unknown byte, higher is slower
2) 90: Handles setting bits #10 and #20 of 6F86,X. Bit #20 controls transparency effect; clear means on, set means off)
3) EB: Jumps forward based on which subsprite we're on; Fire has three, so three branches
4) C9: Play sound; I believe 00 tells it to use the default
5) 80: Runs a subcommand based on the parameter. 3B masks the target with the spell palette.
6) 83: Moves the spell sprite; #1F is the amount, #E0 is the direction
7) 8B/8C: Does a while loop - loops over the code xx times. 89/8A is the for loop version. The difference is that the for loop counts what loop we're on, the while loop does not.
8) 00: Not sure; numbers less than #80, like in FF5, seem to indicate frames to display. I think 00 is short hand for "next frame." However, it could just be a way of pausing with a while loop.
9) 80 3C: clears the target mask.
10) FF: Signals the end of the animation
  Find
Quote  
[-] The following 1 user says Thank You to madsiur for this post:
  • SSJ Rick (06-22-2015)

#14
Posts: 48
Threads: 10
Thanks Received: 3
Thanks Given: 4
Joined: May 2015
Reputation: 2
Status
None
I think the magic graphics data starting offset listed here (0x107F8F) is wrong. It seems to be 0x107FB2 (0x1081B2 in a headered rom). Might be a difference between the Japanese and English rom because all the other offsets are correct.

Okay, I'm working on dissecting the control code and starting to wrap my head around it, but running into a big roadblock with the 'eb' command (brand based on subsprite number). I get how it works, but I can't find any indication in the spell's data as to how many subsprites an effect has.

You can tell by looking for an 'eb' command in the code and reading along until it looks like you'v gotten to another command (fire has 3, pearl has 3, drain has 6, bio has 4), but that's not a useable way of doing things.

The good news is that for the most part though, this code seems pretty easy. I'll crack it, but if someone has any information about subsprite count that's help me out a lot.
  Find
Quote  

#15
Posts: 178
Threads: 2
Thanks Received: 23
Thanks Given: 4
Joined: Apr 2015
Reputation: 18
Status
None
(09-11-2015, 07:22 PM)sleepydude Wrote: The good news is that for the most part though, this code seems pretty easy. I'll crack it, but if someone has any information about subsprite count that's help me out a lot.

I think what you're looking for is hidden in "byte 10" of the spell animation data. That value gets used to jump to an initialization subroutine at the beginning of the animation. Here's the code for the jump table:

Code:
C2/E8D0: 29 7F        AND #$7F
C2/E8D2: 0A           ASL
C2/E8D3: AA           TAX
C2/E8D4: FC D8 E8     JSR ($E8D8,X)
C2/E8D7: 6B           RTL

; battle animation init function jump table
C2/E8D8:              .DW $F836, $F820, $F82B, $F7EF, $F436, $F812, $F305, $F820
C2/E8E8:              .DW $F2BF, $F49C, $F489, $F809, $F46B, $E9D6, $F7C7, $F741
C2/E8F8:              .DW $F809, $F6ED, $F4CA, $F7A1, $F630, $F58D, $F763, $F6D5
C2/E908:              .DW $F6A4, $F77D, $F418, $F839, $F63E, $F8CA, $F392, $F35D
C2/E918:              .DW $F3B5, $F60D, $F5C1, $F5A1, $F2B9, $F6C4, $F83C, $F847
C2/E928:              .DW $F65B, $F351, $F3E9, $F795, $F3D9, $F59E, $F5F8, $F5D2
C2/E938:              .DW $F5A4, $F3FB, $F299, $F289, $F27B, $F25D, $F241, $F231
C2/E948:              .DW $F221, $F211, $F1FA, $F195, $F16B, $F14D, $F129, $F119
C2/E958:              .DW $F109, $F0F9, $F0DD, $F0C1, $F08E, $F070, $F020, $F00F
C2/E968:              .DW $EFFE, $EFE3, $EFD2, $EF7B, $EF67, $EF59, $EF4B, $EF48
C2/E978:              .DW $EF1F, $EF1C, $EF0A, $EEF6, $EEDE, $EEBD, $EEAC, $EEA7
C2/E988:              .DW $EE99, $EE30, $EE8D, $EE76, $EE0C, $EDFD, $EDF5, $EDAC
C2/E998:              .DW $EDA3, $ED8E, $ED6E, $ECF6, $ED62, $EC52, $EC4B, $EC43
C2/E9A8:              .DW $EC36, $EC29, $EC1C, $EBFE, $EBEE, $EBE1, $EBC2, $EBBC
C2/E9B8:              .DW $EB97, $EB91, $EB2C, $EB87, $EB4F, $EB35, $EB1D, $EACB
C2/E9C8:              .DW $EABD, $EAA7, $EA88, $EA71, $EA65, $EA43, $E9D7

Some of these subroutines set the number of subsprites (among other things). Here's an example of the one used by the Fire spell (byte 10 = $25):

Code:
; $25: Fire, Bio, Sonic Boom, Plasma, Blaze, Shimsham, Sonic Boom, Plasma, Blaze, Shimsham

C2/F6C4: 20 3F FA     JSR $FA3F       ; set color add/sub data (add bg1 and bg2, affect sprites)
C2/F6C7: A9 08        LDA #$08        ; 8 frame delay between subsprites
C2/F6C9: 85 26        STA $26
C2/F6CB: A9 02        LDA #$02        ; make 2 copies
C2/F6CD: 20 F8 F4     JSR $F4F8       ; duplicate sprite
C2/F6D0: A9 03        LDA #$03
C2/F6D2: 4C E6 F6     JMP $F6E6       ; set number of subsprites to 3
  Find
Quote  

#16
Posts: 48
Threads: 10
Thanks Received: 3
Thanks Given: 4
Joined: May 2015
Reputation: 2
Status
None
Awesome information, also stops me beating my head against the wall trying to figure out how the shape of masking windows is set, since it's in the Byte 10 subroutines (if anyone wants to change the shape of Ultima it's C2F2AC).

That's one step closer to emulating / editing spells :0
  Find
Quote  

#17
Posts: 732
Threads: 36
Thanks Received: 12
Thanks Given: 41
Joined: Jan 2016
Reputation: 6
Status
None
So, for my romhack, I had to dive deep into the world of custom animations. Like, all the way. And that meant a lot of time staring at this thread in confusion. I'm gonna try to explain in my own words what I did to pull off my lone custom attack graphic. Hopefully this can help other people make more sense of this and custom graphics can be a more viable option for modders.

Code:
0x107F8F: Magic graphic data
14 bytes per spell

This is simply the spell animation data you'd change in FF3usME, so if you want to modify that stuff in the hex editor without opening usME, there you are.

What we need for custom animations is the number for the spell animation, which you can get from either usME or the D0 animation script doc. Get that number, multiply it by six, and that's the offset in D4/D bank. For example, I was modifying Rippler:

Code:
Rippler = $0192

$192 x 6 = $96C

Rippler offset is D4/D96C

In this bank are all the attack animations, and at that offset for Rippler there are six bytes.


Code:
05 F4 B3 07 01 01

Byte 1 - Number of animation frames (range from 00-3F)
Byte 2 - Graphic set to use
Byte 3&4 - Graphic mold to use
Byte 5 - Width
Byte 6 - Height

So here's where my struggles began - contrary to what OP said, I found that changing Byte 1, or Byte 5 or 6, had little or no effect on my new attack. That being said, my animation is a single frame. 

To see if the problem was OP's documentation or my methodology, I tried modifying Fire by changing these Bytes - changing Byte 1, Fire had the same animation script in terms of how the graphic moved, but only the first frame of Fire as shown in the OP displayed. Changing the width and height did not affect the graphic itself, but it did affect Fire's alignment when it displayed. 

So, I think that Width and Height do NOT refer to the animation itself, but the animation's position relative to the rest of the screen. I say I think because changing those values on my graphic had no effect whatsoever. It may be that they're only applicable for graphics with more than one frame, or depending on the animation script, I don't know.

Anyway, if you just want to change a spell's graphics to another spell, like saying, if you want to turn Rippler into a new attack that uses the Missile graphic, find the D4/D offset for Missile and copy those six bytes over Rippler. Voila, Rippler's graphics are changed to Missile. You'll still have to actually edit the animation script in D0 bank, as-is now you just have Rippler's animation but instead of the orbs that spin around Strago, it's the Missile graphic.

For fully custom graphics...ugh. That's where it gets "fun".

Now, the OP says that the method for effect 3 is different in terms of the offsets used and how you get to them. I did not do anything with effect 3 graphics, so I can't help there, but it seems similar to the effect 1 and 2 methods, just with different numbers. Anyway, the second byte in the six-byte string we got is what determines the actual graphic being loaded, so you can change that get your graphic loaded. How that byte loads the spell graphics, I don't know. Rippler's graphics are located at approximately D4/7D60 if you open a rom in yy-chr, but I can't see any obvious way the game loads data from that address. But, if you're editing a pre-existing graphic into something new, you can of course use the same offset and it'll load, though you may have to increase or decrease the digit a little depending on the exact location.

Take the second byte from your six-character string and multiply it by $40 to get an offset in D2 bank. There you'll find a string equal to the length of your byte 1 times 2, because each byte is 2 digits. Again using Rippler as an example:
Code:
$F4 x $40 = 3D00

Rippler graphic offset is D2/3D00.

As OP says, there will be two-byte pairs here that are essentially pointers to load your graphic. The game draws graphics in 2x2 squares each 8x8 pixels large (if you're using yy-chr, this can make visualization easier for you since it edits in the same). And this is where you'll have to play around a bit and use trial and error to figure out how to load the graphic you want, because it is not obvious and again, there's not a direct correlation as I can tell between the address of the graphics in the rom and the bytes used here to load them. But if you play around, you'll get what you want.

What I CAN tell you to help you is that the second byte in each pair, the first digit can be used to flip/rotate the 2x2 square. It seems to be even numbers that do this, odd numbers glitch up, but it's like every other even number - 2F and 4F seem to have the same effect, for example, while 6F and 8F have a different effect that they share. There may indeed be a difference, more testing would need to be done. Anyway, here you can build out your graphic in those 2x2 chunks.
Next comes the graphic mold - just like enemy sprites in battle formations, graphic data needs the proper mold or it won't display right. For that we look to bytes 3&4, which for Rippler is B3 07. That's the hex value offset so flip them as you do, and we get $7B3. Multiply that by 2.

NOW, here's where OP may be wrong - they say to add 14DF36 to the result to get the offsets of the pointers. This seems to be wrong - I believe you want to add 14DF3C to the result. But I may be wrong here too, if you've made it this far I'm sure you understand this is confusing. Play around with the data here and see how it affects the spell you're editing. Anyway, wherever you end up, if you're in the spot you should be, there will be more two-byte pairs, which are pointers to molds for the graphic. For Rippler, this is either D4/EE9C or D4/EEA2, depending on if OP or I are right.

However long the first byte was in the six-byte string we originally got, that's how many pairs you're looking for here. ie, 14 in byte 1, you want 14 pair. Each pair is a pointer to a spot in the D1 bank for the animation mold, so reverse them and away we go.
Code:
D4/EE9C: E7 A2 EB A2 ED A2 F1 A2 BF 0D

D1/A2E7 is our first destination, followed by D1/A2EB, etc. AGAIN, OP or I may be wrong about the addresses for the pointers and thus where exactly in D1 you want to begin, but again, play with stuff and you'll find something that breaks your spell, which is how I found my way around. This is why you keep backups!

In the D1 bank are yet-more two byte pairs that position each chunk of your graphic on the screen. This is complicated to explain (lolrly) but if you go to existing spell effects, you'll quickly see a pattern emerge: "WW ZZ", "XX YY", where XX is one higher than WW and YY is probably one off from ZZ, possibly with a C to flip it. The XXnumber is the position of the chunk of graphic, the YY number is an off-set of some kind. Draw out the pattern for your graphic, end the script with FF FF, and test it out.

If you want a spell to be larger than it is in the vanilla, it seems to be as simple as adding more byte pairs; I was creating a duplicate of Scar Beam that was the length of the screen, and Scar Beam's pattern went down on an angle: "82, 92, A2 / 93, A3, B3 / A4, B4, C4", etc (not exactly but you get the idea). To make the beam longer, I just kept going; B5, C5, D5, etc. Further, while they're mostly in order it doesn't seem like they need to be, which makes sense: if graphic data is being assigned to A4, the code probably doesn't care if the command is before 82 or after 94 or whatever. But again, I may be wrong.
----------------------
I'm sorry I can't be as thorough and insightful as preferred, at times I barely understood what I was doing myself, but in the end, I was able to copy Scar Beam's graphics into Rippler's place and duplicate Scar Beam animation but with a longer, thinner beam, by more or less following the OP and figuring out the methods I've described. The only other advice I can give is that when in doubt, play with shit until something breaks - as I've said before, OP seems to be wrong in some places and I may be as well, so if you can't find your string of bytes that are your graphic mold pointers, just copy/back-up the area, start blanking out lines, and try out your graphic until it glitches up, then you can narrow it down some.

So, there you are - how to make entirely new graphics for spells. It ain't clean, it ain't easy, but it can be done. I eventually stumbled my way to success, and if I can manage, anyone can.
[Image: o4BfFG7.png]
  Find
Quote  
[-] The following 4 users say Thank You to DrakeyC for this post:
  • C-Dude (10-27-2022), Everything (10-27-2022), Gi Nattak (10-28-2022), Warrax (10-29-2022)

#18
Posts: 178
Threads: 2
Thanks Received: 23
Thanks Given: 4
Joined: Apr 2015
Reputation: 18
Status
None
Nice work with this, the result looks great!

I can add a couple pieces of information about the 6-byte graphics properties. In the byte 1, bit 6 (0x40) is the MSB of the tilemap offset from byte 1. Bit 7 (0x80) determines if the graphics is 2bpp (if 1) or 3bpp (if 0). Like you mention, the 16x16 tiles don't get loaded directly from ROM, but rather from the 2bpp or 3bpp tilemap, which are at D2/C000-D2/DFFF and D2/0000-D2/5FFF. You can view these tilemaps in FF6Tools via Ability -> Attack Tilemap (2bpp) or (3bpp).

Also, for the animation frame data at D1/0141-D1/E988, the 2-byte format is as follows:

Byte 0: xxxxyyyy (x,y) position for this tile
Byte 1: vhtttttt v/h flip and tile index

Each frame is terminated by 0xFFFF *OR* when it reaches the next pointer in the pointer table at D4/DF3C-D4/F645. So if your frames are sequential you can omit the 0xFFFF terminator to save 2 bytes. For reference, the subroutines that load this data are at C1/9F61 for BG threads and C1/A0C6 for sprite threads.
  Find
Quote  
[-] The following 4 users say Thank You to Everything for this post:
  • C-Dude (10-27-2022), DrakeyC (10-27-2022), Gi Nattak (10-28-2022), Warrax (10-29-2022)

#19
Posts: 732
Threads: 36
Thanks Received: 12
Thanks Given: 41
Joined: Jan 2016
Reputation: 6
Status
None
Thanks for the additional clarifications!
  Find
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite