Users browsing this thread: 1 Guest(s)
Frame Job - Making Weapons show after a strike

#1
Posts: 363
Threads: 31
Thanks Received: 154
Thanks Given: 136
Joined: Dec 2018
Reputation: 18
Status
Moog
Lightning wanted to change the strike animation so that the weapon would always show for a final frame after strike, much like how Final Fantasy 4 and 5 handle weapon graphics. In other words, the swipe on small swords needed to be replaced. After much bamboo-under-nails agony, @everything8215 came down from code heaven and explained how this stuff actually works and we were able to achieve the desired effect.

So, first thing's first. There's attack graphics data (https://www.ff6hacking.com/wiki/doku.php...phics_data) at D4D000 to D4DF3B. These are six-byte strings of information about the attack, such as which weapon tile region to draw from. That information is arranged as follows:
Code:
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
For this example, we worked with the Regal Cutlass, which has an internal index of 0x29 (You can see this index in the USME weapon animation editor). So, since this data comes in strings of 0x06, and we're looking at index 0x29, we take the product 0x29 * 0x06 to get our offset, which in this case is D4D0F6. (Remember, file offsets in a hex editor are -C00000 for HiRom, so if we're looking in hXd this offset would be 14D0F6).

Okay, so we go to this offset and we get Regal Cutlass's attack graphics data, which is
04 21 D7 00 03 03
Byte 1 tells us that this particular weapon strike has four animation frames. Byte 2 tells it which graphics set to draw from, which in this instance is the Regal Cutlass set (which is shared with a few other weapon tiles, including the paint brushes, but we're leaving this value be for now). The next two bytes are really important, though, that's the animation offset. D7 00 is two bytes of data listed little-endian, so the low byte is first. That means that Regal Cutlass has an animation offset of 00D7. What do we do with that? Well...

The game converts this offset into a pointer, but those pointers are ALSO two bytes, so we have to double the offset to find the pointer address.
0x00D7 * 0x02 = 0x01AE
The pointers to Battle Animation frame data are located in a jump table from D4DF3C to D4FFFF, so we add the low end of that range to our doubled offset to get the Regal Cutlass's battle animation frame data. 0x01AE + 0xD4DF3C = 0xD4E0EA

We go to 0x14E0EA in our hex editor, and we find this:
7D 05 7F 05 83 05 85 05
Each frame of the animation has its own pointer, and we know that the Regal Cutlass has four frames of animation from its graphics data (that Byte 1 from D4/D0F6). So, we need eight bytes, two for each pointer times four frames.

These pointers are modifiers to the $D1 bank, so...
Code:
Regal Cutlass
Frame 0 data: D1/057D  -  02 00
Frame 1 data: D1/057F  -  11 04
Frame 2 data: D1/0583  -  12 06
Frame 3 data: D1/0585  -  12 07
Regal Cutlass shows the sword over the character's shoulder, then a swipe behind the character's back, followed by a cross-swipe that is drawn in front of the character, and finally fading particles from that cross-swipe. We want to replace the last frame with another draw from the sword, so, let's gather the data from these four addresses and see what's going on there.

https://www.ff6hacking.com/wiki/doku.php...frame_data

Frame data comes in two byte strings. The first determines the base offset of the frame, and the second determines which graphic map to use. Don't ask me where the graphic maps are; they're a completely unrelated set of pointers in the $D2 bank and that's outside the scope of this discussion (The best I could muster was reverse-engineering a tilemap location by locating the tile's graphic address (found in YYCHR), dividing by 0x18, and then searching for the result little-endian in a hex editor.  There must be a table somewhere, but I don't know where it is).

You'd think we could just change Frame 4's data to be a copy of Frame 1, but then the sword will be drawn in the wrong orientation and position.  We need to horizontally flip it, so we add 0x40 to the second byte.  Then... we need to discuss what these two bytes actually DO.
Code:
Byte 0:     X, Y position of the graphic block in 16 pixel intervals
$0F     Y position (0 to 15)
$F0     X position (0 to 15)
Byte 1:   ID of block taken from graphic
$3F     Block ID (0 to 63)
$40     Flipped horizontally
$80     Flipped vertically
(Taken from the FF6 Wiki)

Okay, so the X and Y position sounds great, right?  Except, it's not.  It's not pixels.  It's not even TILES.  It seems to be stamps of the entire graphic, so even a change of 1 to either value will have a HUGE impact on the position of the graphic.  This is why animation scripts have finer positioning commands.
If we use the same positioning data as Frame 3, with a flipped sprite of Frame 1 (D1/0585 from 12 07 to 12 40), we end up drawing the sword on the attacker's foot.

(Original Discord tutorial had an image here, you'll have to use your imagination or try the change yourself)

That's no good.  But if we try to change the position of the sword, it'll get drawn off in space, with no apparent relation to the attacker at all.  We're going to have to change the animation script to match.
Weapon animation pointers are dictated by a jump table located at D1/EAD8.
This jump table consists of two-byte little-endian addresses, so we need to adjust our offset to match (doubling it, like we did before with the other jump table).
0x29 * 0x02 = 0x52, and 0x52 + 0xD1EAD8 = 0xD1EB2A
The value at that address is 90 7D.

All of the battle animation scripts are in the $D0 bank, which means that Regal Cutlass calls the animation script at D0/7D90.
That's great and all, but this animation script is shared by a BUNCH of weapons.  Either all the associated weapons need to have their frames changed to match, or we need to repoint Regal Cutlass to freespace where we can control how its animation plays out.  I'll leave that decision up to you.  For the purposes of this tutorial, we're just going to change that animation in-line.
From the battle animation document... we can see what's going on at D0/7D90
Code:
; [ Animation Script $0016: Chocobo Brsh (sprite) ]

D0/7D90: 00 20                    speed 1, align to center of character/monster
D0/7D92: 8E 01                    show animation on weapon-hand side of character/monster sprites
D0/7D94: 81 12 13                 change attacker graphic to 18 (walking forward, frame 2) if facing left or 19 (walking forward, hands up) if facing right
D0/7D97: 83 81                    move back 2
D0/7D99: 83 F6                    move up/back 23
D0/7D9B: BF 03 71                 jump to subroutine $7103
D0/7D9E: C9 00                    play default sound effect
D0/7DA0: 83 7E                    move forward 31
D0/7DA2: 83 36                    move down 23
D0/7DA4: 81 04 06                 change attacker graphic to 4 (walking forward, frame 1) if facing left or 6 (walking forward, frame 3) if facing right
D0/7DA7: 01                       [$01]
D0/7DA8: 01                       [$01]
D0/7DA9: 01                       [$01]
D0/7DAA: 01                       [$01]
D0/7DAB: 83 C7                    move up 8
D0/7DAD: 8E 00                    show animation on off-hand side of character/monster sprites
D0/7DAF: 02                       [$02]
D0/7DB0: 02                       [$02]
D0/7DB1: 02                       [$02]
D0/7DB2: 02                       [$02]
D0/7DB3: 03                       [$03]
D0/7DB4: 03                       [$03]
D0/7DB5: 03                       [$03]
D0/7DB6: 03                       [$03]
D0/7DB7: FF                       end of script
Notice the square bracket hex calls?  Those are references to the frames we were working with earlier.

So, see how the weapon frames are shifted up 8 between $01 and $02?  We need to change that shift.  We want $03 to be shifted so that the sword is drawn in the right spot.
So first, we're going to increase the offset of Frame 3 so that we have some room to nudge around.

D1/0585
Change from 12 07 to 02 40

(Original Discord tutorial had an image here, of a sword about 11 pixels left of Celes's foot)

Okay, so we need to move this sword up and to the right.  To do that, we need to change the animation script.  There's an instruction to move up 8 pixels, but we want to move it up and back.  83 E0 will move our frame up/back 1 pixel, so we need to count up until we get to a value that looks appropriate.  After some experimenting, I found that 83 EB works well.  So we'll swap that in to the animation script at D0/7DAB, in place of the original move command.
But uh oh, by changing that command, we've messed up Frame 2!

(Original Discord tutorial had an image of a slash over Celes, too far to the right)

Fortunately this problem is easy to fix: we'll adjust the X value of Frame 2 to match.

D1/0583
Change from 12 06 to 02 06

This forces the slash and the sword in these last two frames to line up with each other, which achieves the look we were shooting for!
So in total, the code changes were:
Code:
D0/7DAB (Chocobo Brsh animation)
Changed from 83 C7 to 83 EB
D1/0583 (Regal Cutlass Frame 2 Instruction)
Changed from 12 06 to 02 06
D1/0585 (Regal Cutlass Frame 3 Instruction)
Change from 12 07 to 02 40
Very few actual changes.  Just a lot of math to find the right places to tweak.

Weapons that share the Chocobo Brush animation:
16, 17, 1A, 1B, 1C, 20, 23, 26, 27, 29, 2A, 2B, 2C, 5A, 5B
Fifteen total.
16 (Chocobo Brush), 17 (Magical Brush), 1A (Hawk Eye), 1B (???), 1C (Striker Class), 20 (Bone Club), 23 (Guardian), 26 (Air Lancet), 27 (Dirk Class), 29 (SwordBreaker), 2A (???), 2B (Rune Edge), 2C (Flame Sabre Class), 5A (ValiantKnife), 5B (Falchion)
Attack graphics data for these weapons
Code:
D4D084 (0x16)
  04 20 8F 00 03 03
D4D08A (0x17)
  04 20 93 00 03 03
D4D09C (0x1A)
  04 20 9F 00 03 03
D4D0A2 (0x1B)
  04 21 A3 00 03 03
D4D0A8 (0x1C)
  04 21 A7 00 03 03
D4D0C0 (0x20)
  04 20 B7 00 03 03
D4D0D2 (0x23)
  04 21 C3 00 03 03
D4D0E4 (0x26)
  04 21 CB 00 03 03
D4D0EA (0x27)
  04 21 CF 00 03 03
D4D0F6 (0x29) **Our Example**
  04 21 D7 00 03 03
D4D0FC (0x2A)
  04 21 DB 00 03 03
D4D102 (0x2B)
  04 21 DF 00 03 03
D4D108 (0x2C)
  04 21 E3 00 03 03
D4D21C (0x5A)
  04 87 53 01 03 03
D4D222 (0x5B)
  04 87 57 01 03 03
Animation Pointers from this data
Code:
D4E05A (0x16)
  8D 04 8F 04 93 04 95 04
D4E062 (0x17)
  97 04 99 04 9D 04 9F 04
D4E07A (0x1A)
  C5 04 C9 04 CD 04 CF 04
D4E082 (0x1B)
  D1 04 D3 04 D7 04 D9 04
D4E08A (0x1C)
  DB 04 DD 04 E1 04 E3 04
D4E0AA (0x20)
  27 05 2B 05 2F 05 31 05
D4E0C2 (0x23)
  47 05 49 05 4D 05 4F 05
D4E0D2 (0x26)
  59 05 5B 05 5F 05 61 05
D4E0DA (0x27)
  63 05 65 05 69 05 6B 05
D4E0EA (0x29) **Our Example**
  7D 05 7F 05 83 05 85 05
D4E0F2 (0x2A)
  87 05 89 05 8D 05 8F 05
D4E0FA (0x2B)
  91 05 93 05 97 05 99 05
D4E102 (0x2C)
  9B 05 9D 05 A1 05 A3 05
D4E1E2 (0x5A)
  73 09 75 09 79 09 7B 09
D4E1EA (0x5B)
  7D 09 7F 09 83 09 85 09
Frame Data from these pointers
Code:
(0x16) Chocobo Brsh
D1048D
  02 00 11 0C
D10493
  12 0E 12 0F [pattern suggests delta to 02 0E 02 40]

(0x17) Magical Brush
D10497
  02 01 11 0C
D1049D
  12 0E 12 0F [pattern suggests delta to 02 0E 02 40]

(0x1A) Hawk Eye
D104C5
  02 04
D104C9
  11 0C
D104CD
  12 0E 12 0F [Thrown, leave it be]

(0x1B) ???
D104D1
  02 0B 11 04
D104D7
  12 06 12 07

(0x1C) Striker Style Daggers
D104DB
  02 0A 11 04
D104E1
  12 06 12 07 [pattern suggests delta to 02 06 02 40]

(0x20) Bone Club
D10527
  02 02
D1052B
  11 0C
D1052F
  12 0E 12 0F [pattern suggests delta to 02 0E 02 42]

(0x23) Guardian Style Daggers
D10547
  02 01 11 04
D1054D
  12 06 12 07 [pattern suggests delta to 02 06 02 41]

(0x26) Air Lancet Style Daggers
D10559
  02 09 11 04
D1055F
  12 06 12 07 [pattern suggests delta to 02 06 02 49]

(0x27) Dirk Style Daggers
D10563
  02 08 11 04
D10569
  12 06 12 07 [pattern suggests delta to 02 06 02 48]

(0x29) Regal Cutlass **Our Example**
D1057D
  02 00 11 04
D10583
  12 06 12 07 [we delta'd this to 02 06 02 40]

(0x2A) ???
D10587
  02 03 11 04
D1058D
  12 06 12 07

(0x2B) Rune Edge
D10591
  02 02 11 04
D10597
  12 06 12 07 [pattern suggests delta to 02 06 02 42]

(0x2C) Elemental Swords
D1059B
  02 0E 11 04
D105A1
  12 06 12 07 [pattern suggests delta to 02 06 02 4E]

(0x5A) Valiant Knife
D10973
  02 05 11 00
D10979
  12 02 12 03 [pattern suggests delta to 02 02 02 45]
 
(0x5B) Falchion
D1097D
  02 04 11 00
D10983
  12 02 12 03 [pattern suggests delta to 02 02 02 44]
  Find
Quote  
[-] The following 3 users say Thank You to C-Dude for this post:
  • Gi Nattak (01-01-2023), Joshua H. (01-03-2023), Lightning (01-23-2023)

#2
Posts: 116
Threads: 11
Thanks Received: 8
Thanks Given: 46
Joined: Jun 2021
Reputation: 2
Status
None
Seems like changing battle animations is gonna be a little over my head for a while.  Now that I'm nearing the end stage of my script project, I've been digging through FF6Tools, and I've been able to delete just a few of the event trigger tiles on the various maps to bypass some of the minor events in the game.  Things like Banon's tissue event and the like.  Super basic stuff, like that, has been eye-opening.

Just recently, I've been playing around with the "items" section of both FF6Tools and FF3usME, and that got me fixated on battle animations.  Particularly, the ones with any kind of pop-culture vibe to them...I'd like to see if I can remove them eventually.  Is the Jason Vorhees mask listed as a pointer anywhere around here?  I was assuming I could just clear out the color pallet for the mask.  Is something like that possible?  Or, would I need to go down a different rabbit hole?
  Find
Quote  

#3
Posts: 363
Threads: 31
Thanks Received: 154
Thanks Given: 136
Joined: Dec 2018
Reputation: 18
Status
Moog
This is more about animation than graphic display. I believe the hockey mask is part of the chainsaw graphic, which is more 3bpp graphics data. To that end, you could probably find it in FF6Tools or YYCHR and simply erase it, since you're not seeking to move it to another animation.

For information on how to navigate 3bpp graphics in YYCHR, you should check out Mutteo's harp tutorial thread. It's very helpful to find the data and see how to work with it.
https://www.ff6hacking.com/forums/thread-4013.html

In one of the images in the middle, YYCHR is open to address 1343B0 and you can see the autocrossbow at the bottom of the shot. I bet the two chainsaws are near there.
EDIT: If you go to 135C70 in YYCHR and set the display mode to 3bpp, you'll see the mask in the upper left of the window. The top of the mask is in the second tile row, it's the first two tiles there. The bottom of the mask is in the first tile row on tiles 2 and 3, it's connected to the top of the chainsaw handle so you'll need to be conscientious as you're erasing it.
  Find
Quote  

#4
Posts: 116
Threads: 11
Thanks Received: 8
Thanks Given: 46
Joined: Jun 2021
Reputation: 2
Status
None
Nice! I’ll give it a shot sometime this weekend.
  Find
Quote  

#5
Posts: 307
Threads: 20
Thanks Received: 18
Thanks Given: 68
Joined: Dec 2017
Reputation: 2
Status
None
I forgot to thank you here for this! This feature has been incorporated into my hack thanks to this tutorial. The weapon animations are so much more exciting!
  Find
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite