News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: [NES] The Legend of Zelda (Italian)  (Read 7802 times)

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
[NES] The Legend of Zelda (Italian)
« on: April 13, 2011, 10:08:23 am »
Hi guys, I'm translating The legend of Zelda in Italian and I need a hand with some problems.
The biggest one is: i want to change the colour of the text on the screen after the press start (Many years ago...), but i can't find how! Can someone help me with this? Thx a lot! ;D

Trax

  • Sr. Member
  • ****
  • Posts: 491
    • View Profile
    • Trax ROM Hacking
Re: [NES] The Legend of Zelda (Italian)
« Reply #1 on: April 15, 2011, 03:32:38 am »
The data for the palette mappings of the intro text in Zelda 1 is located in the range: 1A81B - 1A85D.
Each byte codes for a block of 4x4 tiles, 2 bits for each of its four 2x2 blocks.

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #2 on: April 15, 2011, 10:35:51 am »
YOU ARE GREAT!!!! YOU ARE MY SAVIOR!!! Thx a lot!!!

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #3 on: April 15, 2011, 06:18:14 pm »
For future reference:
http://datacrystal.romhacking.net/wiki/Legend_of_Zelda:ROM_map

Relevant info is toward the end in this case.

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #4 on: April 16, 2011, 05:20:51 am »
Ok guys you are really great! I have the last 2 questions:

1- I wanted to change the word "MAP" (1A395 - 1A397) that appear on the dungeon menu with the word "MAPPA" (in italian), but i have only 3 bytes and I need 5. How can I do?
2 - I have the same problem with the word "LEVEL-#" (19D17 - 19D1D) that I want to change with "LIVELLO-#" (I need 2 more bytes)

I tried to move all the following bytes but the result wasn't good. Can someone give me a hand? Thx a lot guys, you're awesome!

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #5 on: April 18, 2011, 06:41:24 pm »
This text is stored in "PPU macros". These are used not just for text, but for all kinds of graphic layout data and palette data. The format of these PPU macros is pretty similar among many different games.

For example, the data for "MAP" actually starts at 1A392, and is part of a larger piece of data.

1A380: 70 4B 6A 2A 7B 01 6D FF 2B 43 07 0C 18 16 19 0A
1A390: 1C 1C 2A A5 03 16 0A 19 2A 8C 10 F5 F5 FD F5 F5
1A3A0: FD F5 F5 FD F5 F5 F5 FD F5 F5 F5 FF
2B AC 10 F5


I've highlighted the "MAP" data in red. The 2A A5 specifies where the data will be written in graphic memory (which determines where it ends up on screen). The 03 specifies the length of the macro data. Finally, the 03 16 0A is the actual tile data that spells out "MAP".

Zelda uses "strings" of PPU macros. This is just a list of PPU macros that are stored together and used at the same time. I've highlighted the macro string that contains the "MAP" macro, in blue. The string is terminated with an FF byte (in bold).

I'm guessing that the easiest way to increase the length of the text is to:
  • Find some free space, big enough to contain the PPU macro string, plus some extra bytes
  • Find the pointer to the PPU macro string (The PPU macro string starts at 0x1A388. I would expect the pointer to have a value of $A378, so you want to search for 78 A3.)
  • Move and modify the PPU macro string.
  • Update the pointer to said string.
« Last Edit: April 18, 2011, 09:14:06 pm by snarfblam »

Trax

  • Sr. Member
  • ****
  • Posts: 491
    • View Profile
    • Trax ROM Hacking
Re: [NES] The Legend of Zelda (Italian)
« Reply #6 on: April 18, 2011, 08:13:04 pm »
I've searched the area too, and it seems the PPU chunks are grouped, just like Snarfblam said. The pointer to "COMPASS", "MAP" and the top of yellow map tile mappings is located at 1A050. And there is a considerable amount of unused space starting at 1ACD9, so there's more than enough latitude for changes in string lengths. The following modifications seem to work correctly, at least for the map and compass labels:
At 1A050:
E0 AC

