News:

11 March 2016 - Forum Rules

Main Menu

Project: FF7 NES Upgrade

Started by Vanya, December 27, 2008, 10:58:55 PM

Previous topic - Next topic

Nerd42

#80
Last night I got stuck in Final Fantasy IV in the underworld. (Not sure where to go next) so I fired up the 98% translation patch for this game in "PSP NesterJ for CN Mapper" and FINALLY found that guy who heals you right before you get Barrett. It's like IMPOSSIBLE to finish the first mission without him.

I guess I'm gonna become the Feature Creature for a little bit here... hope I'm not annoying anyone, but you did say:
Quote from: VanyaAny other cool ideas we come up with. ^_^

So ... here are some ideas ... whether you think they're cool or not is up to you.

I dunno if anybody has mentioned this yet ... but it would be really fun to add secrets to this game. You know, items hidden in pots and behind bookcases and stuff. My favorite secrets in FF games are those you get by finding sneaky ways to get out of the area you're supposed to be walking in. I suggest making it so in one of the train cars after the first mission, you can walk out of one of the windows into the black no-mans-land area to find a secret chest after zigzagging through a miniature invisible maze type thing. (dunno if that's possible, but it would be COOL if it was) and there could be a piece of armor or an ether or extra gil or something in there - something helpful to make it worth it to find the secret

Also ... it would make the first mission alot easier if the person by the stairs healed you also just like the guy right before you get Barrett. Then you'd be able to level up alot quicker right at the beginning without all this screwing around on the bridge. I think that would really help the game's pacing. People don't like the feeling of losing the first mission. If I remember correctly, in the real Final Fantasy 7 your characters basically come strong enough to finish the first mission by default without alot of work that early anyway.

In the first town, it REALLY SUCKS that you can't take Barrett shopping with you so you can enhance his weapon ... I suggest having Barrett stay in the party during the first town if possible

(later edit) Oh, and by the way, I don't mind the thread clutter :) but patches are always nice too

Lindblum

A character's stats recover every time he/she has a level up.  It's weird as heck, but it balances the insanity of the gameplay, so I embraced it by making leveling up faster. 

I'd add treasure chests liberally if it were so easy, but they made it too awkward to hack it.  Every chest is linked to a predefined text string - L.A.M.E.

I've been planning on changing the Wep/Armor shops.  EVERY DAMN ONE OF THEM HAS THE SAME CRAPPY ITEMS!  I think it wouldn't be too hard for me change the way it loads inventory lists based on location, so I plan to work on that sometime. 

I think I can insert an instruction to keep Barret and Tifa in the party when you wake up in 7th Heaven, I did the same thing to make Cloud fight Sephiroth alone at the end, and *hopefully* fixed it (I forget) so you fight DemonGate as a group in the Temple of the Ancients.
Confidence is the feeling you have before you understand the situation.

Nerd42

wow that IS lame that you can't add treasure chests ........ how about easter eggs? Maybe add some quotes from LOVELESS (as quoted by Genesis in Crisis Core) or something

Lindblum

Loveless was the most annoying thing from Crisis Core, though I'd prolly throw in an easter egg if there were more opportunities to do so.  In my earlier translation (different thread) I seized the opportunity to include a reference to Zack's last words to cloud in the Cloud/Tifa Lifestream scene, since the Chinese script had deviated from the original game by that point.  Once I learned how to add more exchanges in a dialog I converted it to the original's text.  I was also hoping to have a "This guy are sick" moment, but there are no sick guy in the game (hope I can add one).  I wanted to maybe have a materia thief enemy that looks like Yuffie (the graphics improvement team is on this thread, maybe they'll consider it).  I was also thinking of having a guy who says "Where can I buy a phone?" or some way to reference Yuff & Vinny. 
Confidence is the feeling you have before you understand the situation.

Killa B

I just realized that when you're done with this, people are going to want to translate it back into Chinese. :crazy:
Quote from: KaioShin on January 25, 2010, 09:25:28 AMI always dreamed of doing a Pokemon hack

Nerd42

Quote from: Lindblum on March 13, 2009, 02:02:34 PM
Loveless was the most annoying thing from Crisis Core, though I'd prolly throw in an easter egg if there were more opportunities to do so.  In my earlier translation (different thread) I seized the opportunity to include a reference to Zack's last words to cloud in the Cloud/Tifa Lifestream scene, since the Chinese script had deviated from the original game by that point.  Once I learned how to add more exchanges in a dialog I converted it to the original's text.  I was also hoping to have a "This guy are sick" moment, but there are no sick guy in the game (hope I can add one).  I wanted to maybe have a materia thief enemy that looks like Yuffie (the graphics improvement team is on this thread, maybe they'll consider it).  I was also thinking of having a guy who says "Where can I buy a phone?" or some way to reference Yuff & Vinny. 
Aww ... I liked Loveless. It made the game sound so philisophical and stuff

