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

Author Topic: Dragon Warrior 1, 2 & 3 Hacking Discussion  (Read 53128 times)

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #80 on: April 25, 2019, 05:43:04 pm »
Okay, really embarrassing question but I can't seem to open the file in either program you recommended. Asar seems to ONLY accept SNES roms and xkas plus seems to only accept dissembled code. Since you've said you've been using the former, I feel like I'm missing something incredibly obvious.

Asar assumes a SNES ROM and memory model by default, but you can get it to work with NES ROMs by flipping a couple of switches. Since it doesn't come with much in the way of examples, give this a try:
Quote from: test.asm
; Example NES 6502 ASM file: writes a small infinite loop.
; Put this file in the same directory as asar and execute it with e.g.
;   copy /Y nul test.bin
;   asar -nocheck test.asm test.bin
; After that, test.bin should contain 64 KB of #$00 followed by "A9 00 4C 00 80"

norom   ; stop Asar from trying to apply SNES memory mapping to this NES code
org $10010   ; set the ROM file insertion point to 0x10010
base $8000   ; set the starting RAM address to $8000

loop:
   LDA #$00
   JMP loop

Edit: Also, I thought I was getting your explanation of Read Breakpoints. I thought to find Monster Length I'd place a Read Breakpoint for Slime which the Pointer points to as memory at B718 (to avoid possible confusion I'll just say that with Chicken Knife sharing his atlas script I thought I'd use the work you guys did in moving the Item and Monster names). I figured it'd have to be CPU memory because PPU memory doesn't let me put in B718 (I assume 3ff0 is the maximum?) And yet when I try to go in to a battle with a Slime, the Debugger doesn't trip anything. And yes I made sure it's enabled before you ask :p It's an easy thing to miss, so I wouldn't blame you if you asked.
Yeah, unless you're specifically looking for graphics stuff, a CPU breakpoint is probably what you want. The original monster list was at 0x1B728 a.k.a. $06:$B718, but I moved my monster list to 0x1D050, a.k.a. $07:$9040, so if you're looking for Slime, that's where it'll be.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #81 on: April 27, 2019, 07:40:19 pm »
Asar assumes a SNES ROM and memory model by default, but you can get it to work with NES ROMs by flipping a couple of switches. Since it doesn't come with much in the way of examples, give this a try:Yeah, unless you're specifically looking for graphics stuff, a CPU breakpoint is probably what you want. The original monster list was at 0x1B728 a.k.a. $06:$B718, but I moved my monster list to 0x1D050, a.k.a. $07:$9040, so if you're looking for Slime, that's where it'll be.

I guess I figured what was there at the pointer would still work. Thanks.

Well I got the game to stop and saw
 0F:F47B:8D A0 60  STA $60A0 = #$0B

And thanks to laserlambert's testing I know that the line 1 of monster names gets cut off at 11 letters, so I figure that's GOTTA be it right? Am I right in thinking maybe this ISN'T a hardcoded value but something that's loaded in memory? I also know that the second line for monsters is limited to 9 letters which is at least 1 letter short for my new monster names and even when trying to make a breakpoint based on the Monster Line 2 pointer, I got a break but couldn't find anythign resembling a 9 letter limit. I even went BACK to DW1 and tried to recreate the steps you did in finding the length limit of HEAL. made a breakpoint and had it stop when casting and found

01:A868:AE E2 64  LDX $64E2 = #$0F

Note this is from my hack, so i figured this would have to be the new 15 letter limit for spells. If so, why does this use LDX? And how did you turn that into the ROM address of $77E9? Or am I just not looking at the right thing at all?

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #82 on: April 28, 2019, 09:21:17 am »
This sounds okay as far as it goes, but you haven't hit ROM yet, so you need to keep following the trail a bit further. Once you find the value you're looking for being read from somewhere in the $8000 - $FFFF range, then you can stop and convert the RAM address to a ROM address (/ get FCEUX to do it for you if you want).