At 1ACF0:
2B 43 07 0B 1E 1C 1C 18 15 0A 2A A4 05 16 0A 19
19 0A 2A 8C 10 F5 F5 FD F5 F5 FD F5 F5 FD F5 F5
F5 FD F5 F5 F5 FF 2B AC 10 F5 FE F5 F5 F5 FE F5
F5 F5 F5 FE F5 F5 F5 FE F5 FF
As for the level label, it's located at 19D14, and it can be easily replaced with:
20 41 07 15 12 1F 0E 15 15 18 FF 
But the level number is still displayed at the same location, which overwrites the "O". If you can find the bytes that define the level number location, you could add 2 to it and that would settle the matter. I presume it's hardcoded somewhere else. If someone knows the RAM address for the current level, that would help the search...

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #7 on: April 18, 2011, 09:39:43 pm »
Here we go :D

05:B02A:AD B1 6B   LDA $6BB1  ; Load level number
05:B02D:F0 EB      BEQ $B01A
05:B02F:8D 25 68   STA $6825  ; Patch into PPU data

The game takes the current level number and patches it into a PPU macro.

Add or subtract from the value at 0x17040 in the ROM to move the level number digit left or right. (This is the number shown in red above.) As long as it falls within the PPU data you're good.

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #8 on: April 19, 2011, 03:17:33 pm »
I've searched the area too, and it seems the PPU chunks are grouped, just like Snarfblam said. The pointer to "COMPASS", "MAP" and the top of yellow map tile mappings is located at 1A050. And there is a considerable amount of unused space starting at 1ACD9, so there's more than enough latitude for changes in string lengths. The following modifications seem to work correctly, at least for the map and compass labels:
At 1A050:
E0 AC

At 1ACF0:
2B 43 07 0B 1E 1C 1C 18 15 0A 2A A4 05 16 0A 19
19 0A 2A 8C 10 F5 F5 FD F5 F5 FD F5 F5 FD F5 F5
F5 FD F5 F5 F5 FF 2B AC 10 F5 FE F5 F5 F5 FE F5
F5 F5 F5 FE F5 F5 F5 FE F5 FF
As for the level label, it's located at 19D14, and it can be easily replaced with:
20 41 07 15 12 1F 0E 15 15 18 FF 
But the level number is still displayed at the same location, which overwrites the "O". If you can find the bytes that define the level number location, you could add 2 to it and that would settle the matter. I presume it's hardcoded somewhere else. If someone knows the RAM address for the current level, that would help the search...

It's perfect, i tried and all work fine! Thx a lot!

Here we go :D

05:B02A:AD B1 6B   LDA $6BB1  ; Load level number
05:B02D:F0 EB      BEQ $B01A
05:B02F:8D 25 68   STA $6825  ; Patch into PPU data

The game takes the current level number and patches it into a PPU macro.

Add or subtract from the value at 0x17040 in the ROM to move the level number digit left or right. (This is the number shown in red above.) As long as it falls within the PPU data you're good.

I tried with the 20 41 09 15 12 1F 0E 15 15 18 FF string, but I need to write "LIVELLO " (with a space between "O" and the level number). How could i do?
« Last Edit: April 19, 2011, 03:59:48 pm by MattDragon »

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #9 on: April 19, 2011, 05:45:12 pm »
This is the important bit. I probably should have put more emphasis on it.

As long as it falls within the PPU data you're good.


Your problem is that you need a dummy tile in the PPU data. The game inserts the level number into the ppu macro. If you move the level number to the right two tiles, this is where the level number will be inserted:

20 41 07 15 12 1F 0E 15 15 18 FF **
----- -- L  O  V  E  L  L  O     #

The game is writing the level number beyond the end of the PPU data. With 20 41 07 15 12 1F 0E 15 15 18 FF, you don't give the game anywhere to write the level number. You need two more tiles: the space, and a dummy byte that will be replaced with the level number. In other words:
20 41 07 15 12 1F 0E 15 15 18 24 01 FF
----- -- L  O  V  E  L  L  O  _  1
.

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #10 on: April 20, 2011, 04:16:41 am »
I understood, but the problem is: how can i add 2 bytes there?

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #11 on: April 20, 2011, 09:42:18 pm »
The simple answer is you can't.