Lindblum

At Gaea's Cliff there is a Sephiroth "shadow" that attacks you and says "Ugh...Errgaahh!" (in the original I think it was one of the clones dying).  Maybe it could say "Even if the morrow is barren of promises,nothing shall forestall my return.If this world seeks my destruction...It goes with Me."

Oh Sweet!  Go to 0x26ADC, overwrite the branch instruction with "EA EA."  This lifts the restriction that a person's materia can only level up if its bearer's level is 10x as high.  It always pissed me off how I could get all the experience needed to level up a materia (earned by casting), but it still wouldn't level up until my guy grew another 10 levels. 
Confidence is the feeling you have before you understand the situation.

Vanya

I wouldn't mind having "Materia Thief" as a new enemy. I want to have cameos for Yuffie & Vincent any way I can get it.

Lindblum

#88
I was worried if the graphics project had stopped, so here's a link to the game's enemy sprites.

EDIT: Hey, I'm making good progress in figuring out how to speed up battle animations (it's almost as hard as music hacking).  By the time I'm finished battles will actually be more exciting than walking!
Confidence is the feeling you have before you understand the situation.

Vanya

It isn't stopped, I've just been really busy lately. I actually got to work for actual pay in the past few weeks. Now that I'm back to being unemployed I'll have some time to work on stuff. Thanks for the sprites, though! That'll really help put some more fuel on the fire! ^_^

tummai

I made a little patch that should help out with people writing new songs.  It:

1) extends the note table to a full 8 octaves.  So instead of note values going from #$40-#$7F, they now go from #$40-#$9D.
2) tuned all of the notes.  They should no longer be flat (though some precision is lost at the highest octave)
3) added a new opcode (DF) that allows for musical branching.  This new opcode works with the loop opcodes (CE and CF), which I'll explain how to use below.

here is the file: http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871

How to loop

There are two opcodes for looping, CE and CF.  They both work exactly the same way, but they each have their own loop counter so you can nest them.  Here's how they work:

Let's say you have a set of notes you want to repeat:

02 6A 5E 6A 5E 6B 5F 6B 5F

To do so, you stick one of the loop opcodes on the end, followed by three operands: CE/CF [num] [lo offset] [hi offset].

[num] is how many times to play the phrase, including the first playthrough.
[lo offset] and [hi offset] tell where the beginning of the repeating musical phrase is, relative to the first byte of the song's header (the first FF).  This is kinda a pain in the ass because you have to count bytes every time.  For simplicity, let's pretend our little repeating phrase is at the beginning of our Square 1 data:


FF 00 0E 00 01 ?? ?? 02 ?? ?? 03 ?? ?? FF
;song header.  We only care about square1 for our example

CC C8 C7 FF C4 6B DB 07 00 00 00 DE 05 CD 03 02 D8 00
;square1 header

02 6A 5E 6A 5E 6B 5F 6B 5F
;our phrase that we want to loop

CE 08 20 00
;our loop opcode.


This will play our phrase 8 times.  the "20 00" tells us that the start of our looping phrase is at songheader+#$0020 (you can count to check).

This saves us a lot of space.  If we didn't use the loop opcode, we would have the following data instead:

FF 00 0E 00 01 ?? ?? 02 ?? ?? 03 ?? ?? FF
CC C8 C7 FF C4 6B DB 07 00 00 00 DE 05 CD 03 02 D8 00
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F
02 6A 5E 6A 5E 6B 5F 6B 5F


After the loop opcode, you can put more music data like normal.  After all repeats are done, it will continue on to whatever data you have after the loop opcode.

Branching Opcode

Ok, it's nice to loop, but what if we have a song structured like this:

A
A
B C
B D


The Chocobo song has this structure.  Hum it to yourself.  You can see that it repeats the first phrase (A) twice, and then changes to a new phrase (B) which has two different endings (C and D).

Our loop opcodes can take care of playing A twice in a row, but there is no support for something like BCBD.  We'd have to write out B manually two times, which wastes space.  So I wrote a new opcode (DF) in that will allow you to branch on the last iteration of a loop.

The format is:  [B Phrase] DF ?? ?? ?? [C Phrase] CE ?? ?? ?? [D Phrase].   The question marks denote operands.  The CE opcode is the loop one I explained above, so you should be able to fill in those question marks.  The DF is new, so here goes:

