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

Author Topic: Dragon Warrior 1 Spanish Translation  (Read 2197 times)

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #20 on: May 09, 2018, 02:59:41 pm »
Question for my wonderful teachers:

Going through the enemy name list, there are several names that are going to require more space in Spanish than they would in English. I haven't looked at the item list yet, but the case for that may be the same. Is there a way to dump the item and enemy lists, translate them, and reinsert them into the ROM like we did with the dialogue/script?
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #21 on: May 09, 2018, 06:23:40 pm »
Going through the enemy name list, there are several names that are going to require more space in Spanish than they would in English. I haven't looked at the item list yet, but the case for that may be the same. Is there a way to dump the item and enemy lists, translate them, and reinsert them into the ROM like we did with the dialogue/script?

Hmm, it depends which is longest: the English or your Spanish. If the former, great. If the latter, you might need to get creative, finding some empty space somewhere (I'm not looking at the ROM now so I can't see what's there).

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #22 on: May 09, 2018, 10:05:49 pm »
Omigosh! It lives! Thank you so much abw and Psyklax!
Hurray! Don't you just love it when a plan comes together?  ;D

Should I post an ad for testers when it's ready? Or should I just test it myself?
This is completely up to you. Dragon Warrior is a pretty small game (with movement and battle systems that are easily abused by save states - if you haven't already, check out http://tasvideos.org/ for some examples of moving around the entire world without encountering a single unwanted enemy and 100% crit/evasion rates), so testing it all by yourself isn't too much work, but on the other hand it's usually nice to get a second set of eyes on a hack before you release it if you can. Whichever way you decide to go will be fine.

Also, how do I post pictures on this forum? The image button just gives me "[img*closingbracket*openingbracket*/img]", and I don't really know what to do with it.
Try sticking an image URL in between the [­​img] and the [​/img].

Question for my wonderful teachers:

Going through the enemy name list, there are several names that are going to require more space in Spanish than they would in English. I haven't looked at the item list yet, but the case for that may be the same. Is there a way to dump the item and enemy lists, translate them, and reinsert them into the ROM like we did with the dialogue/script?
Indeed there is! I can't be 100% certain without doing a lot more analysis than I care to at the moment, but based on the giant chunk of $FFs following the item/enemy/price/spells list, it looks like you've probably got all of 0x7AC7 - 0x7FE7 available for use (the English only uses up to 0x7EAE, so there's a good 300+ bytes of free space, which ought to be more than enough). As with the main dialogue, Dragon Warrior doesn't use a full pointer table with pointers to each string for these lists, but instead reads through the entire list starting from a condensed pointer table (at 0x6842-0x6851), counting end tokens until it finds the string it wants.

For dumping the text, you can try using Pointer Tables again, or since there are only 8 pointers to worry about, a raw dump straight from your favourite table-file-aware hex editor would work too.
Spoiler:
If you really want to be a guinea pig, you could also use abcde, but that probably has the worst learning curve of any of the available sane options, plus I need to push out some optimizations and bug fixes at some point.
Once you've got the list text translated, inserting it back into the ROM with Atlas should be just as easy as inserting the dialogue text was; you'll just need to make sure all the #W16() commands are in the right places.

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #23 on: May 10, 2018, 02:59:12 pm »
Hurray! Don't you just love it when a plan comes together?  ;D

I do!

Try sticking an image URL in between the [­​img] and the [​/img].

What if I don't have a URL? I wanna post some screenshots straight from my lappy. Do I need to upload something online then post a URL of the page?

Indeed there is! etc.

This sounds like good news. Would I be able to just press the insert button and type away in a hex editor, then, so long as I stay within the limit of those FFs? Or do I need to dump the item/spell/enemy text?

For dumping the text, etc.

I tried this and dumped the item/enemy/spell text successfully. However, the dump also includes a significant chunk of the script:

Code: [Select]
Table Start: 8012
Table End: 8037
Text Start: 7AC6
Text End: 7EAE
XOffset: FFFFFA9E

Table Type: 0
Text Type: 0
Custom PT: T0 T1

PT Line Command:
-----------------
8012
[60]Bamboo[ITM]Club[ITM]Copper[ITM]Hand[ITM]Broad[ITM]Flame[ITM]Erdrick}s[ITM]Clothes[ITM]Leather[ITM]Chain[ITM]Half[ITM]Full[ITM]Magic[ITM]Erdrick}s[ITM]Small[ITM]Large[ITM]Silver[ITM]Herb[ITM]Torch[ITM]Dragon}s[ITM]Wings[ITM]Magic[ITM]Fairy[ITM]Ball of[ITM]Tablet[ITM]Fairy[ITM]Silver[ITM]Staff of[ITM]Stones of[ITM]Gwaelin}s[ITM]Rainbow[ITM]Cursed[ITM]Death[ITM]Fighter}s[ITM]Erdrick}s[ITM]Secret[ITM]Pole[ITM][ITM]Sword[ITM]Axe[ITM]Sword[ITM]Sword[ITM]Sword[ITM][ITM]Armor[ITM]Mail[ITM]Plate[ITM]Plate[ITM]Armor[ITM]Armor[ITM]Shield[ITM]Shield[ITM]Shield[ITM][ITM][ITM]Scale[ITM][ITM]Key[ITM]Water[ITM]Light[ITM][ITM]Flute[ITM]Harp[ITM]Rain[ITM]Sunlight[ITM]Love[ITM]Drop[ITM]Belt[ITM]Necklace[ITM]Ring[ITM]Token[ITM]Passage[ITM]Slime[ITM]Red[ITM]Drakee[ITM]Ghost[ITM]Magician[ITM]Magidrakee[ITM]Scorpion[ITM]Druin[ITM]Poltergeist[ITM]Droll[ITM]Drakeema[ITM]Skeleton[ITM]Warlock[ITM]Metal[ITM]Wolf[ITM]Wraith[ITM]Metal[ITM]Specter[ITM]Wolflord[ITM]Druinlord[ITM]Drollmagi[ITM]W
8014
yvern[ITM]Rogue[ITM]Wraith[ITM]Golem[ITM]Goldman[ITM]Knight[ITM]Magiwyvern[ITM]Demon[ITM]Werewolf[ITM]Green[ITM]Starwyvern[ITM]Wizard[ITM]Axe[ITM]Blue[ITM]Stoneman[ITM]Armored[ITM]Red[ITM]Dragonlord[ITM]Dragonlord[ITM][ITM]Slime[ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM]Scorpion[ITM][ITM][ITM]Slime[ITM][ITM][ITM][ITM][ITM][ITM]Scorpion[ITM]Knight[ITM][ITM][ITM][ITM][ITM]Knight[ITM][ITM]Dragon[ITM][ITM][ITM]Knight[ITM]Dragon[ITM][ITM]Knight[ITM]Dragon[ITM][ITM][ITM]g<BE>a0Y0<B4>0M2<DC>5,C20k0<46>0I1<E8>3<B8>bku20<5A>0w3<D0>Vo080k0<46>0R0C00000000000000000<68>1[60]9u000HEAL[ITM]HURT[ITM]SLEEP[ITM]RADIANT[ITM]STOPSPELL[ITM]OUTSIDE[ITM]RETURN[ITM]REPEL[ITM]HEALMORE[ITM]HURTMORE[ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM]
8016
[ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM][ITM]<78><EE><DF><BF>!<8E>[ITM]<80>:.}*.()w[57]*.}.}-(.}ww<56><DE>M<70>141f70<D8><BF><D8><BF><D8><BF><B0><BC>E<80><86><82>p<85>j<87>!<89>i<8D><6E><90><42><94>u<98><88><9C>""<9F><8A><A2><DC><A6>K<AA><61><AC>E<AE><EE><AF><8B><B6><65><BA>[NME] hath woken up.%[60]&Thou art dead.%{Thou art strong enough!&Why can thou not defeat the Dragonlord?}@%{If thou art planning to take a rest, first see King Lorik.}%[ME] held the Rainbow Drop toward the sky.&[60]@%But no rainbow appeared here.%{Good morning.&Thou hast had a good night's sleep I hope.}@%{I shall see thee again.}%{Good morning.&Thou seems to have spent a good night.}@%{Goo
8018
d night.}&%{Okay.&Good-bye, traveler.}%{Welcome to the traveler's Inn.&Room and board is [NUM] GOLD per night.&Dost thou want a room?}&%{All the best to thee.}%{There are no stairs here.}%{Thou cannot enter here.}%{There is no one there.}%{I thank thee.&Won't thou buy one more bottle?}&%{Will thou buy some Fairy Water for 38 GOLD to keep the Dragonlord's minions away?}&%{I will see thee later.}%{Thou hast not enough money.}@%{I am sorry, but I cannot sell thee anymore.}%{Here,take this key.&Dost thou wish to purchase more?}&%{Magic keys!&They will unlock any door.&Dost thou w
etc.
up to:
8034
ded in battle, [ME].}@&{Sleep heals all.}%{Descendant of Erdrick, listen now to my words.}@&{It is told that in ages past Erdrick fought demons with a Ball of Light.}@&{Then came the Dragonlord who stole the precious globe and hid it in the darkness.}@&{Now, [ME], thou must help us recover the Ball of Light and restore peace to our land.}@&{The Dragonlord must be defeated.}@&{Take now whatever thou may find in these Treasure Chests to aid thee in thy quest.}@&{Then speak with the guards, for they have much knowledge that may aid thee.}@&{May the light shine upon thee, [ME].}%@The tablet reads as follows:@&[60]& {I am Erdrick and thou art my descendant.}@& {Three items were needed to reach the Isle of Dragons, which is south of Brecconary.}@& {I gathered these items, reached the island, and there defeated a creature of great evil.}@& {Now I have entrusted the three items to three worthy keepers.}@& {Their descendants will protect the items until thy quest leads thee to seek them out.}@& {When a new
8036


Error
Start is greater than end (start==B503 in ROM @ 8036)

I can tell I did something egregiously wrong, but what exactly was it? Did i give it the wrong Table Start/Table End numbers?
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #24 on: May 11, 2018, 08:18:27 am »
What if I don't have a URL? I wanna post some screenshots straight from my lappy. Do I need to upload something online then post a URL of the page?
Yeah, file hosting on RHDN is generally limited to submissions, with a few exceptions for things like personal forum avatars. Otherwise you've got to find your own file hosting elsewhere. There are plenty of options around, many of them free; if you don't know where to start looking for one, you can search the forum to find a few threads where people recommend their favourite hosting services.

Would I be able to just press the insert button and type away in a hex editor, then, so long as I stay within the limit of those FFs? Or do I need to dump the item/spell/enemy text?
Dumping these lists isn't strictly necessary - typing away in a hex editor will work as long as you stay within the limits of those FFs and update the pointer table to keep each pointer in the table pointing to the start of its respective section. If you e.g. start editing the item names and your new text goes past 0x7C7F but you don't update the enemy name pointer that points to 0x7C80, then you're going to end up with enemies who have names based on your new item names.

That said, typing away in a hex editor is usually not regarded as a good habit to get into for ROM hacking. You can definitely get away with it for small changes (probably most of us have done it that way at least once, especially for our first projects), but the bigger your project is, the more you're going to want to follow some Project Management ideas, such as having a build process that takes a clean copy of the base ROM and applies all of your changes from other files (which can then be tracked in your favourite VCS, which these days is likely to be git), preferably just by pressing a button (the ability to run a bunch of programs from a single script is one reason why people still love the command line even though GUI programs are prettier). It really sucks when you lose hours/days/weeks/months of work because you made a typo somewhere in your manually-hex-edited masterpiece that causes the game to crash, you can't track the typo down because it's just one more changed byte hiding amongst the million other bytes you've changed, and you don't have any working backups or you don't even know what's in them anymore >:(.

Did i give it the wrong Table Start/Table End numbers?
Yup, it looks like you're telling Pointer Tables to still use the pointer table from the main dialogue (8012-8037) rather than the pointer table for these lists - I imagine it will work better if you set Table Start to 6842 and Table End to 6851. You might want to dump the item prices (pointer at 0x684C to text at 0x7E1E - 0x7E65) separately as raw hex (i.e. with no table file translation), since those are stored as 16-bit little endian unsigned integers rather than text and it's easier to e.g. figure out that an item costs 9800 G when you see "<48><26>" than when you see ",C" ;).

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #25 on: May 12, 2018, 11:31:36 am »
Dumping these lists isn't strictly necessary - typing away in a hex editor will work as long as you stay within the limits of those FFs and update the pointer table to keep each pointer in the table pointing to the start of its respective section. If you e.g. start editing the item names and your new text goes past 0x7C7F but you don't update the enemy name pointer that points to 0x7C80, then you're going to end up with enemies who have names based on your new item names.