The data is copied to RAM and later read from there. It needs to be stored in RAM because it will need to be modified to update the level number in the PPU macro.

This makes things more difficult, because not only do you need to relocate the data to free space in the ROM, but you also need to load the data into free RAM, and then you need ASM to load the new data from ROM to RAM. (You can't just re-point this one piece of data because the old data is part of a larger chunk that's all loaded at once.)

You can use this code to load the new PPU data into RAM. The new data is included in the code.
Code: [Select]
; Data
destStart = $7F00
dataSize = endOfPpuData - ppuData
destEnd = destStart + dataSize

; Labels
HijackReturn = $809F
CopyBytes = $80D7

.org $BE00 ;0x1be10
   
DisplacedCode:
      ; We need to run the code that our hijack displaced
      JSR $80C6 ; LoadSomePointers
      JSR $80D7 ; CopyBytes

SetUpCopyPointers:
      ; Source address
      LDA #<ppuData
      STA $00
      LDA #>ppuData
      STA $01
   
      ; Dest addresses
      LDA #<destStart
      STA $02
      LDA #>destStart
      STA $03
   
      LDA #<destEnd
      STA $04
      LDA #>destEnd
      STA $05
     
CopyAndReturn:
      JSR CopyBytes
      JMP HijackReturn
   

ppuData:
      .db $20, $42 ,$09, $15, $12, $1F, $0E, $15, $15, $18, $62, $00, $FF
      ;   PPU dest, len, L    I    V    E    L    L    O   space  -  end
endOfPpuData:

This is the code in assembled form, which you can copy to 0x1BE10 in the ROM.

20 C6 80 20 D7 80 A9 24 85 00 A9 BE 85 01 A9 00
85 02 A9 7F 85 03 A9 0D 85 04 A9 7F 85 05 20 D7
80 4C 9F 80 20 41 09 15 12 1F 0E 15 15 18 30 62
FF


We need a hijack to run the above code.
Code: [Select]
JMP $BE00
In assembled form (copy to 0x180A9):
4C 00 BE

Finally, we need to update two pointers. The first pointer tells the game where to load the PPU macro from to write "LEVEL" on the screen. We change this to $7F00 (write 00 7F to 0x1A01C). The other pointer tells the game which byte in the PPU macro to update with the level number. We change this to $7F0B (write 0B 7F to 0x17040).


It seems rather elaborate for such a simple change, but it's the best I could come up with. Be aware that I'm not positive that the RAM at $7F00 is unused, but it appears to be.
« Last Edit: April 20, 2011, 09:52:42 pm by snarfblam »

Trax

  • Sr. Member
  • ****
  • Posts: 491
    • View Profile
    • Trax ROM Hacking
Re: [NES] The Legend of Zelda (Italian)
« Reply #12 on: April 21, 2011, 03:16:20 pm »
But Snarf, where in ROM is the chunk of data that is transfered into RAM in the first place?
The location (PPU address) of the level number must be somewhere in the ROM...

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #13 on: April 21, 2011, 05:52:07 pm »
I'm not sure I understand the question. You've identified the location of the original "LEVEL" data (19D14). This is loaded into RAM as part of a larger chunk of data that's all loaded at once. Its location in the ROM is never directly referenced. The only pointers for the "LEVEL" data point to the location where it is loaded into RAM. This is why you can't just write the new data to ROM and re-point.

Code: [Select]
; Copy source pointer to $00 (found at 8028)
        06:808C:     LDX #$00
        06:808E:     LDA $8028,X
        06:8091:     STA $0000 =
        06:8093:     INX
        06:8094:     LDA $8028,X
        06:8097:     STA $0001

; Load dest pointers (see below)
        06:8099:     JSR $80C6

; Copy routine
        06:809C:     JSR $80D7