DF [which loop] [lo offset] [hi offset]

[which loop] should be either CE or CF.  Whichever loop opcode you use after your [C Phrase] should be the one you use here.
[lo offset] and [hi offset] tell the location of [D Phrase], relative to the first FF in the song's header.  Let's look at an example.  Here is the chocobo melody:

FF 00 0E 00 01 ?? ?? 02 ?? ?? 03 ?? ?? FF
;song header. We only care about square1 for now

CC C8 C7 FF C4 6B DB 07 00 00 00 DE 05 CD 03 02 D8 00
;square 1 header

02 6A C9 67 63 60 6A 67 63 67 C9 63 C9 06 67 02 65 01 63 C9 63 65 02
63 61 05 63 01 C9 02 61 01 63 C9 63 68 02 6A 6C 06 6D 02 C9 CE 02 20 00
;this is our [A Phrase].  Notice the CE loop opcode at the end that tells this to play twice.
 
6C C9 68 65 62 65 68 6C 6A C9 6F C9 06 6A DF CE 7B 00
;this is our [B Phrase] with the new DF opcode.
;It will be used in conjunction with the CE loop, and it tells us that our [D Phrase]
;is located at songheader+#$007B

02 6A 68 C9 65 62 5E 62 65 68 01 67 C9 67 68 02 67 65 06 67 02 C9 CE 02 4F 00
;this is our [C Phrase].
;At the end we have our loop opcode CE, which points us to the
;beginning of [B Phrase] (songheader+#$004F)

02 67 01 65 C9 65 67 02 65 63 06 65 02 63 01 65 C9 65 67 02 68 6A 04 6C 6E D0
;this is our [D Phrase].
;On the last repeat of [B Phrase], the DF opcode will send us here instead of to [C Phrase]


Chocobo Song
Here is some Chocobo Song data.  The bassline sucks and there's no percussion, but it will play.  Copy and paste it into 0x1B8DD and it will play as the intro song so you can listen.

Try to find all the loop and branch opcodes and see if you can understand what they're doing.  Can you figure out the sneaky trick I used to get the delay effect on the square2 channel?

FF 00 0E 00 01 95 00 02 B1 00 03 EC 00 FF

CC C8 C7 FF C4 6B DB 07 00 00 00 DE 05 CD 03 02 D8 00
02 6A C9 67 63 60 6A 67 63 67 C9 63 C9 06 67 02 65 01 63 C9 63 65 02 63 61
05 63 01 C9 02 61 01 63 C9 63 68 02 6A 6C 06 6D 02 C9 CE 02 20 00
6C C9 68 65 62 65 68 6C 6A C9 6F C9 06 6A DF CE 7B 00
02 6A 68 C9 65 62 5E 62 65 68 01 67 C9 67 68 02 67 65 06 67 02 C9 CE 02 4F 00
02 67 01 65 C9 65 67 02 65 63 06 65 02 63 01 65 C9 65 67 02 68 6A 04 6C 6E D0

CC FE C7 FF C4 08 DB 07 00 00 00 CD 03 03 DE 05 D8 00
DF CE 20 00 01 C9 CE 02 A7 00

CC FE C7 FF C4 6E DB 07 00 1E 78 DE 05 D8 00
02 63 5E 63 5E CE 10 C0 00
02 65 60 65 60 68 62 68 62 63 5E 63 5E 63 5E 63 5E CE 03 C9 00
02 65 60 65 60 65 60 65 60 CE 02 DE 00 D0

CC FE C7 FF C4 4A CD 45 00 D8 00 DE 00
C9 D0


The Patch

And just in case you missed it at the top, here is the patch: http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871

Vanya

Amazing job on that, dude! ^_^
I can't wait to see what comes of this. With the proper music in place this hack will be epic!!
I've gotta get my butt working on some graphics to go along with this!

Lindblum

O Happy day, I have good news too!  It was a real headache, but my first speed patch is out.  It speeds up several battle animations so things like simple attacks don't feel so much like Knights of Round (if only they were that powerful though).  Also, holding down B lets you walk twice as fast --as long as the screen isn't scrolling (hey, better than nothing).  I'll try out tummai's stuff soon. 
Confidence is the feeling you have before you understand the situation.

mrspoon

Glad to see the progress on thi is coming along.  :)

Vanya

Sweet, Lindblum!! That's awesome. That's a separate patch from the translation, right?

BTW, I looked over the enemy sprites you gave me. I'm going to go ahead and look for info on the FF7 psx enemies and decide what changes need to be made. I'll take the info on the attacks they use into account while I do the research, too. I'll be making a big update to the first post soon after that.