That said, typing away in a hex editor is usually not regarded as a good habit to get into for ROM hacking. You can definitely get away with it for small changes (probably most of us have done it that way at least once, especially for our first projects), but the bigger your project is, the more you're going to want to follow some Project Management ideas

Good to know. Iirc, Psyklax spoke against using game-specific editors, too, and that a hex editor was better and/or all you needed. Perhaps he meant more than he said, but his guidance left me under the impression that anything and everything could be/should be done in a hex editor :P

such as having a build process that takes a clean copy of the base ROM and applies all of your changes from other files (which can then be tracked in your favourite VCS, which these days is likely to be git), preferably just by pressing a button (the ability to run a bunch of programs from a single script is one reason why people still love the command line even though GUI programs are prettier).

When you say VCS, I think of an Atari 2600 :P Do you mean something like github?

It really sucks when you lose hours/days/weeks/months of work because you made a typo somewhere in your manually-hex-edited masterpiece that causes the game to crash, you can't track the typo down because it's just one more changed byte hiding amongst the million other bytes you've changed, and you don't have any working backups or you don't even know what's in them anymore >:(.

Yes! This is why I just make a copy of the ROM I dumped when I do something new.

Yup, it looks like you're telling Pointer Tables to still use the pointer table from the main dialogue (8012-8037) rather than the pointer table for these lists - I imagine it will work better if you set Table Start to 6842 and Table End to 6851. You might want to dump the item prices (pointer at 0x684C to text at 0x7E1E - 0x7E65) separately as raw hex (i.e. with no table file translation), since those are stored as 16-bit little endian unsigned integers rather than text and it's easier to e.g. figure out that an item costs 9800 G when you see "<48><26>" than when you see ",C" ;).