; Unrelated crap follows
Code: [Select]
; Load copy destination pointers to $02 (start) and $04 (end)
; (67F0 - 687D)
; "LEVEL" macro is included in this (it is copied to $681C)
        06:80C6:     LDA #$F0
        06:80C8:     STA $0002
        06:80CA:     LDA #$67
        06:80CC:     STA $0003
        06:80CE:     LDA #$7D
        06:80D0:     STA $0004
        06:80D2:     LDA #$68
        06:80D4:     STA $0005

If you write the data elsewhere in the ROM (as I did), you'll need to load the additional data into RAM. (You NEED to load it into RAM, so it can be patched before it is handed to the PPU.)

Or do you mean, where does the byte used to patch the "LEVEL" macro come from? If that's the case, it comes from a block of level data that is also loaded into RAM. But this really isn't the issue. The level number isn't a PPU macro in itself, it's a single byte that is patched into "LEVEL" macro:
Code: [Select]
05:B02A:AD B1 6B  LDA $6BB1  ; Load level number (from level data block that has been loaded to RAM)
05:B02D:F0 EB     BEQ $B01A  ; Is it a level? (Overworld is level 0)
05:B02F:8D 25 68  STA $6825  ; Then write the level number into the "LEVEL" macro

So, the "LEVEL" macro is loaded into RAM, then modified, then loaded into the PPU.
« Last Edit: April 21, 2011, 06:10:32 pm by snarfblam »

Trax

  • Sr. Member
  • ****
  • Posts: 491
    • View Profile
    • Trax ROM Hacking
Re: [NES] The Legend of Zelda (Italian)
« Reply #14 on: April 21, 2011, 06:01:43 pm »
So if the macro in Cartridge RAM is like any other PPU macro around, then there must be two other bytes that define the level number tile position in PPU RAM. Probably at 6823 and 6824...

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #15 on: April 21, 2011, 06:22:23 pm »
I don't follow. Sorry if I'm not being clear, or if I'm misunderstanding you.

The level number is part of a larger macro. In the original game we have the macro, in ROM:
  20 42 07  15 0E 1F 0E 15 62 01 FF
PpuDest Len L  E  V  E  L  __ 1  end


What the game does is load this into RAM at $681C, but as part of a larger, containing chunk of data. Then, when you enter a level, it writes the level number to $6825, overwriting the "1" with the level number. For instance, in level 4...
  20 42 07  15 0E 1F 0E 15 62 01 FF
PpuDest Len L  E  V  E  L  __ 1  end
--becomes--
  20 42 07  15 0E 1F 0E 15 62 04 FF
PpuDest Len L  E  V  E  L  __ 4  end


Finally, this macro is fed to the PPU. But the level number is not its own macro.

Trax

  • Sr. Member
  • ****
  • Posts: 491
    • View Profile
    • Trax ROM Hacking
Re: [NES] The Legend of Zelda (Italian)
« Reply #16 on: April 22, 2011, 11:06:01 am »
Yeah, now I see exactly what you mean...
I just wanted to be sure of the mechanics at work...

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #17 on: April 23, 2011, 07:46:33 am »
I'm not sure I understand the question. You've identified the location of the original "LEVEL" data (19D14). This is loaded into RAM as part of a larger chunk of data that's all loaded at once. Its location in the ROM is never directly referenced. The only pointers for the "LEVEL" data point to the location where it is loaded into RAM. This is why you can't just write the new data to ROM and re-point.

Code: [Select]
; Copy source pointer to $00 (found at 8028)
        06:808C:     LDX #$00
        06:808E:     LDA $8028,X
        06:8091:     STA $0000 =
        06:8093:     INX
        06:8094:     LDA $8028,X
        06:8097:     STA $0001

; Load dest pointers (see below)
        06:8099:     JSR $80C6

; Copy routine
        06:809C:     JSR $80D7

; Unrelated crap follows
Code: [Select]
; Load copy destination pointers to $02 (start) and $04 (end)
; (67F0 - 687D)
; "LEVEL" macro is included in this (it is copied to $681C)
        06:80C6:     LDA #$F0
        06:80C8:     STA $0002
        06:80CA:     LDA #$67
        06:80CC:     STA $0003
        06:80CE:     LDA #$7D
        06:80D0:     STA $0004
        06:80D2:     LDA #$68
        06:80D4:     STA $0005