0F:F47B:8D A0 60  STA $60A0 = #$0B
This shows that the game is about to store whatever the current value of A is to $60A0 (which was #$0B just before that instruction executed), so you'll need to find out where $60A0 became #$0B in the first place.

01:A868:AE E2 64  LDX $64E2 = #$0F
Similarly, this shows that the game is loading X with the value of $64E2, which happens to be #$0F; you'll need to find out how $64E2 became #$0F.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #83 on: May 04, 2019, 06:40:23 pm »
Asar assumes a SNES ROM and memory model by default, but you can get it to work with NES ROMs by flipping a couple of switches. Since it doesn't come with much in the way of examples, give this a try:

Sorry, I did this and ran it, it made the bin file but I'm still getting the "Not an SNES ROM Error" You might have to dumb it down even more for me. (9_6)

This sounds okay as far as it goes, but you haven't hit ROM yet, so you need to keep following the trail a bit further. Once you find the value you're looking for being read from somewhere in the $8000 - $FFFF range, then you can stop and convert the RAM address to a ROM address (/ get FCEUX to do it for you if you want).
This shows that the game is about to store whatever the current value of A is to $60A0 (which was #$0B just before that instruction executed), so you'll need to find out where $60A0 became #$0B in the first place.
Similarly, this shows that the game is loading X with the value of $64E2, which happens to be #$0F; you'll need to find out how $64E2 became #$0F.

Okay so I used trace logger to log the data from the world map to the start of a battle to the breakpoint. Still not seeing what I want. I tried to put an Execution Breakpoint on 60A0, but I don't think I'm doing it right. When doubleclicking in the debugger it just gives me "K==#00" as the "condition" and when I try to change it I get an invalid condition.

Really sorry about this. It's hard not to feel like that guy who was trying to translate DW1 into Spanish. It's frustrating to feel so clueless, but this is uncharted territory for me and I'm determined to pick up SOMETHING new for later games.

On another note, the Assembly guide you posted is really handy, thanks! It's nice to know what all those 3 letter terms mean.

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #84 on: May 15, 2019, 06:06:35 pm »
Sorry for the delay in responding, I've been offline for the past couple of weeks!

Sorry, I did this and ran it, it made the bin file but I'm still getting the "Not an SNES ROM Error" You might have to dumb it down even more for me. (9_6)
I'm not sure how much further down I can go :P. Go to the directory containing Asar, copy the sample ASM I provided into a new file named test.asm, make an empty file named test.bin, and then open a command prompt in that directory and run "asar -nocheck test.asm test.bin". Works like a charm for me.

Okay so I used trace logger to log the data from the world map to the start of a battle to the breakpoint. Still not seeing what I want. I tried to put an Execution Breakpoint on 60A0, but I don't think I'm doing it right. When doubleclicking in the debugger it just gives me "K==#00" as the "condition" and when I try to change it I get an invalid condition.
For $60A0, you'd want a write breakpoint since you're looking for places where the game writes #$0B to $60A0. Execute breakpoints fire when the code at the address you set the breakpoint for gets executed (e.g. the F47B in "0F:F47B:8D A0 60  STA $60A0 = #$0B") and read/write breakpoints fire when the address you set the breakpoint for gets modified by some code (e.g. 60A0 is being written to in "0F:F47B:8D A0 60  STA $60A0 = #$0B").

With the trace log, you don't necessarily need to set any breakpoints; they just help to reduce the size of the log file you need to look through. If I do the same thing as you with an unaltered ROM, making a trace log from the world map to the start of a battle, it's a huge file but I can search it for $B718 (the start of the monster list) to get:
Code: [Select]
        $F422:A0 00     LDY #$00                                     A:18 X:00 Y:00 S:F7 P:nvUBdIzc
        $F424:AE A0 60  LDX $60A0 = #$0B                             A:18 X:00 Y:00 S:F7 P:nvUBdIZc
        $F427:B1 57     LDA ($57),Y @ $B718 = #$36                   A:18 X:0B Y:00 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:36 X:0B Y:00 S:F7 P:nvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:36 X:0B Y:00 S:F7 P:nvUBdIzc
        $F42D:9D FF 00  STA $00FF,X @ $010A = #$5F                   A:36 X:0B Y:00 S:F7 P:nvUBdIzc
        $F430:C8        INY                                          A:36 X:0B Y:00 S:F7 P:nvUBdIzc
        $F431:CA        DEX                                          A:36 X:0B Y:01 S:F7 P:nvUBdIzc
        $F432:D0 F3     BNE $F427                                    A:36 X:0A Y:01 S:F7 P:nvUBdIzc
        $F427:B1 57     LDA ($57),Y @ $B719 = #$15                   A:36 X:0A Y:01 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:15 X:0A Y:01 S:F7 P:nvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:15 X:0A Y:01 S:F7 P:nvUBdIzc
        $F42D:9D FF 00  STA $00FF,X @ $0109 = #$5F                   A:15 X:0A Y:01 S:F7 P:nvUBdIzc
        $F430:C8        INY                                          A:15 X:0A Y:01 S:F7 P:nvUBdIzc
        $F431:CA        DEX                                          A:15 X:0A Y:02 S:F7 P:nvUBdIzc
        $F432:D0 F3     BNE $F427                                    A:15 X:09 Y:02 S:F7 P:nvUBdIzc
        $F427:B1 57     LDA ($57),Y @ $B71A = #$12                   A:15 X:09 Y:02 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:12 X:09 Y:02 S:F7 P:nvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:12 X:09 Y:02 S:F7 P:nvUBdIzc
        $F42D:9D FF 00  STA $00FF,X @ $0108 = #$5F                   A:12 X:09 Y:02 S:F7 P:nvUBdIzc
        $F430:C8        INY                                          A:12 X:09 Y:02 S:F7 P:nvUBdIzc
        $F431:CA        DEX                                          A:12 X:09 Y:03 S:F7 P:nvUBdIzc
        $F432:D0 F3     BNE $F427                                    A:12 X:08 Y:03 S:F7 P:nvUBdIzc
        $F427:B1 57     LDA ($57),Y @ $B71B = #$16                   A:12 X:08 Y:03 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:16 X:08 Y:03 S:F7 P:nvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:16 X:08 Y:03 S:F7 P:nvUBdIzc
        $F42D:9D FF 00  STA $00FF,X @ $0107 = #$5F                   A:16 X:08 Y:03 S:F7 P:nvUBdIzc
        $F430:C8        INY                                          A:16 X:08 Y:03 S:F7 P:nvUBdIzc
        $F431:CA        DEX                                          A:16 X:08 Y:04 S:F7 P:nvUBdIzc
        $F432:D0 F3     BNE $F427                                    A:16 X:07 Y:04 S:F7 P:nvUBdIzc
        $F427:B1 57     LDA ($57),Y @ $B71C = #$0E                   A:16 X:07 Y:04 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:0E X:07 Y:04 S:F7 P:nvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:0E X:07 Y:04 S:F7 P:nvUBdIzc
        $F42D:9D FF 00  STA $00FF,X @ $0106 = #$5F                   A:0E X:07 Y:04 S:F7 P:nvUBdIzc
        $F430:C8        INY                                          A:0E X:07 Y:04 S:F7 P:nvUBdIzc
        $F431:CA        DEX                                          A:0E X:07 Y:05 S:F7 P:nvUBdIzc
        $F432:D0 F3     BNE $F427                                    A:0E X:06 Y:05 S:F7 P:nvUBdIzc
        $F427:B1 57     LDA ($57),Y @ $B71D = #$FF                   A:0E X:06 Y:05 S:F7 P:nvUBdIzc
        $F429:C9 FF     CMP #$FF                                     A:FF X:06 Y:05 S:F7 P:NvUBdIzc
        $F42B:F0 07     BEQ $F434                                    A:FF X:06 Y:05 S:F7 P:nvUBdIZC
        $F434:60        RTS (from $F3FE) --------------------------- A:FF X:06 Y:05 S:F7 P:nvUBdIZC
which shows that the game is copying data from $B718-$B71D to $010A-$0106 (stored backwards) until it reads a #$FF (monster name end token) or X reaches #$00, and that X was set based on $60A0.

Spoiler:
As a side note, a little further down, you'll see the game copies the monster name from $00FF,X to $6119,Y, where it will eventually get used by the [name] control code:
Code: [Select]
      $FCE8:AE A0 60  LDX $60A0 = #$0B                             A:FF X:06 Y:00 S:F9 P:nvUBdIZc
      $FCEB:BD FF 00  LDA $00FF,X @ $010A = #$36                   A:FF X:0B Y:00 S:F9 P:nvUBdIzc
      $FCEE:99 19 61  STA $6119,Y @ $6119 = #$25                   A:36 X:0B Y:00 S:F9 P:nvUBdIzc
      $FCF1:C8        INY                                          A:36 X:0B Y:00 S:F9 P:nvUBdIzc
      $FCF2:CA        DEX                                          A:36 X:0B Y:01 S:F9 P:nvUBdIzc
      $FCF3:D0 F6     BNE $FCEB                                    A:36 X:0A Y:01 S:F9 P:nvUBdIzc
...

Searching backwards in the trace log for $60A0, the very first result is this:
Code: [Select]
     $FC92:A9 0B     LDA #$0B                                     A:00 X:00 Y:00 S:FA P:nvUBdIZc
     $FC94:8D A0 60  STA $60A0 = #$01                             A:0B X:00 Y:00 S:FA P:nvUBdIzc
So $60A0 got its value from A, and A got its value set based on $FC93 (the #$0B part of "LDA #$0B"), which unlike $60A0 comes from ROM i.e. 0x3FCA3. Ta-da!

With that as a guide, see if you can find where the maximum length of the second "line" of monster names in the main dialogue box is set (hint: it's #$09 and it's not too far away from where the maximum length of the first "line" is set), and then see if you can track down where the lengths for each of the two lines in the monster menu list get set (hint: same values as the dialogue box lengths, but set in a different area of the code; they'll still be in your trace log, though).

Really sorry about this. It's hard not to feel like that guy who was trying to translate DW1 into Spanish. It's frustrating to feel so clueless, but this is uncharted territory for me and I'm determined to pick up SOMETHING new for later games.

On another note, the Assembly guide you posted is really handy, thanks! It's nice to know what all those 3 letter terms mean.
Yeah, if you're not used to this kind of thing, it can take a while to really sink in. Just keep at it and you'll get the hang of it sooner or later!

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #85 on: May 18, 2019, 07:11:35 am »
Hey! Glad to see your back and that you're okay! I was genuinely worried for a bit there that something bad might've happened that would've taken you out of the picture. While I'm sure I could've found help, you're a cool guy and it would've been a bummer to not be able to finish this while learning how to do it on my own. But anyway...

I'm not sure how much further down I can go :P. Go to the directory containing Asar, copy the sample ASM I provided into a new file named test.asm, make an empty file named test.bin, and then open a command prompt in that directory and run "asar -nocheck test.asm test.bin". Works like a charm for me.

I wonder if it's a Windows thing, are you on 10? When I try to run that very same command from the command line, it seems to work for a second but just takes me back to the command line with a modified test.bin and trying to run asar again just gives me the usual.


Searching backwards in the trace log for $60A0, the very first result is this:
Code: [Select]
     $FC92:A9 0B     LDA #$0B                                     A:00 X:00 Y:00 S:FA P:nvUBdIZc
     $FC94:8D A0 60  STA $60A0 = #$01                             A:0B X:00 Y:00 S:FA P:nvUBdIzc
So $60A0 got its value from A, and A got its value set based on $FC93 (the #$0B part of "LDA #$0B"), which unlike $60A0 comes from ROM i.e. 0x3FCA3. Ta-da!

With that as a guide, see if you can find where the maximum length of the second "line" of monster names in the main dialogue box is set (hint: it's #$09 and it's not too far away from where the maximum length of the first "line" is set), and then see if you can track down where the lengths for each of the two lines in the monster menu list get set (hint: same values as the dialogue box lengths, but set in a different area of the code; they'll still be in your trace log, though).

So on one hand I DID find the second line monster value of 9 at 3FCBF, though I'm not sure how you turned FC93 to 3FCA3. I mean yeah you added 30010 but where did THAT come from? It doesn't quite match up with what you were talking about RAM to ROM addresses on the last page.

And I made a honest effort, but I can't seem to find what you're talking about for the Monster List window. I DID find the subroutine FCE8 in my trace log and while trying to understand it still makes my eyes go @_@ I can understand enough that there's two sections concerning whether or not the Monster needs that second line printed in the window. And I can see that it loads the value as X as opposed to A in the main dialog window. But can't seem to find anything in my log about the value being stored in 60A0.
« Last Edit: May 18, 2019, 08:03:33 am by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #86 on: May 18, 2019, 12:57:54 pm »
Hey! Glad to see your back and that you're okay! I was genuinely worried for a bit there that something bad might've happened that would've taken you out of the picture. While I'm sure I could've found help, you're a cool guy and it would've been a bummer to not be able to finish this while learning how to do it on my own. But anyway...
Yeah, every now and then I go offline for a couple of weeks for IRL stuff, though one time it was for an entire year!

I wonder if it's a Windows thing, are you on 10? When I try to run that very same command from the command line, it seems to work for a second but just takes me back to the command line with a modified test.bin and trying to run asar again just gives me the usual.
I'm actually on Windows 7 (cuz eww 8 and 10), but if you're getting a modified test.bin, then it sounds like Asar is working. Try changing test.asm and see if you get a different test.bin.

So on one hand I DID find the second line monster value of 9 at 3FCBF,
Nice job!

though I'm not sure how you turned FC93 to 3FCA3. I mean yeah you added 30010 but where did THAT come from? It doesn't quite match up with what you were talking about RAM to ROM addresses on the last page.
If the Trace Logger included bank number, $FC93 would show up as $0F:$FC93, and $0F * $4000 - $8000 - $01 * $4000 + $FC93 + $10 = $3FCA3 (i.e. <ROM bank number> * <bank size> - <base RAM-to-ROM offset> - <RAM bank number> * <bank size> + <RAM address> + <iNES header size>). Or find $FC93 in the Hex Editor -> right click -> Go Here In ROM File.

And I made a honest effort, but I can't seem to find what you're talking about for the Monster List window. I DID find the subroutine FCE8 in my trace log and while trying to understand it still makes my eyes go @_@
Ah, $FCE8's not so bad :P. When you're trying to wrap your head around a block of code, remember that the Debugger and Trace Logger give you two different views of the same thing; sometimes it's easier to understand what's going on when looking at one instead of the other. Here's the basic code you'll see in the Debugger:
Code: [Select]
0F:FCE8:AE A0 60 LDX $60A0
0F:FCEB:BD FF 00 LDA $00FF,X
0F:FCEE:99 19 61 STA $6119,Y
0F:FCF1:C8      INY
0F:FCF2:CA      DEX
0F:FCF3:D0 F6    BNE $FCEB
0F:FCF5:60      RTS

and here's a commented version:
Spoiler:
Code: [Select]
; copy $60A0 bytes of data from $00FF,X to $6119,Y
; X is used as a read index, Y as a write index
; data gets copied in reverse order
; IN:
; A/X/C = irrelevant
; Y = current write index
; OUT:
; A = last byte copied (but calling code doesn't care)
; X = 0
; Y = current write index; this is important since the calling code needs to remember the write index from the first segment when dealing with the second segment
; C = unchanged
; control flow target (from $FC9D, $FCBA)
0x03FCF8|$0F:$FCE8:AE A0 60 LDX $60A0 ; initialize the read index to the value of $60A0
; control flow target (from $FCF3)
0x03FCFB|$0F:$FCEB:BD FF 00 LDA $00FF,X ; read data from $00FF,X
0x03FCFE|$0F:$FCEE:99 19 61 STA $6119,Y ; write data to $6119,Y
0x03FD01|$0F:$FCF1:C8      INY ; increment write index
0x03FD02|$0F:$FCF2:CA      DEX ; decrement read index
0x03FD03|$0F:$FCF3:D0 F6    BNE $FCEB ; if the read index is not 0, loop back to $FCEB
0x03FD05|$0F:$FCF5:60      RTS ; otherwise the read index is 0, so we're done

I can understand enough that there's two sections concerning whether or not the Monster needs that second line printed in the window. And I can see that it loads the value as X as opposed to A in the main dialog window. But can't seem to find anything in my log about the value being stored in 60A0.
If you keep looking for reads on $B718, you should notice that the game scans through the monster name list a few times while starting a battle; the last one is for the monster list menu (you can also easily isolate this one by starting a trace log just before pressing FIGHT, as the monster menu gets redrawn after that point). At the spot where the breakpoint fires, you'll be in the same block of code as for the main dialogue window, but coming from a different place (the stack will show something like FA,F3,C5,EF,..., which means the last JSR before you got to this code ended at $F3FA [so started at $F3F8], and the JSR before that ended at $EFC5 [$EFC3]). Searching backwards for $60A0 from there should quickly get you to:
Code: [Select]
              $EFA9:A9 0B     LDA #$0B                                     A:00 X:18 Y:07 S:F1 P:nvUBdIZc
              $EFAB:8D A0 60  STA $60A0 = #$00                             A:0B X:18 Y:07 S:F1 P:nvUBdIzc
and searching forwards will eventually (after a long series of other uses for $60A0) get you the maximum length of the second line too (or if you look in the Debugger, the code for handling the second line of monster names is only a few lines of ASM away from the code for handling the first line).

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #87 on: June 13, 2019, 09:43:40 pm »
Okay, so first of all, sorry for the delay. I mean yeah I work but a big reason is I just got nice CPU upgrade so I've been finally able to play DQXI among other things, and I think the last time I looked at this (about a week ago) my brain was like "Nope, not today..." but the Smash reveal made me go... "yeah I need to get back to this." If anything I'm just eager to get to 3 and finish the NES Erdrick trilogy at the very very least.

Anyway. Good news is I not only figured out the monster name menu length (though to your credit, you made it pretty easy in your last post) but I ALSO got the spell length for dialog.


(yeah I swapped out Heal for Holy Protection as a quick way to test)

I'm not sure if I want to mess with the menu length and keep it abbreviated like I did DW1 (because I know unlike DW1 not only the spell menus are done differently, but there are many more long spell names too). Otherwise that's all taken care of.

Bad news it, and I'm so sorry, but the ASM stuff is still stumping me. More, the asar usage than anything else.
I'm actually on Windows 7 (cuz eww 8 and 10), but if you're getting a modified test.bin, then it sounds like Asar is working. Try changing test.asm and see if you get a different test.bin.

Is the bin file supposed to be viewable in text form? Because opening it up in Notepad+ just gives me junk so I have no idea what to look for.

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #88 on: June 14, 2019, 09:21:41 am »
Okay, so first of all, sorry for the delay. I mean yeah I work but a big reason is I just got nice CPU upgrade so I've been finally able to play DQXI among other things, and I think the last time I looked at this (about a week ago) my brain was like "Nope, not today..." but the Smash reveal made me go... "yeah I need to get back to this." If anything I'm just eager to get to 3 and finish the NES Erdrick trilogy at the very very least.
Heh, I hear DQXI is a leading cause of delay among DQ NES hackers ;).

Anyway. Good news is I not only figured out the monster name menu length (though to your credit, you made it pretty easy in your last post) but I ALSO got the spell length for dialog.
Congrats! It sounds like you must be getting close to finishing with this game - what's still left?

Bad news it, and I'm so sorry, but the ASM stuff is still stumping me. More, the asar usage than anything else.
Is the bin file supposed to be viewable in text form? Because opening it up in Notepad+ just gives me junk so I have no idea what to look for.
Just as viewable as any other ROM, i.e. not very :P. Like I said earlier, that sample ASM file should generate a file with 64 KB of zero bytes followed by the bytes "A9 00 4C 00 80", so open it up in a hex editor, scroll to the very bottom, and if you see those bytes, then it's working.

For real world usage, you'd want to adjust the org/base values to the ROM/RAM addresses you want to write to, replace the useless infinite loop ASM I concocted for the sample with whatever code you actually want to insert, and then run it against a real ROM instead of an empty file.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #89 on: June 21, 2019, 09:45:23 pm »
Heh, I hear DQXI is a leading cause of delay among DQ NES hackers ;).

The funny thing about playing XI while working on II is spotting the references. The Puff Puff girl in Gondolia says the same thing as the girl in Lianport/Rippleport word for word from the mobile version. That was a real A-ha moment for me and I'm hoping doing these script ports more people will be able to see that.

Quote
Congrats! It sounds like you must be getting close to finishing with this game - what's still left?

Honestly outside fixing the buggy  plural s and of course the monster name ASM, just need to edit the uncompressed Prologue text and get the new graphics from Chicken Knife's hack I'll be done. I have the new menus ready to go for insertion.

Speaking of A-Ha moment, I finally get how asar works. Man I feel dumb. I was expecting some kind of fancy interface like PS2Dis or something where you can just edit the lines of code as you go.

Am I right in thinking I could just copy the Pluralization rules from the Wiki into the test.asm (replace the loop code) file but change org to $01C805 (code where it starts to check monster count) and base to $4000 (?) and then just "revise" the code to my liking and then run "asar -nocheck test.asm (DW2 rom)" Is that what you do?

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #90 on: June 22, 2019, 04:46:25 pm »
Speaking of A-Ha moment, I finally get how asar works. Man I feel dumb. I was expecting some kind of fancy interface like PS2Dis or something where you can just edit the lines of code as you go.
Ah, yeah, it's not that fancy, alas. Quite possibly there are better assembler options out there; Asar is just the one I'm used to and it hasn't yet irritated me enough to go looking for alternatives.

Am I right in thinking I could just copy the Pluralization rules from the Wiki into the test.asm (replace the loop code) file but change org to $01C805 (code where it starts to check monster count) and base to $4000 (?) and then just "revise" the code to my liking and then run "asar -nocheck test.asm (DW2 rom)" Is that what you do?
Sort of. You'll want to set the base value (RAM address) to $87F5 and then trim out the non-ASM ROM address, RAM address, and assembled code bytes from the wiki, leaving just the opcodes and data bytes (and probably the comments, because why not?). Unless you can manage to keep the byte counts between control flow targets identical to the original code or enjoy manually counting bytes and updating lots of pointers every time you make a change, you will also want to convert the control flow addresses into labels and use those, so it'll look something like this:
Code: [Select]
LDY $8F ; number of monsters in the current group
DEY
BEQ done ; if only 1 monster, then no need to pluralize, so we're done
DEX ; back up to [end-FA]
DEX ; back up to final letter of monster name
LDA $60F1,X ; read final letter of monster name
CMP #$18 ; "o"
BEQ o_handler ; -ngo -> -ngo, -o -> -os
CMP #$0F ; "f"
BEQ f_handler ; -f -> -ves (not used)
CMP #$22 ; "y"
BEQ y_handler ; -y -> -ies
CMP #$12 ; "i"
BEQ i_handler ; -i -> -ies
CMP #$1C ; "s"
BEQ s_handler ; -rus -> -rii, -s -> -ses
CMP #$11 ; "h"
BEQ h_handler ; -ch -> -ches, -sh -> -shes, -h -> -hs
CMP #$17 ; "n"
BEQ n_handler ; -man -> -men, -Man -> -Men, -n -> -ns
CMP #$0E ; "e"
BEQ e_handler ; -mouse -> -mice, -Mouse -> -Mice, -e -> es
CMP #$0D ; "d"
BEQ d_handler ; -dead -> -dead, -d -> -ds
; control flow target (from $883A, $8841, $8863, $8884, $888F, $889D, $88E1)
; append "s" to monster name
; default pluralization if not handled above
add_s:
INX
LDA #$1C ; "s"
STA $60F1,X ; append "s" to monster name
INX
LDA #$FA ; [end-FA]
STA $60F1,X ; append [end-FA] to monster name
INX
; control flow target (from $87F8, $8843)
done:
SEC
RTS

o_handler:
...

Keep in mind that other unrelated code starts at $88E4, so make sure not to overwrite that; fortunately bank 7 is mostly empty, so if you need more space, you can JMP $8C13 and keep going from there.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #91 on: June 25, 2019, 01:31:06 pm »
Okay, so, here it is!

NOTE: I'm keeping addresses and bytes here for referential purposes. I'm well aware from your last post that these should be removed for insertion.



Code: [Select]
LDY $8F ; number of monsters in the current group
DEY
BEQ done ; if only 1 monster, then no need to pluralize, so we're done
DEX ; back up to [end-FA]
DEX ; back up to final letter of monster name
LDA $60F1,X ; read final letter of monster name
CMP #$0F ; "f"
BEQ $885E ; -f -> -ves (not used)
CMP #$22 ; "y"
BEQ $8874 ; -y -> -ies
CMP #$12 ; "i"
BEQ $8863 ; -i -> -ies
CMP #$1C ; "s"
BEQ $8835 ; -rus -> -rii, -s -> -ses
CMP #$11 ; "h"
BEQ $886B ; -ch -> -ches, -sh -> -shes, -h -> -hs
CMP #$17 ; "n"
BEQ $889C ; -man -> -men, -Man -> -Men, -n -> -ns
CMP #$0A ; "a"
BEQ e_handler ; Madusa -> Madusae
CMP #$1B ; "r"
BEQ d_handler ; Man O' War -> Men O' War
; control flow target (from $883A, $8841, $8863, $8884, $888F, $889D, $88E1)
; append "s" to monster name
; default pluralization if not handled above
add_s:
INX
LDA #$1C ; "s"
STA $60F1,X ; append "s" to monster name
INX
LDA #$FA ; [end-FA]
STA $60F1,X ; append [end-FA] to monster name
INX
; control flow target (from $87F8, $8843)
done:
SEC
RTS

; -s pluralization handler: Cyclops, Gigantes, and Atlas don't change, Magus changes to Magi otherwise add es
$8835:  LDA $60F0,X ; read second-last letter of monster name
$8838:  CMP #$0E ; "e"
$883A:  BEQ $8830 ; if -es, singular=plural
$883C:  CMP #$0A ; "a"
$883F:  BEQ $8830 ; if -as, singular=plural
$8841:  CMP #$19 ; "p"
$8843:  BEQ $8830 ; if -ps, singular=plural
$8845:  LDA $60EF,X ; read third-last letter of monster name
$8848:  CMP #$10 ; "g"
$884A:  BEQ $8855   ; Shortcut here, if g_s (Magus) replace us with i
$884C:  BNE $885D ; If not either Cyclops or Atlas (or Magus), add -es

; append "es" to monster name
$884E:E8      INX
$884F:A9 0E    LDA #$0E ; "e"
$8851:9D F1 60 STA $60F1,X ; append "e" to monster name
$8854:D0 BE    BNE $8823 ; append "s" to monster name; note that this branch is always taken



$8856:  STA $60F0,X ; replace -us with -ii (how do I change this to replace -us to -i?)
$8859:  STA $60F1,X
$885C:  SEC
$885D: RTS

; -f pluralization handler: -f -> -ves (no need to have this, but if there's space, might keep it for possible hacks)
$885E:A9 1F    LDA #$1F ; "v"
$8860:4C 6C 88 JMP $886C ; replace "f" with "v" then append "es"


; -i pluralization handler: -i -> -ies (same as above)
$8863:A9 12    LDA #$12 ; "i"
; unused control flow target (from $8867)
$8865:9D F1 60 STA $60F1,X ; replace final letter with "i"
$8868:4C 5D 88 JMP $884E ; append "es"

; -h pluralization handler: -ch -> -ches, -sh -> -shes, -h -> -hs (no longer need ch, keeps Mech as Mechs)
$886B:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
$886E:C9 1C    CMP #$1C ; "s"
$8870:F0 E0    BEQ $885D ; if -sh, append "es"
$8872:D0 A4    BNE $8823 ; else, append "s"

; -y pluralization handler: like -i, except needs exceptions for boy-boys and dragonfry-no change
$8874 LDA $60F0,X ; read second-last letter of monster name
$8877 CMP #$18 ; "o"
$8879 BEQ $8823 ; if -oy, append "s"
$887B CMP #$18 ; "r"
$887D BEQ $8830       ; if -ry, no change
$887F BNE $886C       ; otherwise replace y with -ies

; -a pluralization handler: needed for madusa -> madusae
$8881 LDA $60F0,X ; read second-last letter of monster name
$8884 CMP #$1C ; "s"
$8886 BEQ             ; if -sa add "e"
$8888 BNE $8823       ; if not -sa append "s"

;adding "e"
$888A INX
$888B LDA #$0E ; "e"
$888D STA $60F1,X ; append "e" to monster name
$8890 JMP 8829

; -r pluralization handler: needed for man o' war
$8893 LDA $60E9,X     ; read ninth from end letter of monster name
$8895 CMP #$0A ; "a"
$8897 BNE $8823       ; if not "a" append "s"
$8899 STA $60E9,X     ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?

; -n pluralization handler: -man -> -men, -Man -> -Men, -n -> -ns
$889C:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
$889F:C9 0A    CMP #$0A ; "a"
$88A1:D0 9D    BNE $8823 ; if not -an, append "s"
$88A3:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
$88A6:C9 16    CMP #$16 ; "m"
$88A8:F0 04    BEQ $8891 ; -man -> -men
$88AA:C9 30    CMP #$30 ; "M"
$88AC:D0 92    BNE $8823 ; if not -Man, append "s"
; control flow target (from $888B)
$88AE:A9 0E    LDA #$0E ; "e"
$88B0:9D F0 60 STA $60F0,X ; replace second-last letter of monster name
; control flow target (from $88DF)
$88B3:38      SEC
$88B4:60      RTS

Not neading the -dead or -mouse codes freed up a bunch of space. So much so, I thought I'd just keep some of the extra codes I didn't necessarily need like f-ves or i-ies in case someone wants to use my script port as a base for a hack that needs new monster names.

I just had a couple of confused points. I'm not quite sure how the replace text code works so I'm a little stumped at changing the old -us to -ii code to just -us to -i (Magus to Magi)

Code: [Select]
$8856:  STA $60F0,X ; replace -us with -ii (how do I change this to replace -us to -i?)
$8859:  STA $60F1,X
$885C:  SEC
$885D: RTS

and I just wanted to run my Man O' War to Men O' War code by you

Code: [Select]
; -r pluralization handler: needed for man o' war
$8893 LDA $60E9,X     ; read ninth from end letter of monster name
$8895 CMP #$0A ; "a"
$8897 BNE $8823       ; if not "a" append "s"
$8899 STA $60E9,X     ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #92 on: June 25, 2019, 08:39:22 pm »
I just had a couple of confused points. I'm not quite sure how the replace text code works so I'm a little stumped at changing the old -us to -ii code to just -us to -i (Magus to Magi)

Code: [Select]
$8856:  STA $60F0,X ; replace -us with -ii (how do I change this to replace -us to -i?)
$8859:  STA $60F1,X
$885C:  SEC
$885D: RTS
There's nothing magic going on here; try setting an execute breakpoint at $8853, getting into a fight with some Magic Vampirii (or temporarily rename e.g. Slime to Slrus and get into a fight with some of those), and step through the code, watching what happens around $60F1 in the Hex Editor.

Does this make it any clearer?
Spoiler:
Code: [Select]
0x01C863|$07:$8853:A9 12    LDA #$12 ; "i"
0x01C865|$07:$8855:9D F0 60 STA $60F0,X ; replace the second-last letter ("u") with "i"
0x01C868|$07:$8858:9D F1 60 STA $60F1,X ; replace the last letter ("s") with "i"
0x01C86B|$07:$885B:38      SEC ; let calling code know to read a #$FA-terminated string from $60F1 instead of a single byte from A
0x01C86C|$07:$885C:60      RTS

and I just wanted to run my Man O' War to Men O' War code by you

Code: [Select]
; -r pluralization handler: needed for man o' war
$8893 LDA $60E9,X     ; read ninth from end letter of monster name
$8895 CMP #$0A ; "a"
$8897 BNE $8823       ; if not "a" append "s"
$8899 STA $60E9,X     ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?
Close, but as it's written that code will still end pluralizing Man O' War to Man O' War, since it takes the ninth-last letter and writes it to the ninth-last letter; try doing "LDA #$0E" before the "STA $60E9,X".

Once you've finished labelling the control flow targets, try assembling and inserting it! Your code is definitely shorter than the original (and way shorter than mine for Latin!), so this probably won't be an issue, but just in case, keep in mind that all those branches use a 1-byte signed displacement from the end of the operand, which basically means if you need to move farther than -127/+128 bytes, you'll have to use a JMP instead. Assuming that works, it's time to test it out - here's hoping the game doesn't crash on you :D.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #93 on: June 26, 2019, 09:42:21 pm »
There's nothing magic going on here; try setting an execute breakpoint at $8853, getting into a fight with some Magic Vampirii (or temporarily rename e.g. Slime to Slrus and get into a fight with some of those), and step through the code, watching what happens around $60F1 in the Hex Editor.

Does this make it any clearer?
Spoiler:
Code: [Select]
0x01C863|$07:$8853:A9 12    LDA #$12 ; "i"
0x01C865|$07:$8855:9D F0 60 STA $60F0,X ; replace the second-last letter ("u") with "i"
0x01C868|$07:$8858:9D F1 60 STA $60F1,X ; replace the last letter ("s") with "i"
0x01C86B|$07:$885B:38      SEC ; let calling code know to read a #$FA-terminated string from $60F1 instead of a single byte from A
0x01C86C|$07:$885C:60      RTS
Close, but as it's written that code will still end pluralizing Man O' War to Man O' War, since it takes the ninth-last letter and writes it to the ninth-last letter; try doing "LDA #$0E" before the "STA $60E9,X".

Once you've finished labelling the control flow targets, try assembling and inserting it! Your code is definitely shorter than the original (and way shorter than mine for Latin!), so this probably won't be an issue, but just in case, keep in mind that all those branches use a 1-byte signed displacement from the end of the operand, which basically means if you need to move farther than -127/+128 bytes, you'll have to use a JMP instead. Assuming that works, it's time to test it out - here's hoping the game doesn't crash on you :D.

First of all, really smacking my forehead at the obvious lack of a LDA command for some of these. I think I forgot to copy that line over for the Wiki but also, it's really easy for me to overlook something obvious.  :crazy:

Not sure what I did, but my first time seemed to work okay aside from a couple of mistakes, but now after checking my Jump/Branch values I seem to have made it worse. A lot of my test names tend to show one or two letters like "Three y appeared" instead of two "Iron Dragonfry appeared"



I was able to parse your example asm script above, filling in the byte values appropriately, but I did change stuff like done: and add_s: assuming those were meant to be comments. Did I mess somethign up there?

This is my current script as it's being inserted (also yeah I should have known base meant was a RAM address. Here I thought it was some kind of hardware value that needed to be changed to something signifying NES hardware instead of SNES hardware. Live and learn.

Code: [Select]
norom   ; stop Asar from trying to apply SNES memory mapping to this NES code
org $01C805   ; set the ROM file insertion point to 0x10010
base $87F5   ; set the starting RAM address to $8000

LDY $8F ; number of monsters in the current group
DEY
BEQ $882C ; if only 1 monster, then no need to pluralize, so we're done
DEX ; back up to [end-FA]
DEX ; back up to final letter of monster name
LDA $60F1,X ; read final letter of monster name
CMP #$0F ; "f"
BEQ $8856 ; -f -> -ves (not used)
CMP #$22 ; "y"
BEQ $886C ; -y -> -ies
CMP #$12 ; "i"
BEQ $885B ; -i -> -ies
CMP #$1C ; "s"
BEQ $882E ; -rus -> -rii, -s -> -ses
CMP #$11 ; "h"
BEQ $8863 ; -ch -> -ches, -sh -> -shes, -h -> -hs
CMP #$17 ; "n"
BEQ $8899 ; -man -> -men, -Man -> -Men, -n -> -ns
CMP #$0A ; "a"
BEQ $887A ; Madusa -> Madusae
CMP #$1B ; "r"
BEQ $888C ; Man O' War -> Men O' War
; control flow target (from $883A, $8841, $8863, $8884, $888F, $889D, $88E1)
; append "s" to monster name
; default pluralization if not handled above
; add_s:
INX
LDA #$1C ; "s"
STA $60F1,X ; append "s" to monster name
INX
LDA #$FA ; [end-FA]
STA $60F1,X ; append [end-FA] to monster name
INX
; control flow target (from $87F8, $8843)
; done:
SEC
RTS

; -s pluralization handler: Cyclops, Gigantes, and Atlas don't change, Magus changes to Magi otherwise add es
LDA $60F0,X ; read second-last letter of monster name
CMP #$0E ; "e"
BEQ $882C ; if -es, singular=plural
CMP #$0A ; "a"
BEQ $882C ; if -as, singular=plural
CMP #$19 ; "p"
BEQ $882C ; if -ps, singular=plural
LDA $60EF,X ; read third-last letter of monster name
CMP #$10 ; "g"
BEQ $884E   ; Shortcut here, if g_s (Magus) replace us with i
BNE $8846 ; If not either Cyclops or Atlas (or Magus), add -es

; append "es" to monster name
INX
LDA #$0E ; "e"
STA $60F1,X ; append "e" to monster name
BNE $881F ; append "s" to monster name; note that this branch is always taken

; replace us with i
LDA #$12    ; "i"
STA $60F0,X ; replace -us with -ii (how do I change this to replace -us to -i?)
SEC
RTS

; -f pluralization handler: -f -> -ves (no need to have this, but if there's space, might keep it for possible hacks)
LDA #$1F ; "v"
JMP $885D ; replace "f" with "v" then append "es"


; -i pluralization handler: -i -> -ies (same as above)
LDA #$12 ; "i"
; unused control flow target (from $8867)
STA $60F1,X ; replace final letter with "i"
JMP $8846 ; append "es"

; -h pluralization handler: -ch -> -ches, -sh -> -shes, -h -> -hs (no longer need ch, keeps Mech as Mechs)
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ $8846 ; if -sh, append "es"
BNE $881F ; else, append "s"

; -y pluralization handler: like -i, except needs exceptions for boy-boys and dragonfry-no change
LDA $60F0,X ; read second-last letter of monster name
CMP #$18 ; "o"
BEQ $881F ; if -oy, append "s"
CMP #$1B ; "r"
BEQ $882C       ; if -ry, no change
BNE $885D      ; otherwise replace y with -ies

; -a pluralization handler: needed for madusa -> madusae
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ $8883   ; if -sa add "e"
BNE $881F       ; if not -sa append "s"

;adding "e"
INX
LDA #$0E ; "e"
STA $60F1,X ; append "e" to monster name
JMP $8825

; -r pluralization handler: needed for man o' war
LDA $60E9,X     ; read ninth from end letter of monster name
CMP #$0A       ; "a"
BNE $881F       ; if not "a" append "s"
LDA #$0E        ; "e"
STA $60E9,X     ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?

; -n pluralization handler: -man -> -men, -Man -> -Men, -n -> -ns
LDA $60F0,X ; read second-last letter of monster name
CMP #$0A ; "a"
BNE $881F ; if not -an, append "s"
LDA $60EF,X ; read third-last letter of monster name
CMP #$16 ; "m"
BEQ $88AB   ; -man -> -men
CMP #$30 ; "M"
BNE $881F ; if not -Man, append "s"
; control flow target (from $888B)
LDA #$0E ; "e"
STA $60F0,X ; replace second-last letter of monster name
; control flow target (from $88DF)
SEC
RTS
« Last Edit: June 26, 2019, 09:55:12 pm by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #94 on: June 27, 2019, 04:56:07 pm »
First of all, really smacking my forehead at the obvious lack of a LDA command for some of these. I think I forgot to copy that line over for the Wiki but also, it's really easy for me to overlook something obvious.  :crazy:
Yeah, you'll probably make all sorts of little mistakes on your first few attempts. It's especially bad if you're like me and have a bad habit of thinking one thing but typing another :P.

Not sure what I did, but my first time seemed to work okay aside from a couple of mistakes, but now after checking my Jump/Branch values I seem to have made it worse. A lot of my test names tend to show one or two letters like "Three y appeared" instead of two "Iron Dragonfry appeared"
When writing ASM, labels are your friends, they get sad if you exclude them :P. It's basically the same idea as pointers when inserting a script: let the computer handle all the boring tedious address calculations for you; that's what computers are good at. Additionally, if you check the assembled code, branches are probably not getting assembled the way you think they are. E.g. that "BEQ $886C" actually ends up as "F0 6C", i.e. branch ahead $2C bytes, or "BEQ $8873", which happens to be right in the middle of "CMP #$1B", which is almost never a good idea, especially since 1B isn't a valid 6502 opcode. Labels don't have that problem.

Try something like this instead (not really tested):
Code: [Select]
norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $01C805 ; set the ROM file insertion point
base $87F5 ; set the starting RAM address

LDY $8F ; number of monsters in the current group
DEY
BEQ done ; if only 1 monster, then no need to pluralize, so we're done
DEX ; back up to [end-FA]
DEX ; back up to final letter of monster name
LDA $60F1,X ; read final letter of monster name
CMP #$22 ; "y"
BEQ _y ; -y -> -ies
CMP #$12 ; "i"
BEQ _i ; -i -> -ies
CMP #$1C ; "s"
BEQ _s ; -rus -> -rii, -s -> -ses
CMP #$11 ; "h"
BEQ _h ; -ch -> -ches, -sh -> -shes, -h -> -hs
CMP #$17 ; "n"
BEQ _n ; -man -> -men, -Man -> -Men, -n -> -ns
CMP #$0A ; "a"
BEQ _a ; Madusa -> Madusae
CMP #$1B ; "r"
BEQ _r ; Man O' War -> Men O' War
; append "s" to monster name
; default pluralization if not handled above
append_s:
INX
LDA #$1C ; "s"
set_final_letter:
STA $60F1,X
INX
LDA #$FA ; [end-FA]
STA $60F1,X ; append [end-FA] to monster name
INX
done:
SEC
RTS

_s:
; -s pluralization handler: Cyclops, Gigantes, and Atlas don't change, Magus changes to Magi otherwise add es
LDA $60F0,X ; read second-last letter of monster name
CMP #$0E ; "e"
BEQ done ; if -es, singular=plural
CMP #$0A ; "a"
BEQ done ; if -as, singular=plural
CMP #$19 ; "p"
BEQ done ; if -ps, singular=plural
LDA $60EF,X ; read third-last letter of monster name
CMP #$10 ; "g"
BEQ _us ; Shortcut here, if g_s (Magus) replace us with i
; If not either Cyclops or Atlas (or Magus), add -es
append_es:
; append "es" to monster name
INX
LDA #$0E ; "e"
STA $60F1,X ; append "e" to monster name
BNE append_s ; append "s" to monster name; note that this branch is always taken

_us:
; replace "us" with "i"
DEX ; shorten string by 1 letter
LDA #$12 ; "i"
BNE set_final_letter

_i:
; -i pluralization handler: -i -> -ies
LDA #$12 ; "i"
STA $60F1,X ; replace final letter with "i"
BNE append_es ; append "es"

_h:
; -h pluralization handler: -ch -> -ches, -sh -> -shes, -h -> -hs (no longer need ch, keeps Mech as Mechs)
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ append_es ; if -sh, append "es"
BNE append_s ; else, append "s"

_y:
; -y pluralization handler: like -i, except needs exceptions for boy-boys and dragonfry-no change
LDA $60F0,X ; read second-last letter of monster name
CMP #$18 ; "o"
BEQ append_s ; if -oy, append "s"
CMP #$1B ; "r"
BEQ done ; if -ry, no change
BNE _i ; otherwise replace y with -ies

_a:
; -a pluralization handler: needed for madusa -> madusae
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ append_e ; if -sa add "e"
BNE append_s ; if not -sa append "s"

append_e:
; adding "e"
INX
LDA #$0E ; "e"
BNE set_final_letter

_r:
; -r pluralization handler: needed for man o' war
LDA $60E9,X ; read ninth from end letter of monster name
CMP #$0A ; "a"
BNE append_s ; if not "a" append "s"
LDA #$0E ; "e"
STA $60E9,X ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?
BNE done

_n:
; -n pluralization handler: -man -> -men, -Man -> -Men, -n -> -ns
LDA $60F0,X ; read second-last letter of monster name
CMP #$0A ; "a"
BNE append_s ; if not -an, append "s"
LDA $60EF,X ; read third-last letter of monster name
CMP #$16 ; "m"
BEQ update_e ; -man -> -men
CMP #$30 ; "M"
BNE append_s ; if not -Man, append "s"
update_e:
LDA #$0E ; "e"
STA $60F0,X ; replace second-last letter of monster name
SEC
RTS

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #95 on: July 05, 2019, 09:35:04 pm »
Yeah, you'll probably make all sorts of little mistakes on your first few attempts. It's especially bad if you're like me and have a bad habit of thinking one thing but typing another :P.
When writing ASM, labels are your friends, they get sad if you exclude them :P. It's basically the same idea as pointers when inserting a script: let the computer handle all the boring tedious address calculations for you; that's what computers are good at. Additionally, if you check the assembled code, branches are probably not getting assembled the way you think they are. E.g. that "BEQ $886C" actually ends up as "F0 6C", i.e. branch ahead $2C bytes, or "BEQ $8873", which happens to be right in the middle of "CMP #$1B", which is almost never a good idea, especially since 1B isn't a valid 6502 opcode. Labels don't have that problem.

Try something like this instead (not really tested):
Code: [Select]
norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $01C805 ; set the ROM file insertion point
base $87F5 ; set the starting RAM address

LDY $8F ; number of monsters in the current group
DEY
BEQ done ; if only 1 monster, then no need to pluralize, so we're done
DEX ; back up to [end-FA]
DEX ; back up to final letter of monster name
LDA $60F1,X ; read final letter of monster name
CMP #$22 ; "y"
BEQ _y ; -y -> -ies
CMP #$12 ; "i"
BEQ _i ; -i -> -ies
CMP #$1C ; "s"
BEQ _s ; -rus -> -rii, -s -> -ses
CMP #$11 ; "h"
BEQ _h ; -ch -> -ches, -sh -> -shes, -h -> -hs
CMP #$17 ; "n"
BEQ _n ; -man -> -men, -Man -> -Men, -n -> -ns
CMP #$0A ; "a"
BEQ _a ; Madusa -> Madusae
CMP #$1B ; "r"
BEQ _r ; Man O' War -> Men O' War
; append "s" to monster name
; default pluralization if not handled above
append_s:
INX
LDA #$1C ; "s"
set_final_letter:
STA $60F1,X
INX
LDA #$FA ; [end-FA]
STA $60F1,X ; append [end-FA] to monster name
INX
done:
SEC
RTS

_s:
; -s pluralization handler: Cyclops, Gigantes, and Atlas don't change, Magus changes to Magi otherwise add es
LDA $60F0,X ; read second-last letter of monster name
CMP #$0E ; "e"
BEQ done ; if -es, singular=plural
CMP #$0A ; "a"
BEQ done ; if -as, singular=plural
CMP #$19 ; "p"
BEQ done ; if -ps, singular=plural
LDA $60EF,X ; read third-last letter of monster name
CMP #$10 ; "g"
BEQ _us ; Shortcut here, if g_s (Magus) replace us with i
; If not either Cyclops or Atlas (or Magus), add -es
append_es:
; append "es" to monster name
INX
LDA #$0E ; "e"
STA $60F1,X ; append "e" to monster name
BNE append_s ; append "s" to monster name; note that this branch is always taken

_us:
; replace "us" with "i"
DEX ; shorten string by 1 letter
LDA #$12 ; "i"
BNE set_final_letter

_i:
; -i pluralization handler: -i -> -ies
LDA #$12 ; "i"
STA $60F1,X ; replace final letter with "i"
BNE append_es ; append "es"

_h:
; -h pluralization handler: -ch -> -ches, -sh -> -shes, -h -> -hs (no longer need ch, keeps Mech as Mechs)
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ append_es ; if -sh, append "es"
BNE append_s ; else, append "s"

_y:
; -y pluralization handler: like -i, except needs exceptions for boy-boys and dragonfry-no change
LDA $60F0,X ; read second-last letter of monster name
CMP #$18 ; "o"
BEQ append_s ; if -oy, append "s"
CMP #$1B ; "r"
BEQ done ; if -ry, no change
BNE _i ; otherwise replace y with -ies

_a:
; -a pluralization handler: needed for madusa -> madusae
LDA $60F0,X ; read second-last letter of monster name
CMP #$1C ; "s"
BEQ append_e ; if -sa add "e"
BNE append_s ; if not -sa append "s"

append_e:
; adding "e"
INX
LDA #$0E ; "e"
BNE set_final_letter

_r:
; -r pluralization handler: needed for man o' war
LDA $60E9,X ; read ninth from end letter of monster name
CMP #$0A ; "a"
BNE append_s ; if not "a" append "s"
LDA #$0E ; "e"
STA $60E9,X ; replace "a" with "e" so that Man o' War becomes "Men o' War" <-IS THIS RIGHT?
BNE done

_n:
; -n pluralization handler: -man -> -men, -Man -> -Men, -n -> -ns
LDA $60F0,X ; read second-last letter of monster name
CMP #$0A ; "a"
BNE append_s ; if not -an, append "s"
LDA $60EF,X ; read third-last letter of monster name
CMP #$16 ; "m"
BEQ update_e ; -man -> -men
CMP #$30 ; "M"
BNE append_s ; if not -Man, append "s"
update_e:
LDA #$0E ; "e"
STA $60F0,X ; replace second-last letter of monster name
SEC
RTS

So.. yeah. I think when I saw your post earlier in the thread about addresses in ASM I read it as "Oh hey, there are ways to make branches in ASM so you don't have to count bytes. You could, but you don't have to" kinda like Pointers. Looking at the code now, I see If/Then branches don't actually use addresses but some kind of relative jump value (and that comment you made about needing JMP commands over a certain amount of bytes makes more sense now too). Only JMP commands do. Lesson learned. Anyway, the new code works great so far. Just have to test out stuff like Man/Men o' War.

Changing tracks though. I was working on the Menu script and instead of dealing with Pointer Tables and updating the Pointers manually like I did with DW1, I thought I'd take a crack at making a Cartographer script so that I could just update and insert as much as I want with no fuss, and I seem to be hung up on the extraction part. It's the #base pointer: that I think is messing me up.

Code: [Select]
#GAME NAME:      DragonW2.nes

#BLOCK NAME:      Menus
#TYPE:         NORMAL
#METHOD:      POINTER_RELATIVE
#POINTER ENDIAN:   LITTLE
#POINTER TABLE START:   $7652
#POINTER TABLE STOP:   $76E5
#POINTER SIZE:      $02
#POINTER SPACE:      $00
#STRINGS PER POINTER:   01
#ATLAS PTRS:      Yes
#BASE POINTER:      $16368
#TABLE:         dw2menu.tbl
#COMMENTS:      No
#END BLOCK

I tried following the examples (initially I thought, "Oh, Base Pointer is Text Address - Pointer Address, right?") but I can't seem to get it to extract right (cartographer just hangs as it generates a huge block of text that I don't think is anywhere close to what I want)

Speaking of menus, I just want to bring up something you mentioned a while back

Quote
You won't be able to completely copy my code since I cannibalized the free space I created by shortening "ADVENTURE LOG" to "VOLUMEN", but the ASM for handling menu control codes $98 - $9F starts at 0x3ED8A; the original game ran the same code for all of $9A - $9F, so I stole $9B - $9F for the "names in border" code.

So thanks to my menu editing I too was able to cut down my usage of the ADVENTURE LOG macro (going with " Log", with a space, and was still able to get what I wanted into the menus with plenty of space to spare. But poking around your Latin menus to see what you did. There's resizing going on obviously, but it looks like you ADDED windows (namely a couple extra battle windows). What's going on there?

I mean having the full names in the battle status window would be awesome, but I'd be happy if I could just add the full names to battle menus minus extra spaces. But is the code you mentioned above JUST for the trailing spaces on the window bar or does it cover that too?

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #96 on: July 06, 2019, 11:19:58 am »
I think when I saw your post earlier in the thread about addresses in ASM I read it as "Oh hey, there are ways to make branches in ASM so you don't have to count bytes. You could, but you don't have to" kinda like Pointers. Looking at the code now, I see If/Then branches don't actually use addresses but some kind of relative jump value (and that comment you made about needing JMP commands over a certain amount of bytes makes more sense now too).
Yeah, all the branch ops use a signed displacement, which means they target a certain number of bytes away from the current PC value (e.g. +5 bytes, -22 bytes, etc.), rather than an absolute address like the jumps do (e.g. $885C).

So, yes, you could, but you don't have to, and if you do, then you need to write the addresses differently.

I was working on the Menu script and instead of dealing with Pointer Tables and updating the Pointers manually like I did with DW1, I thought I'd take a crack at making a Cartographer script so that I could just update and insert as much as I want with no fuss, and I seem to be hung up on the extraction part. It's the #base pointer: that I think is messing me up.
[...]
I tried following the examples (initially I thought, "Oh, Base Pointer is Text Address - Pointer Address, right?") but I can't seem to get it to extract right (cartographer just hangs as it generates a huge block of text that I don't think is anywhere close to what I want)
BASE POINTER is how much you need to add to the pointer value to get the text ROM address. The pointer value is a RAM address, though. So taking that first pointer at 0x7652 as an example, its value is D6 B6 = $B6D6 and it's in ROM bank 1, so that corresponds to ROM address 0x76E6, and $B6D6 + (-$3FF0) = $76E6, so -$3FF0 is the BASE POINTER value you want. What you're currently getting with that $16368 is 0x21A3E, which is in the middle of the title screen graphics :D.

Even without that issue, though, the problem I had with dumping the menus was that it was hard to tell where the menu data stopped. Unlike most other strings in the game, the menus don't have end tokens or anything that says exactly how many bytes long they are; after processing the menu header that sets up things like the window's height, width, and line spacing, the game just keeps on reading data until the menu is full, taking into account some variable-width control codes and non-uniform line-wrapping behaviour. If you're using the latest version of abcde, it comes with enough upgrades to get a decent dump of these menus and includes the Cartographer and table files I was using, so unless you're really determined to figure it out on your own, it's probably easier to reuse what I had.

So thanks to my menu editing I too was able to cut down my usage of the ADVENTURE LOG macro (going with " Log", with a space, and was still able to get what I wanted into the menus with plenty of space to spare. But poking around your Latin menus to see what you did. There's resizing going on obviously, but it looks like you ADDED windows (namely a couple extra battle windows). What's going on there?

I mean having the full names in the battle status window would be awesome, but I'd be happy if I could just add the full names to battle menus minus extra spaces. But is the code you mentioned above JUST for the trailing spaces on the window bar or does it cover that too?
Nope, there aren't any new windows, in battle or otherwise. Which ones look like they're new? I did move some of the windows around both in ROM as a sanity aid (I got tired of scrolling all over the place while editing related menus that were originally spread far apart) and on screen for various reasons. The code I added for printing hero names with spaces replaced by top borders prints the full 8 byte names, but if you wanted to only display 4 byte names, you would only have to delete a dozen of so lines of code.

gamingcat02261991

  • Jr. Member
  • **
  • Posts: 11
    • View Profile
Re: General NES Hacking Questions
« Reply #97 on: July 07, 2019, 11:05:07 pm »
How do you edit palettes and sprites for SMB2 (or SMUSA for the Japanese)?

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
Re: General NES Hacking Questions
« Reply #98 on: July 08, 2019, 03:48:41 pm »
How do you edit palettes and sprites for SMB2 (or SMUSA for the Japanese)?
This thread has mostly consisted of Dragon Quest 1 / 2 technical discussion but considering the thread title your question is perfectly on topic haha.

When I started with sprite editing, I used a combination of Tile Layer Pro and YYCHR software. I'd recommend watching some youtube videos that walk you through the basics. There are several good ones. FYI, one detail that took me awhile to figure out is the importance of hitting the plus and minus keys if the sprite graphics don't immediately show up clearly in the editors.

abw

  • Sr. Member
  • ****
  • Posts: 298
    • View Profile
Re: General NES Hacking Questions
« Reply #99 on: July 08, 2019, 09:10:11 pm »
This thread has mostly consisted of Dragon Quest 1 / 2 technical discussion but considering the thread title your question is perfectly on topic haha.
Yeah, given that the first 96 posts in this thread are all about Dragon Warrior 1 and 2 (mostly about 2), it might be worth changing the thread title to reflect that :P.