Okay, cool! Gonna try this. Now, question: how do you know where the pointer table for each section of text is? I assume there are certain hex values that tell you that, but how do you figure out what's what? Also, are there pointer tables for things other than text (e.g. calculations for damage points in an RPG)?

[Edited for a typo]
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #26 on: May 12, 2018, 01:18:13 pm »
Good to know. Iirc, Psyklax spoke against using game-specific editors, too, and that a hex editor was better and/or all you needed. Perhaps he meant more than he said, but his guidance left me under the impression that anything and everything could be/should be done in a hex editor :P

But you can use a non-game-specific tool without typing your whole script in a hex editor. :) That's what abw meant. Like using something like Pointer Tables to do your script, rather than directly typing into Windhex 32 EX.

And yes, anything CAN be done in a hex editor, but not necessarily SHOULD be done. ;)

Okay, cool! Gonna try this. Now, question: how do you know where the pointer table for each section of text is? I assume there are certain hex values that tell you that, but how do you figure out what's what? Also, are there pointer tables for things other than text (e.g. calculations for damage points in an RPG)?

It ain't the hex values, it's learning how to use the debugger in an emulator, and understanding assembly. Basically, a pointer is just a value that tells the game where to find something. So when there's a pointer table, it's a list of locations in the ROM, and the game will look there when it needs something, such as a line of dialogue. The alternative is to do what's called 'hardcoded pointers', meaning you have to write the location into the code ("load from this place, write it to RAM"). That's fine for simple things like a Game Over message or something, but dozens of lines of dialogue would be very impractical. With a table, there's a command that loads from a location, plus whatever is in a register. So if the game needs dialogue number 5, it will load 5 into a register and say "load from this address, plus 5".

So to find these pointers, you just work backwards with a debugger: you set a breakpoint for the line of dialogue, see where it got that address from. If you're lucky, you'll immediately find the pointer; otherwise you just keep following the trail.

If you need any help finding stuff in DW, let me know. :)

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #27 on: May 12, 2018, 05:51:49 pm »
When you say VCS, I think of an Atari 2600 :P Do you mean something like github?
Ah, sorry - VCS = Version Control System. git is currently the most popular VCS, and github is the most popular place for hosting/sharing git repositories.