If you write the data elsewhere in the ROM (as I did), you'll need to load the additional data into RAM. (You NEED to load it into RAM, so it can be patched before it is handed to the PPU.)

Or do you mean, where does the byte used to patch the "LEVEL" macro come from? If that's the case, it comes from a block of level data that is also loaded into RAM. But this really isn't the issue. The level number isn't a PPU macro in itself, it's a single byte that is patched into "LEVEL" macro:
Code: [Select]
05:B02A:AD B1 6B  LDA $6BB1  ; Load level number (from level data block that has been loaded to RAM)
05:B02D:F0 EB     BEQ $B01A  ; Is it a level? (Overworld is level 0)
05:B02F:8D 25 68  STA $6825  ; Then write the level number into the "LEVEL" macro

So, the "LEVEL" macro is loaded into RAM, then modified, then loaded into the PPU.

This solution work fine!!! Thank you guys, you are great! I have the very last question:

I need to add a row here: http://img199.imageshack.us/i/immaginelim.png/
How can i do?
If it could help, i don't use this row in my translation: http://img35.imageshack.us/i/1immagine.png/
So i left it blank.

Thx a lot, you are really cool!!!

snarfblam

  • Submission Reviewer
  • Hero Member
  • *****
  • Posts: 589
  • CANT HACK METROID
    • View Profile
    • snarfblam
Re: [NES] The Legend of Zelda (Italian)
« Reply #18 on: April 24, 2011, 08:38:53 pm »
At this rate, I'll have the entire game disassembled in no time.

Here's what you need to do.
  • At 0x9190, change $00 to $80. This tells the game to put a line of text where you need it (below "LIFE POTION").
  • At 0x91D8, change $80 to $00. This tells the game to remove a line of text ("BRACELET").
  • Write the following at 0x94C9:
    FE 93 99 94 01 93 15 93 1C 93 32 93 47 93 5E 93
    69 93 7C 93 91 93 98 93 AB 93 C1 93 D4 93 E8 93
       
    We are basically moving the pointer for the line we removed to the location where we need it inserted. All the pointers between just get pushed forward one space.

Now, you are free to use the data at 0x940E for your text. The first byte specifies the indent of the text. You have the next eight bytes to work with for text.

If you need more room, just use some free space in the ROM. Update the pointer at 0x94C9 to the new data. Remember the format is <indent> <text> $FF.

MattDragon

  • Jr. Member
  • **
  • Posts: 16
    • View Profile
Re: [NES] The Legend of Zelda (Italian)
« Reply #19 on: April 27, 2011, 01:42:16 pm »
At this rate, I'll have the entire game disassembled in no time.

Here's what you need to do.
  • At 0x9190, change $00 to $80. This tells the game to put a line of text where you need it (below "LIFE POTION").
  • At 0x91D8, change $80 to $00. This tells the game to remove a line of text ("BRACELET").
  • Write the following at 0x94C9:
    FE 93 99 94 01 93 15 93 1C 93 32 93 47 93 5E 93
    69 93 7C 93 91 93 98 93 AB 93 C1 93 D4 93 E8 93
       
    We are basically moving the pointer for the line we removed to the location where we need it inserted. All the pointers between just get pushed forward one space.

Now, you are free to use the data at 0x940E for your text. The first byte specifies the indent of the text. You have the next eight bytes to work with for text.

If you need more room, just use some free space in the ROM. Update the pointer at 0x94C9 to the new data. Remember the format is <indent> <text> $FF.

Awesome!!! Fantastic, it works perfectly!!! Thx you for the patient!!! If I'll have other questions, i know you'll have always the right answare!!!  :thumbsup:

May 01, 2011, 06:19:07 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Hey guys! I'm working on the translation of all the spoken text in the game (405C - 45B1), but I'm having some problems with the pointer table (4010 - 405B). For example, the first pointer is 4C 80, but the first sentence start at 405C, so the pointer should be 4C 40... This is the same thing for the other pointers... Why? Thx a lot!!!
« Last Edit: May 01, 2011, 06:19:58 am by MattDragon »