Great work guys! Keep it up and we'll have one of the most epic improvement hacks ever! ^_^

Cookies for everyone!!!
:cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie:
:cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie:
:cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie: :cookie:

tummai

I added another opcode, so there's another patch.  This patch does everything the previous patch did, plus the new pitch shift opcode.  You can download it here: http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871

Setting the Pitch Shift

There is an existing opcode D8 that will set the pitch shift.  The pitch shift is added to the note value to get a final note value.  For example, if you have a note 4C (an A), and your pitch shift is set to 01, the sound engine will do a 4C+01, giving you 4D (a B). 

The D8 opcode takes one operand (the pitch shift value) and is usually found in channel headers.  Most channels set it to 00, meaning no change in pitch.  It's not a terribly useful opcode.

Adjusting the Pitch Shift

Adjusting the pitch shift on the fly however is very useful.  So I made a new opcode to allow you to add or subtract from the pitch shift value.

The new opcode is D2.  It takes one operand, which is added to the pitch shift.  How is this useful?  Let's look at the first chord arpeggio of the classic FF intro song.  It's a major/9 arpeggio that spans five octaves.  It goes something like this:

(Octave 1)A B C# E (Oc2)A B C# E  (Oc3)A B C# E (Oc4)A B C# E (Oc5)A (Oc4)E C# B A (Oc3)E C# B A (Oc2)E C# B A (Oc1)E C# B.

If we were to write it out manually for the FF7 sound engine, we'd get something like this:

01 4C 4E 4F 53 58 5A 5C 5F 64 66 68 6B 70 72 74 77 7C 77 74 72 70 6B 68 66 64 5F 5C 5A 58 53 4F 4E

That's 33 bytes.  And this is only one chord.  The FF intro song has a few more, so we'd exceed 100 bytes just for one channel!

Luckily, with the new D2 opcode, we can take advantage of the arpeggio pattern and turn the above data into something like this:

01
4C 4E 4F 53 D2 0C CE 04 21 00
4C 47 44 42 D2 F4 CE 04 2B 00


That's 21 bytes, or 2/3 the size!

Let's look at what is happening:

1) First we play the phrase 4C 4E 4F 53.
2) Then we encounter the D2 opcode, which tells the sound engine to adjust the pitch by #$0C.  #$0C is hex for 12.  There are 12 notes on the music scale, so adding 12 to the pitch will raise it an octave.
3) After the D2 opcode, we encounter the CE opcode, which is our loop opcode.  It sends us back to the beginning.
4) We find our phrase again 4C 4E 4F 53, but this time #$0C will be added to them, effectively turning them into 58 5A 5C 5F.
5) We encounter D2 0C again.  This will add #$0C AGAIN (it stacks), so now our pitch adjustment is +#$18, or two octaves higher.
6) Loop again (+#$24), and again (+#$30) for a total of 4 times.  At the end of our loop we will be 4 octaves higher than we started.

7) Next we get to the descending phrase: 4C 47 44 42.  But remember, we are still four octaves higher, so these will actually turn into 7C 77 74 72 for the first playthrough.
8 ) We encounter the D2 opcode.  This time we add #$F4 to our pitch adjustment.  WTF?  #$F4?  Yes.  Adding #$F4 is actually like subtracting #$0C.  Since #$FF is the highest number on an 8-bit machine, the addition will loop around to #$00 and then count up and fall #$0C short of the previous value.  We throw away the carry.  Maybe this table will help make it clear:

00  00   adding 00 is the same as subtracting 00
FF -01   adding FF is the same as subtracting 01
FE -02   adding FE is the same as subtracting 02, etc
FD -03
FC -04
FB -05
FA -06
F9 -07
F8 -08
F7 -09
F6 -0A
F5 -0B
F4 -0C
etc...

So again, adding #$F4 to our pitch adjustment is essentially subtracting #$0C, which will lower the octave.
9) We loop to the beginning of the descending phrase and repeat 4 times.