But you can use a non-game-specific tool without typing your whole script in a hex editor. :) That's what abw meant. Like using something like Pointer Tables to do your script, rather than directly typing into Windhex 32 EX.

And yes, anything CAN be done in a hex editor, but not necessarily SHOULD be done. ;)
Yup. It's not like game-specific editors are evil or anything (some of them are pretty awesome), but if you always rely on them exclusively and never understand what's going on behind the scenes, that leaves you in a bad position for working on any game where somebody else hasn't already written a game-specific editor that does exactly what you want to do.

So to find these pointers, you just work backwards with a debugger: you set a breakpoint for the line of dialogue, see where it got that address from. If you're lucky, you'll immediately find the pointer; otherwise you just keep following the trail.
Here's how I found those pointers using FCEUX, in excruciating step-by-step detail. There are other ways of accomplishing the same goal, but despite the wall of text below, this process got me the answers I was after in only a couple of minutes, so it worked out pretty well.

1) Start with what you know: sometimes the game prints item names to the screen; for this example I'll use the ITEM command to trigger displaying item names.
2) Get to some place where item names are displayed; the ITEM command is available pretty much everywhere, so this part is easy.
3) Display the item name on screen; I have a Torch as the only item in my inventory, so that's what shows up.
4) Open the Name Table Viewer (from the Debug menu).
5) Put your mouse over the "T" in "Torch". The Properties section tells you the Tile ID (37 - in Dragon Warrior's case, this matches up with 37=T in your table file), the X/Y co-ordinates (34 / 27), and the PPU Address (2762) of that "T". We're interested in the PPU Address, so make a note of that.
6) Back in the game, get ready to display the item name again - close the ITEM menu, re-open the COMMAND menu, and position your cursor over the ITEM command, but don't press A yet.
7) Pause the emulator (use the Pause key on your keyboard or the NES -> Emulation Speed -> Pause menu item).
8​) Open the Debugger (also from the Debug menu).
9) Create a new breakpoint using the "Add" button. We want to break when PPU Address 2762 is written to, so enter 2762 in the first "Address" box, check the "Write" checkbox, and select the "PPU Mem" Memory radio button, then press "OK". You should get a breakpoint labelled "$2762:EP-W--". Breakpoints are enabled by default (the "E" in the label) and you can toggle them on/off by double-clicking them. Make sure the breakpoint is enabled.
10) Open the Trace Logger (also from the Debug menu).
11) Select the "Log to File" option and "Browse" for a file to save the trace log under; I made a new "torch.log" file.
12) Press the "Start Logging" button to start logging CPU instructions.
13) Back in the game, unpause the emulator and activate the ITEM command. You'll want to be quick about this - the NES is slow by modern standards, but it still runs at over 1 million cycles per second, so letting a full trace log run for very long is going to generate a large file. I managed to keep mine down to about 4 MB containing nearly 40,000 lines of code. The emulator will stop executing code when it reaches the breakpoint we set up earlier.
14) In the Trace Logger, press the "Stop Logging" button.
15) Open the trace log file from disk in your favourite text editor.
16) At the very bottom of the file, you should see a line like
Code: [Select]
                       $FE48:E8        INX                                          A:37 X:14 Y:0A S:E8 P:nvUbdIzc
. This is the instruction that was logged immediately before the emulator reached our breakpoint. You can see that A contains 37, which is the Tile ID for "T". Our job is to find out where in the ROM that 37 came from, and then find out where the code that loaded that 37 is, so we'll start working backwards.
17) Where did A get its value of 37 from? The previous line in the trace log is
Code: [Select]
                       $FE45:BD 00 03  LDA $0300,X @ $0314 = #$37                   A:5F X:14 Y:0A S:E8 P:nvUbdIzc
which shows that the value of A came from $0314. $0314 corresponds to system RAM, not ROM, so we'll backtrack to find out where $0314 got its value from.
18) Searching backwards in the trace file for "$0314" takes us to
Code: [Select]
                      $ACA1:B9 36 64  LDA $6436,Y @ $6444 = #$37                   A:5F X:14 Y:0E S:E9 P:nvUbdIzc
                      $ACA4:9D 00 03  STA $0300,X @ $0314 = #$5F                   A:37 X:14 Y:0E S:E9 P:nvUbdIzc
which shows us that $0314 got its 37 from $6444. $6444 corresponds to cartridge RAM, not ROM, so we'll backtrack to find out where $6444 got its value from.
19) Searching backwards in the trace log for "$6444" takes us to
Code: [Select]
                   $A562:BD 35 64  LDA $6435,X @ $6444 = #$37                   A:18 X:0F Y:05 S:EC P:NVUbdIzc
which we don't care about since LDA is a read command, not a write command. Going further backwards takes us to
Code: [Select]
                   $A555:AD DD 64  LDA $64DD = #$37                             A:0E X:0E Y:05 S:EC P:nvUbdIzc
                   $A558:9D 36 64  STA $6436,X @ $6444 = #$5F                   A:37 X:0E Y:05 S:EC P:nvUbdIzc
which shows us that $6444 got its 37 from $64DD. $64DD corresponds to cartridge RAM, not ROM, so we'll backtrack to find out where $64DD got its value from.
20) Searching backwards in the trace log for "$64DD" takes us to
Code: [Select]
                 $A62E:BD C9 64  LDA $64C9,X @ $64D2 = #$37                   A:FF X:09 Y:05 S:EE P:nvUbdIzC
                 $A631:8D DD 64  STA $64DD = #$5F                             A:37 X:09 Y:05 S:EE P:nvUbdIzC
