Dragon Warrior II Name Generation Guide Version 1.0 2009-02-22 Copyright © 2009 Robert Kosinski. All Rights Reserved. whelkman in the proximity of hotmail.com Quote of the guide: "Mirror of Ra turns bitch into princess" --honestgamer -------------------- *** Introduction *** -------------------- Obsessive fans of the original Dragon Warrior know that name selection affects the hero's initial stats and progression. While level growth is static in the sequel, name selection determines your companions names from list. This guide walks through the process the game uses to decide which names your companions receive, both at practical and in-depth levels. Finally, I cover customizing companion names by hacking the ROM itself. ---------------- *** Overview *** ---------------- Algorithmically, Dragon Warrior II's name generator works similarly to its predecessor's: the outcome is determined by the sum of character codes of the first four letters of the inputted name. Unlike the original Dragon Warrior, however, Dragon Warrior II does not clear the "carry flag" during its additions. Imagine you're given graph paper onto which you can write numbers. If you wanted to write "99", it'd fit pretty easily in one square, but, for "100", you might choose to write "00" in one box and the "1" in the square immediately to the left. That's how it works for computers, too. In Dragon Warrior II's case, when an addition result exceeds 255 (0xFF in hexadecimal), a "one" to carry over is triggered internally as a "carry flag". Normally a programmer would either check to see whether the carry flag is set then tell the program the location of that box to the left or simply clear the flag because we're not interested in the carry, but Dragon Warrior II does neither. The carry flag is left to add back into the working result. In our graph paper example, if we didn't have a box to the left to put the "1" in "100" and subsequently added it back to our result, we'd get "00 + 1 = 01", a totally different answer than we expected. The same sort of issue occurs in Dragon Warrior II name generation, leading to to off by one or two results, thus destroying the easy division method offered by the first Dragon Warrior name guide. Complicating matters are junk numbers thrown into the equation that guarantee triggering the carry condition. Fortunately, I've figured it out so you don't have to. --------------------- *** Simple Method *** --------------------- Name Table A B C D E F G H 24 25 26 27 28 29 2A 2B I J K L M N O P 2C 2D 2E 2F 30 31 32 33 Q R S T U V W X 34 35 36 37 38 39 3A 3B Y Z ' , . ; ~ > 3C 3D 5F 69 6B 70 75 63 _ a b c d e f g 60 0A 0B 0C 0D 0E 0F 10 h i j k l m n o 11 12 13 14 15 16 17 18 p q r s t u v w 19 1A 1B 1C 1D 1E 1F 20 x y z ! ? 21 22 23 6F 6E Dragon Warrior's character set doesn't exactly match up with ASCII. Substitutions: ~ = .. > = arrow _ = space To complete this calculation you'll need a calculator that supports hexadecimal math and, preferably, bitwise AND. Windows' Calculator does the job, and I will assume you are using it. You'll need to enable scientific mode, located in the "View" menu; make sure you select hexadecimal mode by clicking on the "Hex" radio button located to the far left, just below the calculator display. After choosing your name, look up the values of the first four characters in the above table and add them together. Then add 180. Next, add whatever is in the third ("hundreds") digit to the first. Now eliminate the third digit, either by subtraction or by clearing the result and retyping the first two digits. Store this result with the M+ button. Now press the "And" button, located to the far right below the "C" button. Input the number 7 and finish the calculation with the "Enter" key or the "=" button in the calculator. The number given will correspond to a prince below: Prince Princess 0 Bran Varia 1 Glynn Elani 2 Talint Ollisa 3 Numor Roz 4 Lars Kailin 5 Orfeo Peta 6 Artho Illyth 7 Esgar Gwen Now press the "MR" key to recall our stored value. This time, press "And", input 38, then divide by 8. Finally, use the value to look up the princess' name on the chart. As an example, I chose "Loto" as my name. Using the above procedure: * Add name values together: 2F + 18 + 1D + 18 = 7C * Add 180: 7C + 180 = 1FC * Add third digit to first: 1FC + 1 = 1FD * Subtract third digit: 1FD - 100 = FD * Hit M+ key and see the 'M' indicator activate * And 7: FD AND 7 = 5 * Look up Prince of Cannock #5: Orfeo * MR: display = FD * And 38: FD AND 38 = 38 * Divide by 8: 38 / 8 = 7 * Look up Princess of Moonbrooke #7: Gwen ---------------------------------- *** What Happens in Game Logic *** ---------------------------------- I used FCEUX for the forthcoming analysis. Other tools may yield different results. The subroutine that calculates the names of your party members is located at $ACEB. What follows is a "trace log", the 6502 code that executes the algorithm: $ACEB:A9 00 LDA #$00 A:2F X:FF Y:00 P:NvUBdIzC $ACED:A2 03 LDX #$03 A:00 X:FF Y:00 P:nvUBdIZC $ACEF:18 CLC A:00 X:03 Y:00 P:nvUBdIzC $ACF0:7D 09 70 ADC $7009,X @ $700C = #$18 A:00 X:03 Y:00 P:nvUBdIzc $ACF3:7D 63 70 ADC $7063,X @ $7066 = #$60 A:18 X:03 Y:00 P:nvUBdIzc $ACF6:CA DEX A:78 X:03 Y:00 P:nvUBdIzc $ACF7:10 F7 BPL $ACF0 A:78 X:02 Y:00 P:nvUBdIzc $ACF0:7D 09 70 ADC $7009,X @ $700B = #$1D A:78 X:02 Y:00 P:nvUBdIzc $ACF3:7D 63 70 ADC $7063,X @ $7065 = #$60 A:95 X:02 Y:00 P:NVUBdIzc $ACF6:CA DEX A:F5 X:02 Y:00 P:NvUBdIzc $ACF7:10 F7 BPL $ACF0 A:F5 X:01 Y:00 P:nvUBdIzc $ACF0:7D 09 70 ADC $7009,X @ $700A = #$18 A:F5 X:01 Y:00 P:nvUBdIzc $ACF3:7D 63 70 ADC $7063,X @ $7064 = #$60 A:0D X:01 Y:00 P:nvUBdIzC $ACF6:CA DEX A:6E X:01 Y:00 P:nvUBdIzc $ACF7:10 F7 BPL $ACF0 A:6E X:00 Y:00 P:nvUBdIZc $ACF0:7D 09 70 ADC $7009,X @ $7009 = #$2F A:6E X:00 Y:00 P:nvUBdIZc $ACF3:7D 63 70 ADC $7063,X @ $7063 = #$60 A:9D X:00 Y:00 P:NVUBdIzc $ACF6:CA DEX A:FD X:00 Y:00 P:NvUBdIzc $ACF7:10 F7 BPL $ACF0 A:FD X:FF Y:00 P:NvUBdIzc $ACF9:48 PHA A:FD X:FF Y:00 P:NvUBdIzc $ACFA:29 07 AND #$07 A:FD X:FF Y:00 P:NvUBdIzc $ACFC:0A ASL A:05 X:FF Y:00 P:nvUBdIzc $ACFD:0A ASL A:0A X:FF Y:00 P:nvUBdIzc $ACFE:0A ASL A:14 X:FF Y:00 P:nvUBdIzc $ACFF:AA TAX A:28 X:FF Y:00 P:nvUBdIzc $AD00:A0 00 LDY #$00 A:28 X:28 Y:00 P:nvUBdIzc $AD02:BD 39 AD LDA $AD39,X @ $AD61 = #$32 A:28 X:28 Y:00 P:nvUBdIZc $AD05:99 0D 70 STA $700D,Y @ $700D = #$32 A:32 X:28 Y:00 P:nvUBdIzc $AD08:99 18 01 STA $0118,Y @ $0118 = #$00 A:32 X:28 Y:00 P:nvUBdIzc $AD0B:BD 3D AD LDA $AD3D,X @ $AD65 = #$18 A:32 X:28 Y:00 P:nvUBdIzc $AD0E:99 67 70 STA $7067,Y @ $7067 = #$18 A:18 X:28 Y:00 P:nvUBdIzc $AD11:99 8A 01 STA $018A,Y @ $018A = #$00 A:18 X:28 Y:00 P:nvUBdIzc $AD14:E8 INX A:18 X:28 Y:00 P:nvUBdIzc $AD15:C8 INY A:18 X:29 Y:00 P:nvUBdIzc $AD16:C0 04 CPY #$04 A:18 X:29 Y:01 P:nvUBdIzc $AD18:D0 E8 BNE $AD02 A:18 X:29 Y:01 P:NvUBdIzc $AD02:BD 39 AD LDA $AD39,X @ $AD62 = #$1B A:18 X:29 Y:01 P:NvUBdIzc $AD05:99 0D 70 STA $700D,Y @ $700E = #$1B A:1B X:29 Y:01 P:nvUBdIzc $AD08:99 18 01 STA $0118,Y @ $0119 = #$00 A:1B X:29 Y:01 P:nvUBdIzc $AD0B:BD 3D AD LDA $AD3D,X @ $AD66 = #$5F A:1B X:29 Y:01 P:nvUBdIzc $AD0E:99 67 70 STA $7067,Y @ $7068 = #$5F A:5F X:29 Y:01 P:nvUBdIzc $AD11:99 8A 01 STA $018A,Y @ $018B = #$00 A:5F X:29 Y:01 P:nvUBdIzc $AD14:E8 INX A:5F X:29 Y:01 P:nvUBdIzc $AD15:C8 INY A:5F X:2A Y:01 P:nvUBdIzc $AD16:C0 04 CPY #$04 A:5F X:2A Y:02 P:nvUBdIzc $AD18:D0 E8 BNE $AD02 A:5F X:2A Y:02 P:NvUBdIzc $AD02:BD 39 AD LDA $AD39,X @ $AD63 = #$0F A:5F X:2A Y:02 P:NvUBdIzc $AD05:99 0D 70 STA $700D,Y @ $700F = #$0F A:0F X:2A Y:02 P:nvUBdIzc $AD08:99 18 01 STA $0118,Y @ $011A = #$00 A:0F X:2A Y:02 P:nvUBdIzc $AD0B:BD 3D AD LDA $AD3D,X @ $AD67 = #$5F A:0F X:2A Y:02 P:nvUBdIzc $AD0E:99 67 70 STA $7067,Y @ $7069 = #$5F A:5F X:2A Y:02 P:nvUBdIzc $AD11:99 8A 01 STA $018A,Y @ $018C = #$00 A:5F X:2A Y:02 P:nvUBdIzc $AD14:E8 INX A:5F X:2A Y:02 P:nvUBdIzc $AD15:C8 INY A:5F X:2B Y:02 P:nvUBdIzc $AD16:C0 04 CPY #$04 A:5F X:2B Y:03 P:nvUBdIzc $AD18:D0 E8 BNE $AD02 A:5F X:2B Y:03 P:NvUBdIzc $AD02:BD 39 AD LDA $AD39,X @ $AD64 = #$0E A:5F X:2B Y:03 P:NvUBdIzc $AD05:99 0D 70 STA $700D,Y @ $7010 = #$0E A:0E X:2B Y:03 P:nvUBdIzc $AD08:99 18 01 STA $0118,Y @ $011B = #$00 A:0E X:2B Y:03 P:nvUBdIzc $AD0B:BD 3D AD LDA $AD3D,X @ $AD68 = #$5F A:0E X:2B Y:03 P:nvUBdIzc $AD0E:99 67 70 STA $7067,Y @ $706A = #$5F A:5F X:2B Y:03 P:nvUBdIzc $AD11:99 8A 01 STA $018A,Y @ $018D = #$00 A:5F X:2B Y:03 P:nvUBdIzc $AD14:E8 INX A:5F X:2B Y:03 P:nvUBdIzc $AD15:C8 INY A:5F X:2C Y:03 P:nvUBdIzc $AD16:C0 04 CPY #$04 A:5F X:2C Y:04 P:nvUBdIzc $AD18:D0 E8 BNE $AD02 A:5F X:2C Y:04 P:nvUBdIZC $AD1A:68 PLA A:5F X:2C Y:04 P:nvUBdIZC $AD1B:29 38 AND #$38 A:FD X:2C Y:04 P:NvUBdIzC $AD1D:AA TAX A:38 X:2C Y:04 P:nvUBdIzC $AD1E:A0 00 LDY #$00 A:38 X:38 Y:04 P:nvUBdIzC $AD20:BD 79 AD LDA $AD79,X @ $ADB1 = #$2A A:38 X:38 Y:00 P:nvUBdIZC $AD23:99 11 70 STA $7011,Y @ $7011 = #$2A A:2A X:38 Y:00 P:nvUBdIzC $AD26:99 1D 01 STA $011D,Y @ $011D = #$00 A:2A X:38 Y:00 P:nvUBdIzC $AD29:BD 7D AD LDA $AD7D,X @ $ADB5 = #$5F A:2A X:38 Y:00 P:nvUBdIzC $AD2C:99 6B 70 STA $706B,Y @ $706B = #$5F A:5F X:38 Y:00 P:nvUBdIzC $AD2F:99 8E 01 STA $018E,Y @ $018E = #$00 A:5F X:38 Y:00 P:nvUBdIzC $AD32:E8 INX A:5F X:38 Y:00 P:nvUBdIzC $AD33:C8 INY A:5F X:39 Y:00 P:nvUBdIzC $AD34:C0 04 CPY #$04 A:5F X:39 Y:01 P:nvUBdIzC $AD36:D0 E8 BNE $AD20 A:5F X:39 Y:01 P:NvUBdIzc $AD20:BD 79 AD LDA $AD79,X @ $ADB2 = #$20 A:5F X:39 Y:01 P:NvUBdIzc $AD23:99 11 70 STA $7011,Y @ $7012 = #$20 A:20 X:39 Y:01 P:nvUBdIzc $AD26:99 1D 01 STA $011D,Y @ $011E = #$00 A:20 X:39 Y:01 P:nvUBdIzc $AD29:BD 7D AD LDA $AD7D,X @ $ADB6 = #$5F A:20 X:39 Y:01 P:nvUBdIzc $AD2C:99 6B 70 STA $706B,Y @ $706C = #$5F A:5F X:39 Y:01 P:nvUBdIzc $AD2F:99 8E 01 STA $018E,Y @ $018F = #$00 A:5F X:39 Y:01 P:nvUBdIzc $AD32:E8 INX A:5F X:39 Y:01 P:nvUBdIzc $AD33:C8 INY A:5F X:3A Y:01 P:nvUBdIzc $AD34:C0 04 CPY #$04 A:5F X:3A Y:02 P:nvUBdIzc $AD36:D0 E8 BNE $AD20 A:5F X:3A Y:02 P:NvUBdIzc $AD20:BD 79 AD LDA $AD79,X @ $ADB3 = #$0E A:5F X:3A Y:02 P:NvUBdIzc $AD23:99 11 70 STA $7011,Y @ $7013 = #$0E A:0E X:3A Y:02 P:nvUBdIzc $AD26:99 1D 01 STA $011D,Y @ $011F = #$00 A:0E X:3A Y:02 P:nvUBdIzc $AD29:BD 7D AD LDA $AD7D,X @ $ADB7 = #$5F A:0E X:3A Y:02 P:nvUBdIzc $AD2C:99 6B 70 STA $706B,Y @ $706D = #$5F A:5F X:3A Y:02 P:nvUBdIzc $AD2F:99 8E 01 STA $018E,Y @ $0190 = #$00 A:5F X:3A Y:02 P:nvUBdIzc $AD32:E8 INX A:5F X:3A Y:02 P:nvUBdIzc $AD33:C8 INY A:5F X:3B Y:02 P:nvUBdIzc $AD34:C0 04 CPY #$04 A:5F X:3B Y:03 P:nvUBdIzc $AD36:D0 E8 BNE $AD20 A:5F X:3B Y:03 P:NvUBdIzc $AD20:BD 79 AD LDA $AD79,X @ $ADB4 = #$17 A:5F X:3B Y:03 P:NvUBdIzc $AD23:99 11 70 STA $7011,Y @ $7014 = #$17 A:17 X:3B Y:03 P:nvUBdIzc $AD26:99 1D 01 STA $011D,Y @ $0120 = #$00 A:17 X:3B Y:03 P:nvUBdIzc $AD29:BD 7D AD LDA $AD7D,X @ $ADB8 = #$5F A:17 X:3B Y:03 P:nvUBdIzc $AD2C:99 6B 70 STA $706B,Y @ $706E = #$5F A:5F X:3B Y:03 P:nvUBdIzc $AD2F:99 8E 01 STA $018E,Y @ $0191 = #$00 A:5F X:3B Y:03 P:nvUBdIzc $AD32:E8 INX A:5F X:3B Y:03 P:nvUBdIzc $AD33:C8 INY A:5F X:3C Y:03 P:nvUBdIzc $AD34:C0 04 CPY #$04 A:5F X:3C Y:04 P:nvUBdIzc $AD36:D0 E8 BNE $AD20 A:5F X:3C Y:04 P:nvUBdIZC $AD38:60 RTS A:5F X:3C Y:04 P:nvUBdIZC Looking at the code, it becomes obvious that failing to clear the carry flag is a likely bug. What Enix probably meant to do during its calculations is head back to $ACEF, which contains the block's only CLC, instead of the next address, $ACF0, which continues the accumulation. The human readable version follows. In my example, I named the Prince of Midenhall "Loto". The name is processed backwards, as "otoL". The procedure yields Orfeo and Gwen as my companions. Arithmetic is in hexadecimal with occasional binary. For brevity's sake, a few steps ultimately not affecting logical flow are omitted. * Set A to zero. A is the "accumulator" and performs all the math. * Set X to 3. This is used to sequentially read name characters. * Clear carry flag (for only time in the code block). * Add to A 0x18, value of character 3, "o". (A=0x18) * Add to A 0x60. (A=0x78) * Decrement X. (X=2) * Add to A 0x1D, value of character 2, "t". (A=0x95) * Add to A 0x60. (A=0xF5) * Decrement X. (X=1) * Add to A 0x18, value of character 1, "o". Trigger carry. (A=0x0D) * Add to A 0x60 plus the carry, 0x01. (A=0x6E) * Decrement X. (X=0) * Add to A 0x1D, value of character 0, "L". (A=0x9D) * Add to A 0x60. (A=0xFD) * Decrement X. (we're done) * Push A onto stack, a place where we can later access stored values. * Bitwise AND 0x07 with A (00000111 & 11111101 = 101). (A=0x05) * Arithmetic shift left A (double result). (A=0x0A) * Arithmetic shift left A (double result). (A=0x14) * Arithmetic shift left A (double result). (A=0x28) * Copy A to X. (X=0x28) * Set Y to zero. Until this point I have provided a near line-for-line translation of the assembly code. However, the remainder is short on math and long on repetitive memory copying, which can be generalized. Minus one more bitwise AND operation that determines the Princess of Moonbrooke's name, the algorithm itself is about finished. A short review before continuing: We added the values of the first four name letters, padding, and the carry or carries. We performed a bitwise AND to reduce the result to a number between 0 and 7; we needn't higher values because the built-in tables contain eight names a piece for the prince and princess. Finally, we doubled the result three times (2x2x2=8) and copied to X to use as an offset. Multiplying by eight breaks the possibilities into "chunks" spaced eight apart, which is perfect for reading against a table where entries are spaced eight bytes apart. Moving on, we load contents of address $AD39, the start location of the Prince of Cannock's name table plus our name-generated offset, previously copied into X. This will choose one of eight names and copy his name into memory one character at a time. Dragon Warrior II writes names to several locations, which makes this code block look bloated. Upon finishing writing out the Prince of Cannock's name, we come across three instructions that determine the Princess of Moonbrooke's name: * PLA pulls the value previously placed onto the stack into A. (A=0xFD) * Bitwise AND 0x38 with A (00111000 & 11111101 = 00111000) (A=0x38) * Copy A to X Next we perform the same procedure as with the Prince of Cannock's, this time at the Princess' name table, starting at $AD79. The Princess' bitwise AND operation is the inverse of the Prince's: instead of taking the lower three bits, we take the next three. Doing this allows for 64 possible name combinations. Finally, we call RTS, which exits this subroutine. ------------------------------------ *** Taking Things a Step Further *** ------------------------------------ Given our recently gained knowledge, we can create our own names for our companions in ROM. For this we'll need the services of a hex editor. I recommend XVI32: it's adequate and free. Specialized tools are available but unnecessary unless you plan to make ROM hacking a regular habit. My offsets include the iNES header. Before getting to work on the ROM, make a copy. Completely destroying the ROM with a hex editor is trivially easy. Name the copy something like "dw2-hack.nes" so you can easily differentiate it from the original. The first address we're interested in is located at $1AD49, which is the start of the Prince's name table. Now we'll need to calculate the offset in order to get us at the correct entry. If using a trace log, the value we're interested in is the first value passed to X with the TAX instruction. Otherwise we'll use our quick 'n dirty calculation method to derive the same value. Sticking with "Loto": * Add name values together: 2F + 18 + 1D + 18 = 7C * Add 180: 7C + 180 = 1FC * Add third digit to first: 1FC + 1 = 1FD * Subtract third digit: 1FD - 100 = FD * And 7: FD AND 7 = 5 This time we need to multiply the result by 8, which yields 0x28 in hexadecimal. This is our offset. To get to the correct location, simply add 0x28 to 0x1D49, giving us $1D71. Unless the offset to be added is 0, you should see "5F" immediately to the left of where ever you end up. These are padding characters to fill spaces unused by letters. You have up to eight characters to input. If your name is shorter than what's normally used by the game, pad it out with 5F. If I want to name the Prince of Cannock "Erdrick" with my main character as "Loto", I insert the following starting at $1D71, using the above name table as a reference: 28 1B 0D 1B 12 0C 14 5F. For the princess, we get the correct value at the bitwise AND step; multiplying by 8 is already "built in". Her names begin at $1AD89. So, if I want her as "Gwaelin" with the Prince of Midenhall as "Loto", we'll need an offset of 0x38 beyond $1AD89, which comes to $1ADC1. Using the name table again, we get: 2A 20 0A 0E 15 12 17 5F. Watch for mistakes! It'd be a shame to do all this work and wind up with "Erdrjck" or something. ----------------- *** Thanks to *** ----------------- * the succession of FCE -> FCEU -> FCEUX for great emulation and powerful debugging tools * 6502.org for their opcode list that allowed me to pick up 6502 in a few hours * akira slime for his Dragon Warrior I generation guide