Look at this data.  It is four chords arpeggiated (A/9, F#m/9, D/9, E/9):


;note length
01

;A/9 Chord
4C 4E 50 53 D2 0C CE 04 21 00
4C 47 44 42 D2 F4 CE 04 2B 00

;F#m/9 chord.  I put the D2 F4 in a different place. See explanation below.
49 4B 4C 50 D2 0C CE 04 32 00
D2 F4 55 50 4C 4B CE 04 3C 00

;D/9 chord
51 53 55 58 D2 0C CE 04 46 00
51 4C 49 47 D2 F4 CE 04 50 00

;E/9 chord
D2 02 CF 02 46 00

;song loop
D0


That's 68 bytes.  Without opcodes, this same phrase would be 130 bytes.  That's almost 50% savings!

The A/9 chord should look familiar, since we already stepped through it above.

Next is the F#m/9 chord.  Same concept, different notes.

After the F#m/9 chord, we have the D/9 chord.  It looks very similar to the A/9 chord.

Finally, for the E/9 chord, we pitch shift up a step (D2 02) and use the CF loop opcode to replay the D/9 chord, but this time shifted up a step (to E).  Doing this saves us 14 bytes.  Pretty nice!  Notice that we use the CF loop here, not CE.  This is because we have a CE loop nested inside our bigger CF loop.

Normally we'd want to zero our pitch shift out and put a D2 FE after our E/9 chord to cancel out the D2 02, but since we are at the end of the channel data we don't have to.  The D0 song loop opcode rereads the header, and our header will have a D8 00 in it.  I introduced the D8 opcode at the beginning of this post.  It sets the pitch shift.  The channel header's D8 00 will reset our pitch shift to 0 for us!  Sweet!

Prelude

Here is data for the FF intro song (but in the key of C).  I used the triangle channel as the main instrument for its soft sound, and I used the delay effect trick again.  Please look at the song header, as I have the channels in a nonstandard order (square1 and noise both point to the dead rests at the end).  You can paste this data in at 0x1B8DD and hear it as the new intro song.  It could still use some work, but I think it's an improvement over the crappy 1-chord version in the Chinese original. :) And about half the size too!


FF
00 9D00
01 8100
02 0E00
03 9D00
FF

CC C8 C7 FF C4 6B DB 07000000 DE 0A D8 0C

01
4F 51 53 56 D2 0C CE 04 1E 00
4F 4A 47 45 D2 F4 CE 04 28 00
4C 4E 4F 53 D2 0C CE 04 32 00
4C 47 43 42 D2 F4 CE 04 3C 00 CF 02 1E 00
4C 4F 54 56 D2 0C CE 04 4A 00
D2 F4 58 56 54 4F CE 04 54 00
D2 02 CF 02 4A 00
D2 FE
4B 4F 52 56 D2 0C CE 04 66 00
4B 4A 46 43 D2 F4 CE 04 70 00
D2 02 CF 02 66 00
D0

CC FE C7 FF C4 04 DB 07000000 CD 0301 DE 0A D8 00

DF CE 1D 00 02 C9 CE 02 93 00

00 C9 C9 D0


Patch

If you missed it above, here is the patch: http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871

And if you missed the little lesson on looping/branching, you can read that post here.

burn_654

that is extremely impressive, I'm even more impressed with the documentation of it all. I'm sure the community will be able to help with the tunes because of this :thumbsup:

great job.

I may have a go at working with this, if I get anything worthwhile I'll post it of course.

Vanya

Excellent work, tummai! I'm very impressed. ^_^

For anyone interested in doing some enemy sprites here's a page from the Final Fantasy wiki with images of the original enemies: http://finalfantasy.wikia.com/wiki/List_of_Final_Fantasy_VII_Enemies

Also, here's an archive with images of the NES enemies that Lindblum provided:
http://www.mediafire.com/file/uwjkykzlmcz/FF7NES-Enemy Sprites.zip

I'm currently researching both the psx & nes enemies. I already have a list of all the nes enemys' attacks, courtesy of Lindblum, now I just have to decide what out-of-place enemies need to be changed.

Lindblum

The new intro is cool.  The harmony you created is, dare I say, hypnotic and "trippy."  Feel free to improve the songs I posted earlier, they should give you a head start. 
Have you developed any tools, batches, or organized techniques to convert a song or composition into a chunk of bytes?  I ask because if not...
Proposal:
I want to make a program to do the tedious stuff for me, and if we're making so many songs that you're concerned about saving space, then it would be a good investment of time.  It would be cool to abstract it so it could use codecs to write to any game if you feed it the encoding scheme in some kind of syntax.  Maybe xml interpretation, have a piano roll editor, or accept MIDIs if they fit a certain set of constraints, and if I use a language with a good MIDI interpreter in its API.  For my ignorance it may miss the mark in terms of instruments and timing.  No one should have to overexert himself over music hacking, I'm just surprised I've never seen such a tool yet.
Confidence is the feeling you have before you understand the situation.

tummai

Thanks.  No, I haven't made any tools or a music editor or anything like that.  I wouldn't even know where to begin trying to make something like that.  Sounds like a great idea though! :)