which shows us that $64DD got its 37 from $64D2. $64D2 still corresponds to cartridge RAM, not ROM, so we'll keep backtracking to find out where $64D2 got its value from.
21) Searching backwards in the trace log for "$64D2" takes us to
Code: [Select]
                   $A85E:65 A1     ADC $00A1 = #$B7                             A:76 X:00 Y:76 S:EC P:nVUbdIzc
                   $A860:85 A1     STA $00A1 = #$B7                             A:2D X:00 Y:76 S:EC P:nvUbdIzC
                   $A862:90 02     BCC $A866                                    A:2D X:00 Y:76 S:EC P:nvUbdIzC
                   $A864:E6 A2     INC $00A2 = #$BA                             A:2D X:00 Y:76 S:EC P:nvUbdIzC
                   $A866:A0 00     LDY #$00                                     A:2D X:00 Y:76 S:EC P:NvUbdIzC
                   $A868:AE E2 64  LDX $64E2 = #$09                             A:2D X:00 Y:00 S:EC P:nvUbdIZC
                   $A86B:B1 A1     LDA ($A1),Y @ $BB2D = #$37                   A:2D X:09 Y:00 S:EC P:nvUbdIzC
                   $A86D:C9 FF     CMP #$FF                                     A:37 X:09 Y:00 S:EC P:nvUbdIzC
                   $A86F:F0 07     BEQ $A878                                    A:37 X:09 Y:00 S:EC P:nvUbdIzc
                   $A871:9D C9 64  STA $64C9,X @ $64D2 = #$5F                   A:37 X:09 Y:00 S:EC P:nvUbdIzc
which shows us that $64D2 got its 37 from $BB2D. $BB2D corresponds to ROM, so we've found the start of "Torch". Hurray! Alas, FCEUX's trace log doesn't indicate which ROM banks were visible in RAM at that point, but with a little extra digging (left as an exercise for the reader) we can figure out that RAM $BB2D is ROM 0x7B3D.
So, we're halfway there. Now, how about that ($A1)? We can see that the old value of $A1-$A2 was $BAB7 (which happens to be 0x7AC7, i.e. the start of both "Bamboo" and the entire item list), but how did $A1-$A2 get to be $BAB7? Let's backtrack some more.
22) Searching backwards in the trace log for "$00A1" takes us to
Code: [Select]
                      $A823:0A        ASL                                          A:02 X:04 Y:02 S:E9 P:nVUbdIzc
                      $A824:AA        TAX                                          A:04 X:04 Y:02 S:E9 P:nVUbdIzc
                      $A825:BD 30 A8  LDA $A830,X @ $A834 = #$B7                   A:04 X:04 Y:02 S:E9 P:nVUbdIzc
                      $A828:85 A1     STA $00A1 = #$FF                             A:B7 X:04 Y:02 S:E9 P:NVUbdIzc
                      $A82A:BD 31 A8  LDA $A831,X @ $A835 = #$BA                   A:B7 X:04 Y:02 S:E9 P:NVUbdIzc
                      $A82D:85 A2     STA $00A2 = #$A3                             A:BA X:04 Y:02 S:E9 P:NVUbdIzc
which makes it look like $A1-$A2 is the third pointer (pointers are 2 bytes long, so the first pointer is X=00, the second is X=02, and we're the third at X=04) in a pointer table starting at $A830 (0x6840). A little further investigation (another exercise for the reader) shows that the $A830-$A831 pointer goes to other places (a pointer table for menu stuff), but $A832 - $A841 are pointers into our lists at $BAB7 - $BE9E (0x7AC7 - 0x7EAE).

And there you have it!
« Last Edit: May 15, 2018, 06:58:04 pm by abw »

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #28 on: May 13, 2018, 03:28:58 am »
And there you have it!

Yeah, what he said. :D That's more or less what I would do, I was just too lazy to go in detail, so thank you abw for doing so. :)

One point I'd make, though:

13) Back in the game, unpause the emulator and activate the ITEM command. You'll want to be quick about this

I'd recommend getting to the point where you press your button, and use the frame advance hotkey instead of just unpausing and pausing again: just hold the correct button while paused (turn on input display to make sure you're pressing it) and frame advance until the breakpoint is hit. This way your log won't be too big (most of it is usually full of a vblank waiting loop anyway). I don't always jump straight to trace logging, since often when you set a breakpoint for text, the address will be directly before it in the disassembly, but DW is a good example of when to use a trace log. Why does the game keep loading and reloading within the cartridge RAM?! Very odd.

Anyway, keep trying this out with different games and you'll soon see there's nothing mysterious about it, you just need practice. ;)

ArkthePieKing

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #29 on: May 13, 2018, 05:09:11 am »
Oh this is awesome! I didn't realize this game didn't already have a Spanish translation. I'll never get tired of seeing games from my childhood translated into other languages for new people to experience. You're doing awesome! So quick question, are you keeping all of the 'ye olde' speech in? Is there a Spanish equivalent for that? I would assume so, but I don't speak Spanish so that's just a guess. Either way, keep up the great work! :D

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #30 on: May 14, 2018, 05:51:24 pm »
Oh this is awesome! I didn't realize this game didn't already have a Spanish translation. I'll never get tired of seeing games from my childhood translated into other languages for new people to experience. You're doing awesome! So quick question, are you keeping all of the 'ye olde' speech in? Is there a Spanish equivalent for that? I would assume so, but I don't speak Spanish so that's just a guess. Either way, keep up the great work! :D

Quick response to this (I'll edit with a longer response to Psyklax and abw later):

Thanks for the encouragement! I was surprised as well to see that this was the only DQ NES game that had yet to be translated. Unfortunately, I'm not well-versed enough in Renaissance-era Spanish to know the differences between today's Spanish and the Spanish of, say, Luis de Góngora. This translation uses current-day Spanish (and some creative liberties for the purposes of saving space). These will be detailed in the ReadMe and/or the translation log to be released with the patch. Thanks again!

Quick Reponse, Segundo Parte:

abw: I was able to follow that for the most part. Much of it seems to require knowledge of (correct me if I'm wrong) ASM? Like, I wouldn't know that LDA indicates a read command or much else about the lines of code (I'm guessing A, X, Y, and S are coordinates?). Where can I learn to read this?

Psyklax: Thanks for the encouragement and tips!

Update:

I've got translation scripts of the item, weapon, armor, enemy, and spell lists. I'm gonna send them to my editor for a quick glance, then insert the final product.

Next up: Menus! ;D
« Last Edit: May 15, 2018, 03:16:08 pm by werewolfslayr925 »
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #31 on: May 15, 2018, 07:06:05 pm »
I'd recommend getting to the point where you press your button, and use the frame advance hotkey instead of just unpausing and pausing again: just hold the correct button while paused (turn on input display to make sure you're pressing it) and frame advance until the breakpoint is hit.
Yeah, Input Display + Frame Advance is definitely a better way of doing that step. Clearly I need to pay more attention to the wealth of options FCEUX provides :p.

Assuming you already know where the text you want is stored in RAM, setting a read breakpoint for the text's RAM address is also an Excellent move! (see what I did there? :P), and depending on what the game you're looking at does, you can often get results this way faster than using a trace log.

abw: I was able to follow that for the most part. Much of it seems to require knowledge of (correct me if I'm wrong) ASM? Like, I wouldn't know that LDA indicates a read command or much else about the lines of code (I'm guessing A, X, Y, and S are coordinates?). Where can I learn to read this?
That's right - FCEUX's trace log displays the ASM instructions executed by the (emulated) 6502 CPU. If you check the Assembly category in the Documents section, you can find a bunch of 6502 resources. The SNES uses a 65816 CPU, which is basically a backwards-compatible upgraded version of the 6502, so you can also try reading the 65816 documents, and in fact I use Programming the 65816 as my primary reference for both 6502 and 65816.

In the 6502, A, X, Y, and S are all 8-bit memory registers. The accumulator, A is the main register; almost everything that happens in the CPU goes through A. X and Y are index registers; the main difference between X/Y and A are what 6502 instructions are available for each register - X/Y can be used in some instructions that A can't, and vice-versa. S is the stack pointer, which keeps track of where the top of the NES's tiny stack currently is.

There is a lot of ROM hacking you can do without knowing anything much about ASM (especially in areas like translation where you're mostly dealing with data, not code), but knowing enough ASM to be able to make use of a debugger to help figure out what's going on can be very helpful sometimes.

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #32 on: May 17, 2018, 01:50:43 am »
Okay, so, abw and Psyklax:

I've followed your advice on using FCEUX to look at all of the code. Psyklax, you've made this significantly less of a headache with your advice to use the frame advance hotkey :3 abw, I have a question about the exercises left for the reader (me): how do I figure out that (e.g.)

Quote
RAM $BB2D is ROM 0x7B3D

Is there a mathematical formula for this? (Seriously, is it math?) Or does this also require knowledge of ASM?

I noticed that fortune smiles upon me: you were kind enough to drop me a hint as to how to find the pointers to the menus. I'll see if I can work with that :3

Update:

After a bit of trial and error, I successfully dumped the menus and stats! Gonna translate 'em later today. Thanks again for your help, guys!
« Last Edit: May 17, 2018, 01:59:32 am by werewolfslayr925 »
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #33 on: May 17, 2018, 03:57:07 am »
Is there a mathematical formula for this? (Seriously, is it math?) Or does this also require knowledge of ASM?

I'll put you out of your misery on this one. :)

It's actually very simple. In the CPU's address space (people say RAM but technically it's not RAM) the ROM is accessed between $8000 and $BFFF, and $C000 and $FFFF (two banks). Any part of the ROM has to be swapped in and out of that address space. So as far as the game code is concerned, anything in that range is ROM. In the actual ROM file, on the other hand, it goes from address zero to wherever the ROM finishes. So if the first $4000 bytes of the ROM get put in the first bank, $0000 would be $8000. If it goes in the second bank, it'd be $C000.

But wait! What about that $10 difference? Well, that's the iNES header in the ROM file. Check NESdev to find out more about that. All you need to know for now is that the header takes up $10 in the file, but this never existed on a real cartridge, so it's ignored when putting it in the address space.

Thus, in your example, we take ROM address $7B3D, add $4000 (cause it's the first bank) and remove $10 because of the header - $BB2D. If it went in the second bank, it'd be $FB2D. To go from address space to ROM, just go in reverse.

Got it? ;)

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #34 on: May 17, 2018, 08:50:49 am »
Note, however, that the general form of this problem can get a little bit complicated in cases where the game makes heavier use of bankswapping, goes around changing the bank size all the time, or has a copy of the same data in multiple banks. Fortunately, none of that happens here!

Dragon Warrior uses mapper #1, a.k.a. MMC1 (FCEUX will tell you this if you look under the Help -> Message Log menu item), with 64k of PRG ROM and configures the mapper to use 2 16k banks with the first bank being swappable and the second bank ($C000-$FFFF) connected to the final 16k PRG ROM bank (0xC010 - 0x1000F). So, we know that $C000-$FFFF RAM addresses get mapped to ROM 0xC010-0x1000F, but $8000-$BFFF RAM addresses get mapped to whichever ROM bank the mapper is currently making visible; they could be mapped to 0x0010-0x400F, 0x4010-0x800F, 0x8010-0xC00F, or even 0xC010-0x1000F (though I don't think DW ever actually does that). In order to figure out which of the banks corresponds to $BB2D = $37, there are a few different approaches.

Since there are only 4 PRG banks, you could simply check offset 3B2D (= $BB2D - $8000) within each bank (i.e. 0x3B3D, 0x7B3D, 0xBB3D, and 0xFB3D after adding the $10 iNES header) and see which of them has a value of 37 at that address. You can also use the debugger to set a read breakpoint at $BB2D or an execute breakpoint at $A86B; FCEUX displays the bank number to the left of the RAM address (e.g. 01:A86B) and in the Hex Editor you can right-click on $BB2D and use the "Go Here In ROM File" option to get to 0x7B3D.

I noticed that fortune smiles upon me
:D

After a bit of trial and error, I successfully dumped the menus and stats! Gonna translate 'em later today. Thanks again for your help, guys!
Nice! Unless I've missed something, it sounds like you're getting pretty close - once the menus are translated, I think you've only got the title screen and end credits left to do (and then some play-testing, of course).

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #35 on: May 17, 2018, 02:09:54 pm »
I'll put you out of your misery on this one. :)

It's actually very simple. In the CPU's address space (people say RAM but technically it's not RAM) the ROM is accessed between $8000 and $BFFF, and $C000 and $FFFF (two banks). Any part of the ROM has to be swapped in and out of that address space. So as far as the game code is concerned, anything in that range is ROM. In the actual ROM file, on the other hand, it goes from address zero to wherever the ROM finishes. So if the first $4000 bytes of the ROM get put in the first bank, $0000 would be $8000. If it goes in the second bank, it'd be $C000.

But wait! What about that $10 difference? Well, that's the iNES header in the ROM file. Check NESdev to find out more about that. All you need to know for now is that the header takes up $10 in the file, but this never existed on a real cartridge, so it's ignored when putting it in the address space.

Thus, in your example, we take ROM address $7B3D, add $4000 (cause it's the first bank) and remove $10 because of the header - $BB2D. If it went in the second bank, it'd be $FB2D. To go from address space to ROM, just go in reverse.

Got it? ;)

I do! This is all really cool. abw's further explanation does make things more complicated, though:

Note, however, that the general form of this problem can get a little bit complicated in cases where the game makes heavier use of bankswapping, goes around changing the bank size all the time, or has a copy of the same data in multiple banks.

Is that the kind of thing that Metroid does?

Fortunately, none of that happens here!

Amen.

Dragon Warrior uses mapper #1, a.k.a. MMC1

This I found out from bootgod's database when I dumped the game :3

with 64k of PRG ROM and configures the mapper to use 2 16k banks with the first bank being swappable and the second bank ($C000-$FFFF) connected to the final 16k PRG ROM bank (0xC010 - 0x1000F).

This is where I get lost. If there are two banks of 16k, and 64k of PRG ROM, where's the other 32k?

Nice! Unless I've missed something, it sounds like you're getting pretty close - once the menus are translated, I think you've only got the title screen and end credits left to do (and then some play-testing, of course).

I finished the menus and stats today, actually  ;D Gonna go hunting for the credits location. As for the title screen, I recall reading that it's difficult to hack. Is there a way to dump and edit the text there? Should I just edit it by hand in the hex editor?

EDIT: Incidentally, and I'm not sure whether or not this is common, but the text for the Spanish menus and stats is significantly smaller than that of the English by 122 characters! So far, I've managed to keep everything well within limits :D
« Last Edit: May 17, 2018, 02:23:07 pm by werewolfslayr925 »
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

abw

  • Full Member
  • ***
  • Posts: 105
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #36 on: May 17, 2018, 10:16:30 pm »
Is that the kind of thing that Metroid does?
I've never gone poking around inside Metroid before, so I can't really say what it's doing internally. One project at a time! :P

This is where I get lost. If there are two banks of 16k, and 64k of PRG ROM, where's the other 32k?
Ah, that's the crux of the matter right there. The NES CPU only has a 16-bit (a.k.a. 64k, a.k.a. $0000-$FFFF) RAM address space, and only 32k of that ($8000-$FFFF) gets mapped to cartridge PRG ROM (the PPU has a separate address space that can be mapped to cartridge CHR ROM/RAM, but I'm ignoring CHR for the purposes of this discussion), but most games (including Dragon Warrior) are larger than 32k. This is where memory mappers come in to play.

Normally when you try to write to an address that is mapped to ROM, nothing happens because that memory is, well, read-only. In the case of any game larger than 32k, there's some extra hardware on the cartridge that is affected by writes to $8000-$FFFF (the details vary by mapper) and can change which sections of cartridge ROM are visible in RAM and where (e.g. RAM $BB2D could be ROM 0x3B3D, 0x7B3D, 0xBB3D, or 0xFB3D, ROM 0x3B3D could be RAM $BB2D or $FB2D, etc.).

So to answer your question: the other 32k isn't anywhere you can see it, and it stays that way until the game swaps it in!

I finished the menus and stats today, actually  ;D Gonna go hunting for the credits location. As for the title screen, I recall reading that it's difficult to hack. Is there a way to dump and edit the text there? Should I just edit it by hand in the hex editor?
There's always a way, it's just a question of how much work is involved :P. If you can find where the game starts loading the text from (good practice for your debugging skills!), you can use that knowledge to get a high-quality dump. If that's too much work, you can also just dump an entire byte range, edit that, and then re-insert it. Just remember to avoid overwriting any data you don't know is safe to overwrite and to update any pointers into the data you're editing and it will probably work out okay.

P.S.: I'm going to have no/limited internet access for the next couple of weeks, so I'll leave you in Psyklax's capable hands for a while ;)

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #37 on: May 18, 2018, 04:32:29 am »
I'll leave you in Psyklax's capable hands for a while ;)

Muhahaha... :D

If there are two banks of 16k, and 64k of PRG ROM, where's the other 32k?

I'll add to what abw said here. The 6502 CPU has a 16-bit address space, meaning to load and store addresses, it can't go beyond 16-bits, ie 64kb, or $FFFF. In my "early Famicom games" project, I played every game from the first few years and translated a bunch, and they all have either a 16kb or 32kb PRG ROM. Open up Donkey Kong for example, and you'll see the game is 40kb: 32kb PRG, 8kb CHR.

The first game I found that changed that was City Connection (the Japanese one, not the US one), which had a 16kb CHR ROM. I've also translated (or helped to translate) some other MMC1 games, and it's quite simple.

There's usually a routine in the game that loads the number of the bank, then stores it, usually to $C000 or thereabouts, because as abw says, that part is ROM so it can't be written to, but it's a signal to the MMC to switch banks. This happens instantly, and changes the bank between $8000 and $BFFF. The $C000 bank is fixed to the last 16kb of the ROM. In other games I worked on, I was able to double the size of the game simply by inserting 128kb of zeroes before the last bank, then changing the iNES header to reflect the new size.

So bank switching happens instantly, as it's handled by the MMC, and the CPU does nothing but store a number at an address. Therefore, many later games use this to extremes, changing banks multiple times a FRAME in order to maximise their available memory, and even to make cool effects like parallax scrolling.

Hope it's clearer now. ;)

werewolfslayr925

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Dragon Warrior 1 Spanish Translation
« Reply #38 on: May 23, 2018, 04:57:12 pm »
Muhahaha... :D

I'll add to what abw said here. The 6502 CPU has a 16-bit address space, meaning to load and store addresses, it can't go beyond 16-bits, ie 64kb, or $FFFF. In my "early Famicom games" project, I played every game from the first few years and translated a bunch, and they all have either a 16kb or 32kb PRG ROM. Open up Donkey Kong for example, and you'll see the game is 40kb: 32kb PRG, 8kb CHR.

The first game I found that changed that was City Connection (the Japanese one, not the US one), which had a 16kb CHR ROM. I've also translated (or helped to translate) some other MMC1 games, and it's quite simple.

There's usually a routine in the game that loads the number of the bank, then stores it, usually to $C000 or thereabouts, because as abw says, that part is ROM so it can't be written to, but it's a signal to the MMC to switch banks. This happens instantly, and changes the bank between $8000 and $BFFF. The $C000 bank is fixed to the last 16kb of the ROM. In other games I worked on, I was able to double the size of the game simply by inserting 128kb of zeroes before the last bank, then changing the iNES header to reflect the new size.

So bank switching happens instantly, as it's handled by the MMC, and the CPU does nothing but store a number at an address. Therefore, many later games use this to extremes, changing banks multiple times a FRAME in order to maximise their available memory, and even to make cool effects like parallax scrolling.

Hope it's clearer now. ;)

'Tis! Question: what's the difference between different MMC chips I imagine the later models (3, 4, and 5) are more efficient somehow (especially considering the games associated with 4 (Fire Emblem 1, Fire Emblem Gaiden) and 5 (Metal Slader Glory, Just Breed)?

Back to the hacking:

It turns out that, for the sake of consistency/proper vocabulary and by the recommendation of my editor, I'll need to encroach upon the blank space in the ROM starting at 0x7EB0 (hope I wrote that correctly) in order to accommodate for some monster names that need a bit more space. In addition to that small setback, there's a small vocabulary change that needs to be made throughout the ROM's text. I've translated everything else. After all that is done, I'll insert the script and start testing. I should have the ROM ready for testing by the end of the weekend at the latest :D
As the harbor is welcome to the sailor, so is the last line to the scribe.

- complaint in the margin of a medieval manuscript

Psyklax

  • Hero Member
  • *****
  • Posts: 649
    • View Profile
    • Psyklax Translations
Re: Dragon Warrior 1 Spanish Translation
« Reply #39 on: May 23, 2018, 05:38:25 pm »
what's the difference between different MMC chips

The pages on nesdev give you way more info on this than I ever could:
https://wiki.nesdev.com/w/index.php/Mapper

Suffice to say that the more advanced the chip, the more options available to the developer. MMC1 (in Dragon Warrior), for example, allows for PRG-RAM accessible between $6000 and $7FFF (what many refer to as "SRAM", though that's something of a misnomer), and two 16KB PRG-ROM banks which are either fixed or switchable. It allows the PRG-ROM to be up to 512KB, which when compared to the original 32KB is pretty substantial (incidentally, I was wrong about Donkey Kong: that used 16KB PRG, but it doesn't matter, plenty of other games used the full 32KB). It also allows for 128KB of CHR for graphics, switchable of course.

Compare to MMC5, the last official Nintendo chip, and it's even more useful. It has lots of different bank modes, with increasing granularity. The 32KB PRG bank can be swapped in and out in 8KB chunks (and can even use on-cartridge RAM instead of ROM if need be), and the 8KB CHR bank can be swapped in 1KB chunks. Both PRG and CHR have a 1MB capacity, and it even includes two pulse channels and a PCM channel to complement the existing ones in the NES, giving richer sound. The MMC5 really shows what could be done on such limited hardware when given a bit of help. Of course, as that link above shows, there are MANY other chips out there.

Hope that gives you some insight! I must say that once you get the hang of assembly, these chips are a godsend, because expansion can sometimes be as simple as I suggested earlier.