Romhacking.net

Romhacking => ROM Hacking Discussion => Topic started by: Chicken Knife on September 19, 2018, 08:25:57 am

Title: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 19, 2018, 08:25:57 am
So I've mostly finished my script revisions to Dragon Warrior 1 and I'm now looking at taking on the sequel. There isn't a dedicated table file posted, but when I plug in the table data from the first game, I'm able to read the text for spells, items and monster names in my hex editor. The curious thing is that the bulk of in game dialogue text does not show up in a readable form.

Glancing over information for later Dragon Warrior games, it looks like text compression exists for the dialogue in the 4th game. Am I most likely facing a compression issue in DW2?

If so, are there any good universal tools that would help me with the process of extracting, decoding, and reinserting the text?
Title: Re: Handling possible text compression
Post by: FCandChill on September 19, 2018, 05:43:03 pm
Chances are, this game uses DTE compression. It's very common in NES games. Can you find data that sort of ressembles dialogue like "S.e.h prince." ("Save the princess" compressed)?

Also, you might want to have a dedicated thread for your Dragon Quest questions ... just a suggestion.

September 19, 2018, 05:43:36 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
As for tools, check here https://www.romhacking.net/?page=utilities&category=14&platform=&game=&author=&os=&level=&perpage=20&title=&desc=&utilsearch=Go
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 19, 2018, 07:46:22 pm
I've used the ROM map available on this page to determine the block of data where the dialogue is stored. As I scan through that data, it does not appear as an abbreviated form of actual text like your example of S.e.h prince. Instead, all the data in that section appears as 80-90 percent non letter entries, with occaisional letter entries interspersed.

As far as your point on forum etiquette, it's a fair one. I know I've been throwing a lot of separate topics onto this board lately. I actually do have a dedicated Dragon Quest thread under personal projects. I figured that thread would attract primarily readers interested in my Dragon Quest project, but posting here would catch a wider audience of people willing to help with the numerous technical obstacles I face as a very new person to this process. Perhaps it would be better to have a unified thread here that isn't really about my project but serves to keep my large mess of questions in one place?
Title: Re: Handling possible text compression
Post by: FCandChill on September 19, 2018, 08:09:27 pm
I've used the ROM map available on this page to determine the block of data where the dialogue is stored.

You didn't link to anything in your post, but I assume you meant to link here: https://datacrystal.romhacking.net/wiki/Dragon_Warrior_II:ROM_map

The info you referenced is under the section name Dragon Quest not Warrior. In other words ... the page covers the Japanese version, not the English version. That may be your issue.
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 19, 2018, 08:54:53 pm
Fair point, but I have used a hex editor to carefully scroll through all the data in the rom, several times actually. On each search I come across the full list of items, monsters and spell names. The only other text I come across is the prologue text added for the US version intro. The dialogue text is no where to be found.

When I go through DW1 or even DW3, I easily locate the large block of general dialogue text, along with the items, monster names and spells.
Title: Re: Handling possible text compression
Post by: Psyklax on September 20, 2018, 02:00:55 am
I second the idea of a dedicated thread for all this: no need to make lots of new threads. :)

As for the text compression question, if I can find the time I can have a look myself. I know for a fact that Dragon Warrior doesn't have compression but I can't remember about DW2. I'd be a bit surprised if it did because neither it nor the first game have an overwhelming amount of text.

Maybe later today I'll be able to spend five minutes checking the text to see how it's stored in the ROM. Compression does happen in text heavy games - my efforts translating Time Stranger from 1986 found a neat dictionary compression scheme - but again, I'd be a little surprised were that the case here.
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 20, 2018, 08:58:54 am
Sounds great Psyklax. Once this issue gets figured out I'll change the title of this post to something generalized and put all my technical questions here going forward.

Going back to the issue at hand, I also found it strange that the game would use compression--especially since there is a ton of empty space in the US rom. I initially thought this might be an issue of the game having the alphabet under multiple table entries. To test that, I went into FCEUX Nametable Viewer and checked the hex code of the letters showing up in dialogue text. The hex code for the letters in dialogue was exactly the same as the code for the letters in monster, item and spell names--with all of the latter showing up in a hex editor when I load up table data. Would this indicate compression or could another factor be causing this? 

I appreciate you taking a look at the rom!
Title: Re: Handling possible text compression
Post by: Psyklax on September 20, 2018, 10:43:22 am
I went into FCEUX Nametable Viewer and checked the hex code of the letters showing up in dialogue text. The hex code for the letters in dialogue was exactly the same as the code for the letters in monster, item and spell names--with all of the latter showing up in a hex editor when I load up table data. Would this indicate compression or could another factor be causing this?

I don't think simply looking at the nametable would indicate compression per se. The way I would do it is the more advanced method of debugging the game to see how the text gets from the ROM to the screen, and compression will become apparent then. A simpler way is the old fashioned relative search technique locating where the text is, and discovering the compression then.

I'll have a look later, anyway. I've already hacked this game to double experience and gold, so that's why I'm familiar with it.
Title: Re: Handling possible text compression
Post by: KingMike on September 20, 2018, 12:50:32 pm
I know Dragon Warrior II and III used ROM expansion so I wouldn't expect something beyond dictionary, because what's the point once they're expanding the ROM.

Yes, in DW4 they used Huffman which is tricky but that's because they couldn't really expand further. SOROM or whatever it was (the 512KB MMC1 mapper) was already about the limit.
Title: Re: Handling possible text compression
Post by: Psyklax on September 20, 2018, 06:00:12 pm
Well, you were right: DW2 uses a rather tricky compression method which I don't fully understand yet. I'm still looking at it, and it's not like what I've seen before. I'd say it's a bit like dictionary compression, except not... I'll continue until I've figured it out, but it's weird.
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 20, 2018, 07:40:20 pm
Thank you so much for diving into this Psyklax. Why did those knuckleheads at Nintendo of America feel the need to give us this headache with all that free space at their disposal.  :banghead:
Title: Re: Handling possible text compression
Post by: Alchemic on September 21, 2018, 01:36:17 am
I did some digging around in DW2 a few years back. My notes are kind of a mess, but to summarize:
Code: [Select]
TBL for 0xB49B:
00-09 = 0-9
0A-23 = a-z
24-3D = A-Z
3E-57 = a-z again
58=A
59=(space)
5A=[SUN]
5B=[STAR]
5C=[MOON]
5D=[DROP]
5E=[HEART]
5F=(space)
60=(space)
61='
62="
63=->
64="
65='
66='
67='
68=.'
69=,
6A=-
6B=.
6C=&
6D=(space)
6E=?
6F=!
70=;

Text-dumping code in Python (https://github.com/Osteoclave/game-tools/blob/master/nes/dragonwarrior2_textdump.py)
Title: Re: Handling possible text compression
Post by: Psyklax on September 21, 2018, 03:56:14 am
Wow, Alchemic, that confirms what I saw: that it's pretty messed up. :D I got as far as noticing that each individual word is assembled letter-by-letter in SRAM before being passed off to the PPU, but it would've taken me time to get to the level of detail you've acquired. That has to be the most convoluted text handling scheme I've ever seen in a game.

I had a look so I can see what you're talking about there. It's still messing with my brain, so I think I'll leave it for now. :)
Title: Re: Handling possible text compression
Post by: abw on September 21, 2018, 08:57:00 am
Maybe later today I'll be able to spend five minutes checking the text to see how it's stored in the ROM.
If you actually had cracked that code in 5 minutes, you would have had my vote for the annual "God of ROMHacking" award :P.

I did some digging around in DW2 a few years back. My notes are kind of a mess, but to summarize:
[...]
Text-dumping code in Python (https://github.com/Osteoclave/game-tools/blob/master/nes/dragonwarrior2_textdump.py)
Nice work Alchemic! I'm sure somebody's next question is going to be: did you also happen to write an insertion script?

That has to be the most convoluted text handling scheme I've ever seen in a game.
The basic input -> output encoding is pretty simple, but I definitely agree that DW2's text engine could have been implemented in a much less complicated way. It took me a couple of days to work through it enough to get a decent script dump, but I can confirm that Alchemic's notes are indeed accurate.

I also found it strange that the game would use compression--especially since there is a ton of empty space in the US rom.
Why did those knuckleheads at Nintendo of America feel the need to give us this headache with all that free space at their disposal.  :banghead:
It's not always a question of how much free space in total, but where that free space is located. DW2's script is large enough that even with the compression scheme they added, it still doesn't fit inside a single PRG bank, which is why the script jumps from 0x17FE6 to 0xB7C2. Maybe they were trying to keep almost all of the text-related code and data confined to 2 PRG banks?
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 24, 2018, 07:04:44 am
@abw got it right. I'm definitely asking for someone to help me write a script for this. Wouldn't I need two scripts: one to uncompress the text into readable / editable form and another to recompress for reinsertion? I'm willing to keep the maximum length of each line the same if it means not having to worry about readjusting all the pointers.

In the mean time, I am keeping myself busy figuring out the best way to edit the monster, spell and item lists but I would be so very grateful to have a means of moving forward with the script one day soon.

Title: Re: Handling possible text compression
Post by: abw on September 24, 2018, 09:57:45 pm
@abw got it right. I'm definitely asking for someone to help me write a script for this. Wouldn't I need two scripts: one to uncompress the text into readable / editable form and another to recompress for reinsertion? I'm willing to keep the maximum length of each line the same if it means not having to worry about readjusting all the pointers.
If all else fails, abcde (http://www.romhacking.net/utilities/1392/) can definitely handle both extracting and inserting text like this along with updating the pointers, and you'll have all the original space at your disposal (there's no free space conveniently available after the original script ends, since the very next byte is code, so if you need more space than the original, it'll take a bit more work). As an added bonus, thanks to the original encoding being somewhat inefficient, abcde can actually re-insert the original script using $79 fewer bytes.
Title: Re: Handling possible text compression
Post by: Chicken Knife on September 25, 2018, 08:42:31 am
@abw

Am I to understand that your software can already handle unwinding the existing compression routine in DW2 without the need for a special script being written? Also, if I am to use the more efficient form of compression available through your software, it will automatically rework the code of the game to be able to read the new compression routine?

Something tells me it will be nowhere near this easy.  :laugh:
Title: Re: Handling possible text compression
Post by: abw on September 25, 2018, 06:10:59 pm
Am I to understand that your software can already handle unwinding the existing compression routine in DW2 without the need for a special script being written?
[...]
Something tells me it will be nowhere near this easy.  :laugh:
I'm not going to make any promises about how easy using abcde will be for anybody else, but... basically, yeah. Like I said earlier, the text encoding itself is actually pretty simple, it's just that DW2's code for parsing that encoding is fairly unpleasant. Give abcde the right table file, extract command file, and ROM, and watch it go. Stick a couple of extra lines in the script dump file it generates to turn it into a valid insert command file, and then run abcde again with the same table file, the insert command file (edited to have your new text, if so desired), and (a copy of) the ROM. That said, unless you start making ASM changes, you're still constrained by the total available space and text engine and stuff, so it's not a magic bullet.

Also, if I am to use the more efficient form of compression available through your software, it will automatically rework the code of the game to be able to read the new compression routine?
Haha, don't I wish it was that good :P. abcde doesn't make any changes to the game's code, it just uses a better insertion algorithm. The original data compression was sub-optimal; as one example, the game stores the string "'Welcome " as ['W][e][l][come][ ], with those 5 pieces taking up 10 + 5 + 5 + 10 + 5 = 35 bits. On the other hand, abcde is smarter and inserts the same string as ['][Welcome ] in 5 + 10 = 15 bits, for a savings of 20 bits. Little improvements like that that save 5 bits here, 10 bits there over the course of the entire script is how we end up with 121 bytes of reclaimed space.
Title: Re: General Hacking Questions
Post by: Chicken Knife on November 29, 2018, 08:09:01 am
I thought I'd bring this thread back to life as I'm back into my projects consistently and have a few things I need help with.

I'm nearly done with my Dragon Warrior 1 hack and my only issue left is that I want to fix some compromises I had to make porting over NPC sprite graphics from the famicom version due to left/right mirroring instructions in the DW1 for certain sprite tiles.

Does anyone have any good reading material to recommend that will present in a way that does a good job explaining itself to a non coder that will help me understand "sprite pointers" (if I'm using the right term) and will help me understand how to either disable the LR mirroring instructions I’m struggling with or simply redirect the game to alternative tiles for that sprite? If I can "repoint" them effectively like I do with text, I will have a ton of extra space since I turned all the 4 direction sprites into 1 direction sprites.

There are also other topics where I would like to do some reading and am having a hard time because I either can't find the resources or the resources I find are too technical:

I encountered a multiplier formula in Dragon Warrior 3 where the game takes the base Japanese gold and experience numbers saved for monsters saved in the IS game but applies a .25% boost, rounded up, to those values for what you actually earn in battle. I want to locate and disable that multiplier, restoring the straight Japanese values in gameplay. I assume a debugger would help me here. If so, any good reading material (or better yet videos) you guys would recommend for effectively using the FCEUX debugger for something like this?

Last, I've tried to play around with Atlas / Cartographer, ABCDE software in hopes of solving the DW2 script compression issue. The faq that comes with Atlas is too technical for me at this point and I haven't found much else out there. Any recommended reading?

Thanks guys!
Title: Re: General Hacking Questions
Post by: abw on November 29, 2018, 08:34:16 pm
Does anyone have any good reading material to recommend that will present in a way that does a good job explaining itself to a non coder that will help me understand "sprite pointers" (if I'm using the right term) and will help me understand how to either disable the LR mirroring instructions I’m struggling with or simply redirect the game to alternative tiles for that sprite?
Maybe I shouldn't comment since I don't usually do much graphics work, but when I do, I usually end up consulting Y0SHi's NES Documentation (http://www.romhacking.net/documents/120/), and although I'm pretty sure I originally had to read it a few times before it sunk in, it hasn't steered me wrong yet and it does have a couple of sections that talk about sprites.

Last, I've tried to play around with Atlas / Cartographer, ABCDE software in hopes of solving the DW2 script compression issue. The faq that comes with Atlas is too technical for me at this point and I haven't found much else out there. Any recommended reading?
Did you try abcde's readme or examples? Be honest - how bad are they really? I'm waaaay too deeply immersed in the source material to feel confident about my ability to pitch the documentation at a level that is useful without making other people barf, plus I implicitly assume that the end user is already familiar with Atlas/Cartographer :(.

I might have some recommended reading for you, though (based on abcde v0.0.2; provide your own "Dragon Warrior II (U) [!].nes") ;D:
Extraction:
Quote from: Cartographer.txt
#GAME NAME:      Dragon Warrior II (U) [!].nes

#BLOCK NAME:      Main Script, Part 1
#TYPE:         NORMAL
#METHOD:      POINTER_RELATIVE
#POINTER ENDIAN:   LITTLE
#POINTER TABLE START:   $B762
#POINTER TABLE STOP:   $B7BD
#POINTER SIZE:      $02
#POINTER SPACE:      $00
#STRINGS PER POINTER:   16
#AUTO JUMP START:   $17FE7
#AUTO JUMP STOP:   $B7C2
#ATLAS PTRS:      Yes
#BASE POINTER:      $C010
#TABLE:         dw2_script.tbl
#COMMENTS:      Yes
#END BLOCK

#BLOCK NAME:      Main Script, Part 2
#TYPE:         NORMAL
#METHOD:      POINTER_RELATIVE
#POINTER ENDIAN:   LITTLE
#POINTER TABLE START:   $B7BE
#POINTER TABLE STOP:   $B7C1
#POINTER SIZE:      $02
#POINTER SPACE:      $00
#STRINGS PER POINTER:   16
#ATLAS PTRS:      Yes
#BASE POINTER:      $10
#TABLE:         dw2_script.tbl
#COMMENTS:      Yes
#END BLOCK

Quote from: dw2_script.tbl
# NB: I didn't put much time into figuring out the control codes, so some of them are still unknown and some of them might be wrong. Caveat emptor!

/%00000=[end]\n\n
/%00001=.[end]\n\n
/%00010=?[’ ][FD][FD][end]\n\n
/%00011=[.’][end]\n\n
%00100=[FF]
%00101=y
%00110=c
%00111=o
%01000=d
%01001=e
%01010=f
%01011=g
%01100=h
%01101=i
%01110=j
%01111=
%10000=l
%10001=m
%10010=n
%10011=[line]\n
%10100=[.’]
%10101=[ ‘]
%10110=r
%10111=s
%11000=t
%11001=u
%11010=a
%11011=w
%11100=C0
%11101=C1
%11110=C2
%11111=C3

%1110000000=A
%1110000001=B
%1110000010=Ca
%1110000011=D
%1110000100=E
%1110000101=F
%1110000110=G
%1110000111=H
%1110001000=I
%1110001001=J
%1110001010=King
%1110001011=L
%1110001100=Moonbrooke
%1110001101=N
%1110001110=O
%1110001111=[item]
%1110010000=The
%1110010001=Rhone
%1110010010=S
%1110010011=;
%1110010100=U
%1110010101=”
%1110010110=Water Flying Cl
%1110010111=C
%1110011000=Y
%1110011001=Z
%1110011010=x
%1110011011=Village
%1110011100=z
%1110011101=[F9]
%1110011110=‟
%1110011111=K

%1110100000=v
%1110100001=q
%1110100010=[’ ][wait][line]\n
%1110100011=R
%1110100100=.
%1110100101=[FD][FD]
%1110100110=P
%1110100111=b
%1110101000=T
%1110101001=!
%1110101010=[sun]
%1110101011=[star]
%1110101100=[moon]
%1110101101=W
%1110101110=k
%1110101111=p
%1110110000=?
%1110110001=,
%1110110010=[monster]
%1110110011=....
%1110110100=:
%1110110101=[’ ]
%1110110110=-
%1110110111=[’ ]
%1110111000=[spell]
%1110111001=[letter]
%1110111010=[no voice]
%1110111011=[wait]
%1110111100=M
%1110111101=[name]
%1110111110=[number]
%1110111111=[FD]

%1111000000=Thou hast
%1111000001=hest
%1111000010=Midenhall
%1111000011=hou
%1111000100= of
%1111000101= is
%1111000110= thou has
%1111000111= and
%1111001000=to th
%1111001001= thee
%1111001010=ast
%1111001011= do
%1111001100=hat
%1111001101= shall
%1111001110= was
%1111001111=hou has
%1111010000=d the
%1111010001= has
%1111010010=gon
%1111010011=.[wait][line]\n
%1111010100= have
%1111010101=come to
%1111010110=ing
%1111010111= hast
%1111011000=ost thou
%1111011001=this
%1111011010= of the
%1111011011=Hargon
%1111011100=in the
%1111011101=thing
%1111011110=he
%1111011111= with

%1111100000=reasure
%1111100001=[ ‘]Hast
%1111100010=Erdrick
%1111100011=come
%1111100100=ere is
%1111100101=Welcome
%1111100110=rince
%1111100111= great
%1111101000=arr
%1111101001= for th
%1111101010=piece[(s)] of gold
%1111101011=[.’][wait][line]\n
%1111101100=But
%1111101101=here
%1111101110=can
%1111101111=ove
%1111110000=hee
%1111110001=not
%1111110010=for
%1111110011=one
%1111110100= any
%1111110101= to
%1111110110=descendant
%1111110111=Roge Fastfinger
%1111111000=all
%1111111001=thy
%1111111010=[ ‘]W
%1111111011=thank thee
%1111111100= it
%1111111101= tha
%1111111110= thou
%1111111111= the

Usage (replace \path\to\abcde\abcde.pl as appropriate):
Code: [Select]
perl \path\to\abcde\abcde.pl -m bin2text -cm abcde::Cartographer "Dragon Warrior II (U) [!].nes" Cartographer.txt Cartographer_out -s

Insertion:
Quote from: Atlas.txt
// Define, load, and activate a TABLE
#VAR(Table, TABLE)
#ADDTBL("dw2_script.tbl", Table)
#ACTIVETBL(Table)

// Jump to start of script
#JMP($14010)
#HDR($C010)
// auto-commands for when DW2 does a mid-string bankswap and resets its read address:
#AUTOCMD($17FE7, #HDR($10))
#AUTOCMD($17FE7, #JMP($B7C2, $BE0F))

// the rest of Cartographer_out.txt goes here

Quote from: insert.bat
@copy /Y "Dragon Warrior II (U) [!].nes" "Dragon Warrior II (U) [new].nes" > nul

perl \path\to\abcde\abcde.pl -m text2bin -cm abcde::Atlas "Dragon Warrior II (U) [new].nes" Atlas.txt

pause
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on November 30, 2018, 02:54:28 am
@ abw

Wow! Talk about a silver platter  :beer:

I've done all the steps you've outlined but I'm getting this message after inputting: (from within abcde.pl's directory)
perl abcde.pl - bin2text -cm abcde::Cartographer "Dragon Warrior II - Edit.nes" Cartographer.txt Cartographer_out -s

Message after inputting:

error UTF-8 "\x92" does not map to Unicode at C:/Perl164/lib/Encode.pm line 228, <TABLE> line 3
when reading C:\Rom Editing\dw2_script.tbl line 3

I don't think me using the altered name of my hacked rom file would matter. Let me know if it does.
As far as Perl, I downloaded the software today in order to get this going. ActivePerl 5.26.1.2601 MS Win32-x64-404865 is the version.

PS

As far as Yoshi's NES doc, I think it's written far more for someone like you than someone like me. The density of it loses me in the same way as most of what I try to read on the NES Dev site. Truth be told, your abcde faq is much easier to follow, though I'm far from understanding all of it and it definitely does assume I understand Atlas / Cartographer. As far as the Yoshi faq, I'll have to keep coming back to this and whatever else I find until I figure out how to do the graphical work I need to.
Title: Re: General NES Hacking Questions
Post by: abw on November 30, 2018, 08:36:29 am
@ abw

Wow! Talk about a silver platter  :beer:
Heh, I had it handy from earlier in the thread. I used that stuff to make the King of Moonbrooke say "Oh noes, not the flying purple people eaters!" during the intro scene in order to test inserts :P.

error UTF-8 "\x92" does not map to Unicode at C:/Perl164/lib/Encode.pm line 228, <TABLE> line 3
when reading C:\Rom Editing\dw2_script.tbl line 3
Ah, sorry, I forgot to mention that you'll need to save the files (particularly the table file) encoded as UTF-8. Any modern text editor should give you that option when you save a file; even Notepad can save as UTF-8!

As far as Yoshi's NES doc, I think it's written far more for someone like you than someone like me. The density of it loses me in the same way as most of what I try to read on the NES Dev site.
Yeah, there's definitely a lot to take in, but knowing what's going on at the hardware level, what the different sections of PPU RAM control, and what all those writes to $20xx are doing can be pretty helpful when you're trying to track down some graphics logic.

Truth be told, your abcde faq is much easier to follow
Huzzah, mission partially accomplished!
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on November 30, 2018, 07:33:03 pm
@ abw

Worked like a charm.  :woot!:

I assume that a similar approach to how I edit text in hex editors would serve me well. I plan on working within the length of the existing strings, using blank entries at the end of lines of text if I happen to shorten in order to keep the length exactly the same. The thing that concerns me is the presence of so many control codes in DW2. As I go through the extraction document, I see the presence of plenty of those words in the script, but I don't see any indication that those words are produced by a control code in the document. I can keep Roge Fastfinger in mind easily enough, but with a ton of other common control code words like he, with, can, one, any etc. there is no way I'm going to be able to keep track of them all. Also, how do I know that the game consistently used control codes for those words instead of using them sporadically? It seems like it will be inevitable that I'll end up with a different data size and a considerable headache. Perhaps I could use the find command to highlight every instance of them in the text before I start editing in order to be wary of carefully maintaining string length. Any advice would be appreciated.

Also, going back again to Roge Fastfinger, I will be reverting his name to the Japanese Lagos. Is there any simple way to edit the control code words so I could swap out the name and use the same code? If not, I suppose I'd have to seriously abbreviate those lines to compensate.

Also, when reinsertion time arrives, does your system automatically note every control code word and insert them back into the game as the single byte control code instead of individual letter data? I'm curious.

Last question: I've heard on occasion that this kind of software automatically readjusts the text pointers and I could therefore enlarge some strings of text as long as the total amount of data is the same upon insertion. That seems too good to be true. Could it be?

Let me know your thoughts. I'm sure there is a lot I'm conceptually missing here.
Title: Re: General NES Hacking Questions
Post by: abw on December 01, 2018, 12:13:49 am
Worked like a charm.  :woot!:
Whoo-hoo!

I assume that a similar approach to how I edit text in hex editors would serve me well.
I plan on working within the length of the existing strings, using blank entries at the end of lines of text if I happen to shorten in order to keep the length exactly the same.
It seems like it will be inevitable that I'll end up with a different data size and a considerable headache.
*shudders* Nope, nope, and... wait for it... nope :P.
The fastest way is probably just to try it and see, but basically when you use a (decent) script insertion utility, you don't have to worry too much about things like the binary it inserts or updating pointers, since the utility takes care of all of that for you. Like I mentioned earlier, you're still constrained by the total available space and text engine and stuff like that, but as long as you don't try to insert impossible (combinations of) characters or too much text, you can do more-or-less whatever you want.

Line lengths will change; that's okay and you don't need to care about it.
Some text will get encoded as single characters, some as multiple characters; that's okay and you don't need to care about it.
String addresses will change and pointers to those strings will get updated; that's okay and you don't need to care about it.

Last question: I've heard on occasion that this kind of software automatically readjusts the text pointers and I could therefore enlarge some strings of text as long as the total amount of data is the same upon insertion. That seems too good to be true. Could it be?
Automatically recalculating pointer values is just one of the many benefits of using a script insertion utility over hex editing :).

Also, going back again to Roge Fastfinger, I will be reverting his name to the Japanese Lagos. Is there any simple way to edit the control code words so I could swap out the name and use the same code?
Yup. It's not quite as simple for DW2 as it would be for a game with a less ornery text engine, but it's still not too hard. The dictionary lives at ROM 0xB44B-0xB686, with each nybble (1 nybble = half a byte) of 0xB44B-0xB49A giving the length of the corresponding dictionary entry in 0xB49B-0xB686. So you could change "Roge Fastfinger" to "Lagos" at 0xB655, shift the rest of 0xB664-0xB686 up to just after the end of "Lagos", and then change the length of the "Roge Fastfinger" dictionary entry from 15 to 5 at 0xB496 (i.e. 0xAF -> 0xA5), leaving you with 10 bytes of unused space at 0xB67D-0xB686. Just make sure to update your table file to match whatever changes you make to the game's text encoding, or you're going to get a nasty surprise when you try extracting or inserting text!

Also, when reinsertion time arrives, does your system automatically note every control code word and insert them back into the game as the single byte control code instead of individual letter data? I'm curious.
Based on the table file(s) you provide, abcde is aware of all the possible ways of translating your text into the binary that the game needs, and it will convert your text into the shortest possible binary that represents your text. How? Magic :angel:.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 02, 2018, 04:10:31 pm
@abw

Ok, I worked furiously throughout the weekend on my script. Having just completed it, I ran the insertion routine, loaded up the game, and found the text to be totally mangled. Everyone is saying something different than what they should be saying. I don't think my data overran the alotted space. In general a direct translation of the famicom is shorter than the US version. I assume I would have gotten some kind of error message if it did.

The other possibility in my mind is that I was supposed to totally sort out the control codes prior reworking the script, which I did not do. Is that what you would suspect is the issue or do you have another idea?

I have a frightening suspicion that if control codes are the issue, I would have saved myself tremendous work prior to extraction and reworking the script.

Also, there were some instructions in the Atlas data that you quoted me where I wasn't sure if they were written to me or the program. For example:

// auto-commands for when DW2 does a mid-string bankswap and resets its read address:

PS I don't know if this helps, but all of the dialogue from everyone seems to be various battle commands

*EDIT

If it helps at all, this is the Atlas file where I tried removing what looked like your instructions from me and added my game script underneath. Take a look.

https://www.dropbox.com/s/t06zcf8qmmfhsno/Atlas.txt?dl=0
Title: Re: General NES Hacking Questions
Post by: abw on December 02, 2018, 10:52:18 pm
Ha, that's me skipping over important little details again :-[ (in my defence, they are documented). In my extract script, I set #COMMENTS: Yes, which makes every line of the script be output as a comment and thus ignored during insertion. So, since all the text is a comment, the only thing that actually changed would have been the pointers, and every pointer in the first block of pointers would point to the same first string starting at 0x14010, which happens to contain battle text. The second block of pointers would also point to the same RAM address ($8000), but with the wrong ROM bank visible in RAM, so I imagine any attempt to display one of those strings would end badly.

If you're only making a few changes to the script, you might prefer setting #COMMENTS: No instead and editing the text that way, or reformat the script dump using your text editor of choice (when translating, I like keeping the original text for reference and adding my new text just below); a simple regular expression search-and-replace operation or two should do the trick, or in the worst case you could manually delete the // before each line of script.

Also, there were some instructions in the Atlas data that you quoted me where I wasn't sure if they were written to me or the program. For example:

// auto-commands for when DW2 does a mid-string bankswap and resets its read address:
Any line in the extract or insert command files that starts with // is treated as a comment, so the ones I added are just notes to explain what's going on. In this case, DW2 has some code that says "when the current read address reaches $BFD7, swap in a different bank and keep reading from $B7B2", so the #AUTOCMDs are there to handle that during insertion.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 02, 2018, 11:33:46 pm
@abw

As far as leaving out that bit, you are my patron saint of hacking. No grievance shall ever be held against you.  :laugh:

Ok. So if comments would have been set to No, then all the lines of text would have inserted as intended I assume. If I understand correctly, leaving comments set to Yes would be convenient because I could write the legitimate lines of text underneath them without the // and insert the data back in the rom effectively even with the old script appearing as comments.

So in my case, I took the output document and totally changed 98 percent of the text based on various resources to reflect a literal but fluid version of the Japanese text in contemporary English. I haven't slept much lately--and my wife may want to divorce me but that's neither here nor there. :D

So what would you suggest I do now? I often don't mind doing things the slow and painful way. Lifelong RPG gamer after all  :laugh: I'm thinking to go through the document and delete every instance of the characters // and leave whatever text comes after them. Would that do the job for reinsertion or do I have to add anything in their place?

There is no way I'm starting over with a new extraction. Somehow or another, this document has to get formatted correctly.



December 04, 2018, 02:07:08 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Ok. That was a question I could really answer myself through a little experimentation. I ran another extraction and just confirmed which // characters to remove.

Having done so, I reinserted and about 3/4 of my text was inserted correctly! I'll consider that a small victory haha. The other 1/4 text is either the games original text or bugged.

The error message I got in command prompt when I did the insertion was:

unable to tokenize; best attempt failed at input position 513 at C:\Rom Editing/abcde/Table/Table.pm Line 421 <COMMAND_FILE> line 1707. in text string starting at Atlas.txt line 1665.

I immediately thought this was an issue with my insert text. I went to that line (with word wrap turned off) and found there is nothing unusual at all about it. Line 1665 reads:

[ ‘]This is a sewing shop[.’][line]
Title: Re: General NES Hacking Questions
Post by: abw on December 04, 2018, 08:03:38 pm
As far as leaving out that bit, you are my patron saint of hacking. No grievance shall ever be held against you.  :laugh:
Heh, be careful what you promise >:D

I haven't slept much lately--and my wife may want to divorce me but that's neither here nor there. :D
I'm not going to admit to knowing what that feels like :D.


I took a closer look at this and noticed a couple of things:
- The dictionary does not include uppercase Q, V, or X as displayable characters, so you can't use those anywhere in your script without changing the dictionary. That unreadable mess of garbage just before the final error message abcde gave is supposed to show you how far along abcde got in the problem string before it couldn't go any farther, and as it happens 514 characters into the string starting at line 1665 is a Q. (yeah, the error messages suck)
- Some of the dictionary entries display different visually identical tiles, but I made them the same in my table file. In my translation of DW1, I originally made the mistake of assuming that just because the graphics were identical, it didn't matter which of the different tile IDs I used; this led to a moment of intense dismay when I realized that I had managed to accidentally disable the "speech" text printing sound effect!
- You did indeed make a lot of changes - replacing all the "thee"s and "thou"s and changing some proper nouns meant that a lot of the original dictionary entries went unused during insertion, which resulted in your new script not compressing small enough to fit in the available space. A few ad hoc tweaks to the dictionary was enough to sort that out and leave you with 218 bytes to spare; if you end up needing more room, updating the dictionary based on a full frequency analysis should give you much better compression results than me just eyeballing things.

Here's a copy of the updated insert script (https://drive.google.com/open?id=1rrX177cE49fE2R0CYk9CXhYgGJqmNgQZ) and table file (https://drive.google.com/open?id=1MnB--MNEd4BG_IOxt4qZcwq3y6kigmMr) I used. I took the liberty of merging the original text into your new text as comments and fixing up a couple of typos that were breaking insertion; spell checking the new script is your responsibility :P. For the table file changes, you'll need to make the corresponding changes to the dictionary like I described a couple of posts ago (http://www.romhacking.net/forum/index.php?topic=27053.msg366909#msg366909).
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 05, 2018, 06:29:19 am
@abw, you didn't need to do all this work for me! I'm extremely grateful but I really don't want to be a burden here (Although I imagine watching me flop around like a fish out of water can be equally burdensome)

I think you've given me everything I need to do this insertion and further improvements to my script--except for one thing that I need clarification for.

In order to update the rom's dictionary with the new words and nybble lengths as you instructed above, I need you to clarify how I actually locate where to plug in the nybble that corresponds to each dictionary entry. Either I missed it or you didn't provide the detail as to how you knew 0x0B496 corresponded to the entry for Roge Fastfinger / Lagos. I'm not sure if this uses a counting system like the item/monster/spell lists. Hopefully not since that would give me a big headache as the entries here seem all mashed up together.
Title: Re: General NES Hacking Questions
Post by: abw on December 05, 2018, 07:35:57 pm
@abw, you didn't need to do all this work for me! I'm extremely grateful but I really don't want to be a burden here (Although I imagine watching me flop around like a fish out of water can be equally burdensome)
If it makes you feel any better, only a little bit of that work was purely for you ;). I'm slowly puttering away at my own translation whenever the mood strikes me, so a lot of the issues you're encountering now are issues I would no doubt encounter myself at a later date. Might as well deal with them now so that we can both benefit (and judging from the read count on this topic, I suspect it's more than just you and I that are interested in this).

I think you've given me everything I need to do this insertion and further improvements to my script--except for one thing that I need clarification for.
The lengths of the dictionary entries are stored in nybbles at 0xB44B-0xB49A and the values are stored in bytes at 0xB49B-0xB686; the table file I provided lists the dictionary entries in the same order they appear in ROM, and the table file you were using to edit the item/monster/spell lists will also let you see the dictionary values correctly. An example from partway through the dictionary might be helpful to see what's going on:
Code: [Select]
...
0x00B45B|$02:$B44B:11                            ; length of "A", length of "B"
0x00B45C|$02:$B44C:21                            ; length of "Ca", length of "D"
0x00B45D|$02:$B44D:11                            ; length of "E", length of "F"
0x00B45E|$02:$B44E:11                            ; length of "G", length of "H"
0x00B45F|$02:$B44F:11                            ; length of "I", length of "J"
0x00B460|$02:$B450:41                            ; length of "King", length of "L"
0x00B461|$02:$B451:A1                            ; length of "Moonbrooke", length of "N"
...
0x00B4C1|$02:$B4B1:24                            ; A
0x00B4C2|$02:$B4B2:25                            ; B
0x00B4C3|$02:$B4B3:26 0A                         ; Ca
0x00B4C5|$02:$B4B5:27                            ; D
0x00B4C6|$02:$B4B6:28                            ; E
0x00B4C7|$02:$B4B7:29                            ; F
0x00B4C8|$02:$B4B8:2A                            ; G
0x00B4C9|$02:$B4B9:2B                            ; H
0x00B4CA|$02:$B4BA:2C                            ; I
0x00B4CB|$02:$B4BB:2D                            ; J
0x00B4CC|$02:$B4BC:2E 12 17 10                   ; King
0x00B4D0|$02:$B4C0:2F                            ; L
0x00B4D1|$02:$B4C1:30 18 18 17 0B 1B 18 18 14 0E ; Moonbrooke
0x00B4DB|$02:$B4CB:31                            ; N
...
So if you wanted to, say, change the dictionary entry for King to say Queen instead, you'd change the length stored at 0xB460 from 41 to 51, change King to Queen starting at 0xB4CC, and shift everything from 0xB4D0 down by one byte. The dictionary has a fixed length and is followed immediately by code though, so in a case like this where you added a byte, you would need to remove a byte from somewhere else in the dictionary (pick "Water Flying Cl", it's only used 4 times in the entire script!).
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 05, 2018, 08:04:54 pm
@abw knowing that you tend to respond around this time I was in a big rush to message that I actually figured this out myself (well not really but still), finding that it was indeed a similar counting mechanism and making a little chart for myself just to make sure I understood it. Exhibit A: the little chart I was working on. hahaha

B490   piece(s) of gold   ???
B491   But[ ]         here
B492   can[ ]         ove
B493   hee         not
B494   for         one
B495   [ ]any         [ ]to[ ]
B496   Descendant       Lagos      
B497    all         thy      
B498   ?W         thank thee      
B499   [ ]it         [ ]thou      
B49A   [  ]the.      4

December 05, 2018, 08:07:19 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Now that I get the mechanics of this, I'm going to optimize the dictionary entries to match up to my translation trends as much as possible, which should allow me to expand text a little more as I go through the revision process should I desire.

I'm interested in what you are planning translation wise--more Latin for DW2? Also, now that we are discussing your translation, I'm curious what your textual basis was: the original US English translation or the Japanese?
Title: Re: General NES Hacking Questions
Post by: abw on December 07, 2018, 11:08:02 pm
Exhibit A: the little chart I was working on. hahaha
Haha, I see that's a nice little chart you have there :thumbsup:.

I'm interested in what you are planning translation wise--more Latin for DW2? Also, now that we are discussing your translation, I'm curious what your textual basis was: the original US English translation or the Japanese?
Yup. It's a dirty job, but somebody's got to do it :P. I generally use the English version of whatever I'm translating as my base, but will consult other English versions or other languages if the need arises; this happens most often for made-up enemy/item names, but sometimes I come across a line or two of dialogue that I like to clarify because it's a little too vague or allows for multiple valid interpretations.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 08, 2018, 11:13:07 pm
Ok, I have a report that is pretty darned good. While I was initially having some problems achieving a successful insertion with the updated Atlas.txt and table file you provided, I was able to narrow down the issue to one small mistake I made as I heavily edited the dictionary where a character length was off by one. Once I fixed that, I was able to do an insert that is 99% bug free (at least according to the appx 30% of game text that I've tested so far.) Here is the bug that's jumping out at me. The King of Cannock/Samaltria has some bugged text prior to his normal text. See the two pics below. The text seems to be from Hargon's Temple after you use the Charm/Eye of Rubiss to dispel the illusion

https://www.dropbox.com/s/txzrjqisvzwumuc/Dragon%20Warrior%20II%20-%20Edit_002.png?dl=0
https://www.dropbox.com/s/syx9sowi42u3j03/Dragon%20Warrior%20II%20-%20Edit_003.png?dl=0

After those lines, again he returns to his normal text, allows you to save, and remarks about his son. Very peculiar and I hope you have an idea how to fix it because I have no idea. Let's see if I find anything else like this, but I'm relieved that everything else has pointed to the right text so far. Here are links to my relevant files if you want to look at them regarding this issue. FYI my Atlas.txt script is significantly revised since I last sent it.

https://www.dropbox.com/s/5qo09huap2a5y2t/dw2_script.tbl?dl=0
https://www.dropbox.com/s/yn3qj00b536dxqt/Atlas.txt?dl=0
https://www.dropbox.com/s/fns0v7z1o6i8nxm/dw2_delocalized_052.ips?dl=0

One other thing. Regarding your Latin Translation project, are you planning to include any kind of uncensoring element? If you were I would be most grateful to enlist your efforts on that front. As you can see if you look in my patch I restored the Japanese church crosses and sprite for the priest. Unfortunately however, the priest is assigned the color palette of Princess Moonbrooke instead of what should be the Prince Midenhall/Laurasia palette. And then there's the matter of replacing the ghosts with original coffins but let me know if you're even interested in this graphical stuff. I must say that your long deceased Roman audience probably wouldn't have approved much of censorship--though the Latin speaking clergy would have demanded it I'm sure.  :D

*** Update

After my newest round of updates, King Samaltria's Kee Kee text went away. :o This is after it stuck around through the last 3 updates or so. I don't get it! Seems more like a bug in the game itself than a bug from the insertion

Title: Re: General NES Hacking Questions
Post by: abw on December 09, 2018, 01:58:13 pm
The King of Cannock/Samaltria has some bugged text prior to his normal text. See the two pics below. The text seems to be from Hargon's Temple after you use the Charm/Eye of Rubiss to dispel the illusion
[...]
After my newest round of updates, King Samaltria's Kee Kee text went away. :o This is after it stuck around through the last 3 updates or so. I don't get it! Seems more like a bug in the game itself than a bug from the insertion
This turns out to be a little bit of column A, a little bit of column B.

On the insert side, the game has a hardcoded value that tells it which pointer within the pointer table at ROM 0xB762-0xB7C1 starts reading from ROM bank 2 instead of ROM bank 5, but the insert script didn't update that value, so the pointer at ROM 0xB7BE started reading text from the wrong ROM bank, which threw off the end token counting before the script reached RAM $BFD7 and resulted in the wrong string being displayed. This is easily fixable by adding a COUNTER variable and an AUTOCMD for writing the counter like in the Dragon Quest IV example that ships with abcde, except Dragon Warrior II's script is only spread across 2 ROM banks instead of 6, so it's easier for II than IV.
Code: [Select]
// add this near the top of the insert script:
#VAR(pointerNum, COUNTER) // create a COUNTER variable named pointerNum
#CREATECTR(pointerNum, 8, 0) // pointerNum is an 8-bit value initialized to 0
#AUTOCMD($17FE7, #WLB(pointerNum, $3FA90)) // update the code that controls which pointer starts the next bank

// and then after every #W16 line in the insert script, add:
#INC(pointerNum, 1)

On the game side, there is a bug where the game takes the pointer to the start of the desired group of 16 strings and reads the first 2 bytes from the pointer's target *before* it runs through the code for checking whether the current string address has reached RAM $BFD7, so if you're unlucky enough to have a pointer point to RAM $BFD6 or $BFD7 like happened with your linked insert script, the text for that pointer gets seriously screwed up. There's currently no way for abcde to handle that situation for you automatically, so unfortunately you're just going to have to keep an eye on the pointer values, and if you see $BFD6 or $BFD7 come up, you can knock the #AUTOCMD($17FE7, *) addresses back to $17FE5 or $17FE6 respectively to compensate. It means you lose 1 or 2 bytes of script space, but that's probably easier to deal with than making the ASM changes required to fix the bug in the original game.

Both of these issues only show up depending on where the dividing line between ROM banks 5 and 2 falls in your new script compared to the original script, which explains why they would come and go as you continue updating and re-inserting your script.

One other thing. Regarding your Latin Translation project, are you planning to include any kind of uncensoring element? If you were I would be most grateful to enlist your efforts on that front. As you can see if you look in my patch I restored the Japanese church crosses and sprite for the priest. Unfortunately however, the priest is assigned the color palette of Princess Moonbrooke instead of what should be the Prince Midenhall/Laurasia palette. And then there's the matter of replacing the ghosts with original coffins but let me know if you're even interested in this graphical stuff. I must say that your long deceased Roman audience probably wouldn't have approved much of censorship--though the Latin speaking clergy would have demanded it I'm sure.  :D
I generally try to stick pretty close to the source material for various reasons (e.g. nostalgia, insufficienct fluency in Japanese, etc.), so as a rule of thumb, if my source was censored, so is my translation; if my source was not censored, neither is my translation. I can do graphics hacking if I have to, but while I appreciate the results of other people's graphics hacks, making my own just doesn't have the same appeal as translating does.

As for the ancient Romans, well, they were no strangers to censorship ("censor" itself is a Latin word), but I think a bigger problem there would be the lack of hardware and compatible power sources to play the translation on :P.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 09, 2018, 02:31:57 pm
Thank you for looking at this!

While inserting the lines you quoted in my Atlas.txt are easy enough, if I am to undertand correctly, even with the COUNTER variable and AUTOCMD added, there is still a possibility of seeing these kinds of issues pop up. This leads me to the second fix:

if you see $BFD6 or $BFD7 come up, you can knock the #AUTOCMD($17FE7, *) addresses back to $17FE5 or $17FE6 respectively to compensate. It means you lose 1 or 2 bytes of script space, but that's probably easier to deal with than making the ASM changes required to fix the bug in the original game.

I don't exactly understand the above instructions. Could you explain to me a little more clearly what you mean by "knock the #AUTOCMD($17FE7, *) addresses back to $17FE5 or $17FE6"? First, how do I see when $BFD6 or $BFD7 come up and then how do I actually knock them back to the other addresses.

And finally, my attempt to rally you to the cause of graphics work went exactly as expected. I can't be blamed for trying though!
Title: Re: General NES Hacking Questions
Post by: Choppasmith on December 09, 2018, 03:24:59 pm
Hey guys, with me finishing DW1, it's time for me to throw my hat into the text editing ring as well. I've been following this thread and I should be all caught up as far as having all the stuff I need. Big thanks to you abw for your help :)

abw, I noticed your table says you haven't figured out those control codes, but there's one in particular that's bugging me. In the python script posted on the first script there's a standalone byte, F2, which is a special "s" byte. It's used in the "piece<s> of gold" dictionary entry. I would take a good guess that this is the same as the EF byte in DW1 that adds or omits an S based of the number value used in the string. I'd hope to use this to change the battle message "[name][’ ]s HP is reduced by [number]." into "[name] takes [number] point(s) of damage". Is there a way I can update the table to use this standalone byte?
Title: Re: General NES Hacking Questions
Post by: abw on December 09, 2018, 04:44:32 pm
I don't exactly understand the above instructions. Could you explain to me a little more clearly what you mean by "knock the #AUTOCMD($17FE7, *) addresses back to $17FE5 or $17FE6"? First, how do I see when $BFD6 or $BFD7 come up and then how do I actually knock them back to the other addresses.
Oh, sorry, I meant you'll need to check the values of the pointers in the pointer table at ROM 0xB762-0xB7C1 (based on your current script size, 0xB7BE is the most likely culprit) following an insert to see if any of the values are $BFD6 or $BFD7 (a.k.a. D6 BF or D7 BF in little endian), and if so, then adjust the AUTOCMD commands in the insert script to fire when the insert point reaches $17FE5 or $17FE6 instead of $17FE7.

Basically, we need to make sure the game never tries to read script data at or after RAM $BFD7 / ROM 0x17FE7, and since the game unconditionally reads the first two bytes of the string based on the pointer value, pointer values of $BFD6 or $BFD7 are bad.

And finally, my attempt to rally you to the cause of graphics work went exactly as expected. I can't be blamed for trying though!
Based on your work from DW1, I think you'll be able to manage the graphics just fine without me :P.

Hey guys, with me finishing DW1, it's time for me to throw my hat into the text editing ring as well. I've been following this thread and I should be all caught up as far as having all the stuff I need. Big thanks to you abw for your help :)
Welcome to the party! (There's music for that in this game!) I figured you'd show up here sooner or later ;).

abw, I noticed your table says you haven't figured out those control codes, but there's one in particular that's bugging me.
I also assume the F2 code in DW2 works the same way as EF in DW1, so if you wanted to re-jig the dictionary to make that code available separately as opposed to being usable only as part of the "piece[(s)] of gold" entry, feel free. The process I described a couple of posts ago (https://www.romhacking.net/forum/index.php?topic=27053.msg367159#msg367159) should work just as well for this dictionary update as for "King" -> "Queen".

The codes I haven't bothered to check out are the F9, FD, and FF codes. Based on its usage in the script, F9 is probably some sort of item ID, though it'll take some research to figure out if and how it differs from F7. Some light experimentation suggested that FD might be useless, and FF looks like it might be some kind of conditional end token, but again, I haven't really looked at them to find out, so those are just guesses.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 09, 2018, 05:06:50 pm
Based on your work from DW1, I think you'll be able to manage the graphics just fine without me :P.

Hah. I'm glad my DW1 work *looks* impressive but truthfully all of that was my very first foray into hacking and more a result of elbow grease than actual skill. Most of it was simply spamming tiles from the famicom version all over the tile grid with a ton of duplication. The in game engine is still having the sprites point left, right, up, down etc but all of those directional tiles were simply replaced with the front facing famicom tiles so that they would display appropriately. The issues were when the US game would use mirrored images of tiles and that would put me in a spot where the famicom sprites would inevitably get screwed up. I would have to do little tricks to make the sprites more symmetrical like change the old wizard guy's head so his cap no longer leans to one side, or remove the guards spear because his body had to by symmetrical, all to work around the fact I couldn't disable the mirroring or point the code to different tiles.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 23, 2018, 04:19:50 pm
@abw

Since I'm pretty much done with my DW2 retranslation (perpetual rephrasings aside), I thought I would go back and give the first Dragon Warrior a bit of the old in out (or should I say "out in") with abcde. I figured I would let you and choppasmith have some time to bring your DW2 projects forward before I start assaulting you guys with requests for help on running extract and insert routines on DW3.

I got the table file that Choppasmith used, (byte format as opposed to the bit format one you sent me for DW2--I assume they both will work) and was pleasantly reminded to save it in UTF-8 per your readme. For the Cartographer.txt, I got the text pointer data from data crystal. I removed the auto jump instructions as I figured that would be DW2 specific. Gave it a shot and I got a ton of the same error message in command prompt: substr outside of string at C:\Rom Editing/abcde/Table/Table.pm line 234. It did spit out a very limited cartographer out file which I'll post a bit of immediately below. No in game text was captured in the output.

//POINTER #16 @ $8032 - STRING #16 @ $16FFE

#W16($8032)

// current address: $16FFE


//POINTER #17 @ $8034 - STRING #17 @ $1769B

#W16($8034)

// current address: $1769B


//POINTER #18 @ $8036 - STRING #18 @ $17A75

#W16($8036)

// current address: $17A75

This is what my Cartographer.text looks like below: (FYI I don't really need the comments for existing script turned on. I'm really only refining and expanding what I already wrote while I consult outside of game resources for the Japanese text.)

#GAME NAME:      Dragon Warrior I - Edit.nes

#BLOCK NAME:      Main Script
#TYPE:         NORMAL
#METHOD:      POINTER_RELATIVE
#POINTER ENDIAN:   LITTLE
#POINTER TABLE START:   $8012
#POINTER TABLE STOP:   $8037
#POINTER SIZE:      $02
#POINTER SPACE:      $00
#STRINGS PER POINTER:   16
#ATLAS PTRS:      Yes
#BASE POINTER:      $C010
#TABLE:         dw1_script.tbl
#COMMENTS:      No
#END BLOCK

I'm not sure if anything else needed to be changed. I figure pointer size would be the same. I'm not sure if DW1 also used 16 strings per pointer. Let me know if you think something is wrong here or if something needs to be tweaked with the table file for whatever reason. (attached below)

https://www.dropbox.com/s/h2uxum9jurl0jcb/dw1_script.tbl?dl=0
Title: Re: General NES Hacking Questions
Post by: abw on December 30, 2018, 04:12:13 pm
Try it again with "#BASE POINTER: $10" instead - the issue here is that a pointer value of e.g. $8028 + a base value of $C010 = $14038, but the entire ROM (including header) is only $14010 bytes, so we end up trying to read beyond the end of the file, which doesn't work so well. The other thing that might trip you up a bit is that the final pointer only has 10 strings instead of 16, so for a cleaner dump you'll want to split the main script in to two blocks:
Code: [Select]
#BLOCK NAME: Main Script
#TYPE: NORMAL
#METHOD: POINTER_RELATIVE
#POINTER ENDIAN: LITTLE
#POINTER TABLE START: $8012
#POINTER TABLE STOP: $8035
#POINTER SIZE: $02
#POINTER SPACE: $00
#STRINGS PER POINTER: 16
#ATLAS PTRS: Yes
#BASE POINTER: $10
#TABLE: dw1_script.tbl
#COMMENTS: No
#END BLOCK

// only 10 strings for the final pointer
#BLOCK NAME: Main Script
#TYPE: NORMAL
#METHOD: POINTER_RELATIVE
#POINTER ENDIAN: LITTLE
#POINTER TABLE START: $8036
#POINTER TABLE STOP: $8037
#POINTER SIZE: $02
#POINTER SPACE: $00
#STRINGS PER POINTER: 10
#ATLAS PTRS: Yes
#BASE POINTER: $10
#TABLE: dw1_script.tbl
#COMMENTS: No
#END BLOCK
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 30, 2018, 11:08:16 pm
Try it again with "#BASE POINTER: $10" instead - the issue here is that a pointer value of e.g. $8028 + a base value of $C010 = $14038, but the entire ROM (including header) is only $14010 bytes, so we end up trying to read beyond the end of the file, which doesn't work so well. The other thing that might trip you up a bit is that the final pointer only has 10 strings instead of 16, so for a cleaner dump you'll want to split the main script in to two blocks:
Code: [Select]
#BLOCK NAME: Main Script
#TYPE: NORMAL
#METHOD: POINTER_RELATIVE
#POINTER ENDIAN: LITTLE
#POINTER TABLE START: $8012
#POINTER TABLE STOP: $8035
#POINTER SIZE: $02
#POINTER SPACE: $00
#STRINGS PER POINTER: 16
#ATLAS PTRS: Yes
#BASE POINTER: $10
#TABLE: dw1_script.tbl
#COMMENTS: No
#END BLOCK

// only 10 strings for the final pointer
#BLOCK NAME: Main Script
#TYPE: NORMAL
#METHOD: POINTER_RELATIVE
#POINTER ENDIAN: LITTLE
#POINTER TABLE START: $8036
#POINTER TABLE STOP: $8037
#POINTER SIZE: $02
#POINTER SPACE: $00
#STRINGS PER POINTER: 10
#ATLAS PTRS: Yes
#BASE POINTER: $10
#TABLE: dw1_script.tbl
#COMMENTS: No
#END BLOCK

@abw, thank you as always for that and the explanation.

Unfortunately however the results were not successful. The output file contains a little bit of the script in a mashed together format with no delineation as I had with DW2. After the small section of script there is this massive block of information in byte format. Here's a copy if you want to take a glance. I'm scratching my head as to what would be causing this result.

https://www.dropbox.com/s/4tvfmtab1upy3vu/Cartographer_out.txt?dl=0

my command line instruction for output is basically the same as the one you recommended for DW2. Should any of that change in the case of this game?

perl abcde.pl -m bin2text -cm abcde::Cartographer "Dragon Warrior I - Edit.nes" Cartographer.txt Cartographer_out -s
Title: Re: General NES Hacking Questions
Post by: abw on December 31, 2018, 01:06:04 am
Ah, yes, that table file doesn't mark any of the table entries as end tokens, and with no end tokens there's nothing to say when to stop dumping, so each string keeps going until the end of the ROM :P. It also doesn't contain any newline markers, so even after fixing the end tokens you'd still end up with all 16 of each pointer's strings on one line, which didn't feel right to me. Here's the table file I've been using; feel free to adjust the \n linebreaks to match your desired format.
Code: [Select]
00=0
01=1
02=2
03=3
04=4
05=5
06=6
07=7
08=8
09=9
0A=a
0B=b
0C=c
0D=d
0E=e
0F=f
10=g
11=h
12=i
13=j
14=k
15=l
16=m
17=n
18=o
19=p
1A=q
1B=r
1C=s
1D=t
1E=u
1F=v
20=w
21=x
22=y
23=z
24=A
25=B
26=C
27=D
28=E
29=F
2A=G
2B=H
2C=I
2D=J
2E=K
2F=L
30=M
31=N
32=O
33=P
34=Q
35=R
36=S
37=T
38=U
39=V
3A=W
3B=X
3C=Y
3D=Z
3E=‟
3F=”
# 40 and 53 are visually identical, but 40 is used as a right single quotation mark while 53 is used as an apostrophe
40=’
41=*
42=[triangle-r]
43=[triangle-d]
44=:
45=[..]

47=.
48=,
49=-

4B=?
4C=!
4D=;
4E=)
4F=(
50=‘
# 51 is visually identical to 50, but does not trigger "speech" sound effects or auto-indentation
51=[‘; no sound, no indent]
52=[.’]
# 53 is the apostrophe version of 40
53='
54=[ ’]

5F=

F0=[ Point(s)]
F1=[(n )enemy name]
F3=[experience Point(s)]
F4=[enemy name]
F5=[number]
F6=[spell name]
F7=[item name]
F8=[HERO]
FB=[wait]
# FC is the end token used in the main script
/FC=[end]\n\n
FD=[line]\n
# FF is the end token used in the item/monster/spell lists
/FF=[/name]\n
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on December 31, 2018, 01:45:13 am
This worked perfectly. I'll have to study the format you used here for when I get through this revision and eventually move on to doing the same for DW3. I really want to develop the skill level to do this on my own, but the thing I'm most foggy on is what kind of process you use to figure out all these opcodes. Would  you do an initial extraction with just letters and the line breaks and then use context clues to flesh out the opcodes?
Title: Re: General NES Hacking Questions
Post by: abw on December 31, 2018, 01:17:34 pm
This worked perfectly.
Hurray!

I really want to develop the skill level to do this on my own, but the thing I'm most foggy on is what kind of process you use to figure out all these opcodes.
Every game is a world unto itself, so the only (as far as I know, anyway) guaranteed way to figure out how and where the game stores its text is by getting that text to display in a debugging emulator and tracing the code from the point where it writes the text to screen all the way backwards until you find the code that read the text from ROM. You'll need to be at least somewhat familiar with the console's hardware, the emulator's debugging features, and whatever variety of ASM the console uses, and it's usually a pretty time-consuming process, but it will give you highly detailed knowledge of how the game handles its text. Frequently, though, there are indeed easier ways.

Would  you do an initial extraction with just letters and the line breaks and then use context clues to flesh out the opcodes?
For games with simple text encodings like Dragon Warriors I and III, yeah, that's probably the fastest way to go about it. Making a table file based on how the individual character tiles are laid out in the PPU and then dumping a block of text (if you already know where the text and/or pointers are) or even loading the ROM and table file in a hex editor and running a quick visual scan through the ROM for blocks that look like text will go a long way towards getting a usable script dump. After that, it's usually not too hard to guess what any other codes appearing in the dump are supposed to do, especially if you're already familiar with what the text is supposed to say (e.g. due to playing the game obsessively as a child) or can find the string in-game. For ones you aren't too sure about, experimenting by removing them from the string or adding them elsewhere and observing how the game's behaviour changes will often shed more light on their purpose, and if all else fails, you can start diving in to the ASM.

For games with slightly trickier text encodings like the main scripts of Dragon Warriors II and IV, even if you know how the individual characters are laid out in the PPU, the game doesn't store the text that way in ROM and you're never going to be able to just guess how the text actually is stored within any reasonable time frame (unless somebody else has already done a bunch of work for you, thus allowing you to make better guesses), so the simple methods aren't going to work there and tracing through the game's code is probably the best way of finding out what in the world it's doing under the hood.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on January 01, 2019, 07:42:07 pm
Every game is a world unto itself, so the only (as far as I know, anyway) guaranteed way to figure out how and where the game stores its text is by getting that text to display in a debugging emulator and tracing the code from the point where it writes the text to screen all the way backwards until you find the code that read the text from ROM. You'll need to be at least somewhat familiar with the console's hardware, the emulator's debugging features, and whatever variety of ASM the console uses, and it's usually a pretty time-consuming process, but it will give you highly detailed knowledge of how the game handles its text. Frequently, though, there are indeed easier ways.

This brings me to a question. Over the last couple weeks I've been making a concerted effort to learn more about the NES architecture, study tutorials on the basics of ASM, and have spent more time playing with the FCEUX debugger. The 6502 NES ASM tutorials usually focus on teaching the basics of building an NES game from the ground up, which is good (if overwhelming) information but doesn't necessarily hone in on what I really want to be learning, which is what you highlighted--using the debugger to follow the data trails back to the rom code that dictates them. I've spent a lot of time looking for videos or tutorials around debugging and haven't come up with much. The only substantial information I've encountered is what was included in the FCEUX files themselves. Do you happen to recall anything in particular that helped you learn the process of tracing data back to its source? I think this is what would help me most not only with resolving some of these script editing issues but it would also help me track down how tile address instructions are stored in the code for the graphics work I need to do.
Title: Re: General NES Hacking Questions
Post by: abw on January 02, 2019, 10:39:17 am
Do you happen to recall anything in particular that helped you learn the process of tracing data back to its source?
Nothing specifically, alas. At a high level, the process is fairly simple: start with something you know (e.g. some text currently being displayed), figure out how that something got to be where it is / where it came from, and then keep repeating until "where it came from" is the ROM. The details can sometimes get messy, but FCEUX provides a pretty good collection of debugging tools for helping you do all that figuring out.

The Dragon Warrior code seems to be very fond of copying data back and forth between multiple staging areas in cartridge RAM before writing to the PPU, so even if you've mastered the use of FCEUX's Debugger, using its Trace Logger is probably still going to be a quicker way to find out useful information for these particular games. I wrote up a detailed description of tracking down DW1's item list and the pointer to it using FCUEX's Trace Logger in the Dragon Warrior 1 Spanish Translation (http://www.romhacking.net/forum/index.php?topic=26135.msg358879#msg358879) thread; you might find that helpful if you haven't read it already.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on January 06, 2019, 10:45:39 pm
@abw,

So I started the process of reinserting the script changes as I go. My main motivation for doing so was that I was hoping to be able to track how many characters worth of data remained available, as that indicator was very helpful while working on II.

After my first insert of my DW1 script, the command prompt curiously gave me no indication of remaining data afterwards. Other than that, the insertion seems to be working within the game. I believe I have some data available since I eliminated a ton of blank character spaces in the existing script. Am I missing something that turns that on this time around? This is the data I added to the top of my Atlas file.

// Define, load, and activate a TABLE
#VAR(Table, TABLE)
#ADDTBL("dw1_script.tbl", Table)
#ACTIVETBL(Table)

// Jump to start of script
#JMP($8038)
#HDR($10)

I didn't include the auto commands for mid-string swaps/counter variables, etc that were used in my Atlast file for DW2

I suppose I can pull the game up for myself in a hex editor to gauge how I'm doing with space but that command prompt indicator I always got before was very helpful.
Title: Re: General NES Hacking Questions
Post by: abw on January 07, 2019, 09:34:43 pm
Am I missing something that turns that on this time around?
Yup - without an upper bound on the insert range, there's no good way to calculate how much available space remains. abcde will just keep on inserting data until either it runs out of data to insert or your computer runs out of disk space (though I haven't tried that last one myself) :P. Try changing the jump command to e.g. "#JMP($8038, $BCBF)" and you should get some better feedback.

On a side note, I just submitted an update for abcde. Nothing major, but there are a couple of goodies that will be helpful if you end up doing some menu work on these games.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on February 06, 2019, 07:47:17 pm
So after a lot of editing (and I still wouldn't say it's 100% done) I managed to edit my script dump with the mobile script. It's 80K, about 50% bigger than the original.

I had to edit it a few times to fix some errors, thankfully abcde makes it easy to find what the troubled line is.

I then get this:

(https://i.imgur.com/DbrUmm6.png)

So far so good?


But then I get some scrambled text:

(https://i.imgur.com/DrJGHVe.png)

Looks like I need to double check my dictionary values. I hope that's my only problem.

EDIT: Yep dictionary and table needed a tiny tweak

(https://i.imgur.com/GxaFTL2.png)

Though, I think there's something funny with the special table provided in this thread. The combined .' for dialog works fine but the standalone closing quote/apostrophe just brings up the openign single quote instead

(https://i.imgur.com/9vw9uVS.png)

Also, getting some scrambled text. I wonder if this is from being over the limit. There's no way to immediately tell as said on the last page.

(https://i.imgur.com/8yK2JXO.png)

EDIT 2: Yeah the Midenhall castle NPC dialog is near the end of the first bank. If I'm reading it right, would using the script on the previous page be a way of transferring dialog/pointers to the second bank?
Title: Re: General NES Hacking Questions
Post by: abw on February 06, 2019, 10:28:36 pm
So after a lot of editing (and I still wouldn't say it's 100% done) I managed to edit my script dump with the mobile script. It's 80K, about 50% bigger than the original.

I had to edit it a few times to fix some errors, thankfully abcde makes it easy to find what the troubled line is.
You might want to grab the latest version (0.0.3) of abcde - I made some improvements like letting you know exactly how far over your limit the script goes. For your massive script, DW2 comes with 3 whole empty banks, so at least you shouldn't have to expand the ROM this time. If you haven't come across it yet, the code for switching between script banks starts at 0x3FE15 / $0F:$FE05, so that seems like a good place to start rewriting ASM.

Though, I think there's something funny with the special table provided in this thread. The combined .' for dialog works fine but the standalone closing quote/apostrophe just brings up the openign single quote instead
Yeah, like I said, I hadn't put much effort into the table file at that point, and I've noticed a couple of mistakes in it. I've uploaded my current table file here (https://drive.google.com/open?id=1MnB--MNEd4BG_IOxt4qZcwq3y6kigmMr) if you're interested, but if you've been modifying the dictionary, you'll also want to ensure that your dictionary does in fact contain the correct value.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on February 13, 2019, 02:42:50 pm
You might want to grab the latest version (0.0.3) of abcde - I made some improvements like letting you know exactly how far over your limit the script goes. For your massive script, DW2 comes with 3 whole empty banks, so at least you shouldn't have to expand the ROM this time. If you haven't come across it yet, the code for switching between script banks starts at 0x3FE15 / $0F:$FE05, so that seems like a good place to start rewriting ASM.
Yeah, like I said, I hadn't put much effort into the table file at that point, and I've noticed a couple of mistakes in it. I've uploaded my current table file here (https://drive.google.com/open?id=1MnB--MNEd4BG_IOxt4qZcwq3y6kigmMr) if you're interested, but if you've been modifying the dictionary, you'll also want to ensure that your dictionary does in fact contain the correct value.

Thanks for that, I've updated my table. I tried using the newest version of your abcde, I now get: "#JMP bounded by at $BE0F has -15738 ($-3D7A) space left" So I take it this means my script overwrites 15,738 bytes over the limit of the bank? Would cutting down my script temporarily be a good way to indicate where would be a good stopping point for the first bank? (I know I can't just go into the ROM and see where it overwrites data) BTW, maybe I'm missing something (and I'll be honest, I'm earnest in learning but a lot of this stuff still makes me go @_@) Why is it in the ROM Map, The Main Script Part 1 starts at B7C2 and Part 2 starts at 14010 but in the atlas script they're the other way around?
Title: Re: General NES Hacking Questions
Post by: abw on February 13, 2019, 06:38:46 pm
Thanks for that, I've updated my table. I tried using the newest version of your abcde, I now get: "#JMP bounded by at $BE0F has -15738 ($-3D7A) space left" So I take it this means my script overwrites 15,738 bytes over the limit of the bank? Would cutting down my script temporarily be a good way to indicate where would be a good stopping point for the first bank? (I know I can't just go into the ROM and see where it overwrites data)
If you want to get technical about it, the script space is already split between 2 banks, so that means you're 15,738 bytes over the total script space limit rather than the bank limit, but basically, yes. For finding out how much of your script fit into the first bank, you can check 0x3FA90 to see which pointer starts the next bank; if your new script is twice as big as the original, you'll probably have something like $17 there instead of $2E. Temporarily cutting down your script is probably the fastest way to find out how much fits into the original script space, though since it looks like you're going to need 3 banks anyway, you may wish to consider moving the script space from 0xB7C2-0xBE0F to one of the unused banks; some of DW2's bankswap routines are limited to swapping in one of the first 8 banks, so having lots of free space in bank 3 might come in handy if you plan on making other changes too.

BTW, maybe I'm missing something (and I'll be honest, I'm earnest in learning but a lot of this stuff still makes me go @_@) Why is it in the ROM Map, The Main Script Part 1 starts at B7C2 and Part 2 starts at 14010 but in the atlas script they're the other way around?
Oh, sorry, that was my fault - I was in "sort things by ROM address" mode :P. I've corrected the wiki now.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 01, 2019, 02:50:31 pm
Sorry for the late reply, just been finding no time to spare lately, but I'm still determined to learn and get this figured out.

So I found that I can fit up to "Pointer 34" in the original space (with 818 bytes left over which is plenty for possible edits and additions) leaving the text from Pointer 35-45 and the last little bit of "Script Part 2" left.

I also inserted just the script AFTER Pointer 34 into the original space and got 1401 bytes left. So by doing a little bit of math subtracting those numbers from 17,955 (the combined amount of bytes for script space according to the ROM Map) means the first part of my script that fits is 17,137 bytes and the remaining is 16,554 meaning my whole script is 33,691 bytes. So yeah despite different text file sizes, the actual script data is about double.

So I'm already a little confused here...

Firstly


For finding out how much of your script fit into the first bank, you can check 0x3FA90 to see which pointer starts the next bank; if your new script is twice as big as the original, you'll probably have something like $17 there instead of $2E.

So what am I looking at here (at 3FA90) exactly? It certainly says 2E. What does that signify?

And secondly, more a noobish question, but am I understanding correctly that the Wiki stating the game has 16 PRG-ROM Pages that are 16KB each referring to the banks? If I do switch banks for dialog, and yes I can see there are plenty of blank patches of data, is there an easy way to determine what bank is where aside from trying to divide the bytes of the rom by 16? I feel like I'm missing something glaringly obvious.

As far as doing anything else. The only thing I might do is what you and Chicken Knife talked about in moving the Monster Names. I had shortened the names just enough to fit, but having that extra little bit of space for having full names would be nice. Script is the priority for me though!

Anyway, once again, I appreciate the help and feel free to tell me just enough so I can figure it out while learning. Certainly don't want to come off as the type who just wants stuff done for them!
Title: Re: General NES Hacking Questions
Post by: abw on March 01, 2019, 06:52:28 pm
So what am I looking at here (at 3FA90) exactly? It certainly says 2E. What does that signify?
What you've got there is the key byte inside the routine for deciding which ROM bank needs to be swapped in to get the string the game wants to display:
Code: [Select]
; determine which ROM bank to load based on string index
; IN: A = low byte of string index, X = high byte of string index << 5 (don't ask me why), Y and C irrelevant
; OUT: no change to A or X, Y = index of ROM bank to swap in to read the string from, C not used, but does indicate whether we ended up choosing bank 5 (clear) or 2 (set)
; control flow target (from $FA68)
0x03FA7E|$0F:$FA6E:A0 05    LDY #$05 ; default to bank 5
0x03FA80|$0F:$FA70:48      PHA ; save the original string index in A
0x03FA81|$0F:$FA71:29 F0    AND #$F0 ; useless op
0x03FA83|$0F:$FA73:4A      LSR
0x03FA84|$0F:$FA74:4A      LSR
0x03FA85|$0F:$FA75:4A      LSR
0x03FA86|$0F:$FA76:4A      LSR
0x03FA87|$0F:$FA77:85 10    STA $10 ; 16 strings per pointer, so low byte of string index >> 4 = low nybble of pointer index
0x03FA89|$0F:$FA79:8A      TXA
0x03FA8A|$0F:$FA7A:29 E0    AND #$E0
0x03FA8C|$0F:$FA7C:4A      LSR ; A = high nybble of pointer index
0x03FA8D|$0F:$FA7D:05 10    ORA $10 ; glue the high and low nybbles of the pointer index together into a single byte
0x03FA8F|$0F:$FA7F:C9 2E    CMP #$2E
0x03FA91|$0F:$FA81:90 02    BCC $FA85 ; if the pointer index < #$2E, keep the bank 5 default
0x03FA93|$0F:$FA83:A0 02    LDY #$02 ; if the pointer index >= #$2E, load bank 2 instead
; control flow target (from $FA81)
0x03FA95|$0F:$FA85:8C C6 60 STY $60C6
0x03FA98|$0F:$FA88:68      PLA ; restore the original string index in A
; control flow target (from $D12B)
; external bank control flow target (from $06:$9542, $06:$9550)
0x03FA99|$0F:$FA89:60      RTS
If you added the #INC commands I mentioned in an earlier post (http://www.romhacking.net/forum/index.php?topic=27053.msg367369#msg367369), that #$2E should have been updated to reflect the new dividing line between bank 5 and 2.

The good news is that it looks like you are pretty close to being able to fit your script into just 2 banks, and if you can manage that, then all you need to do is insert the second half of your script into one of the unused banks and update 0x3FA94 to the new bank number. Do you think you can update the dictionary to get an extra 3% compression?

And secondly, more a noobish question, but am I understanding correctly that the Wiki stating the game has 16 PRG-ROM Pages that are 16KB each referring to the banks?
Yup!

is there an easy way to determine what bank is where aside from trying to divide the bytes of the rom by 16? I feel like I'm missing something glaringly obvious.
Math is the way (especially when you're flipping between games with different bank sizes), but this shouldn't be something you need a calculator for. 16 KB = $4000, so (ignoring the $10 byte iNES header), $0000 - $3FFF is bank 0, $4000 - $7FFF is bank 1, $8000 - $BFFF is bank 2, $C000 - $FFFF is bank 3, and so on. So if you have an address like 0x3FA90, you can look at the 3F part and say something to yourself like "3 x 4 = 12, F is in bank 3, and 12 + 3 = 15" to know that 0x3FA90 is in ROM bank 15.

Anyway, once again, I appreciate the help and feel free to tell me just enough so I can figure it out while learning. Certainly don't want to come off as the type who just wants stuff done for them!
Heh, the first game was free, but you're going to have to work for the second one :D.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 02, 2019, 12:23:48 pm
Heh, the first game was free, but you're going to have to work for the second one :D.

Sounds fair :) I'll get this slowly but surely.

Okay, so, in updating my dictionary, I had to update the table because I was still unable to use apostrophes and single closing quotes. Part of my new dictionary table looks like this (taken from your latest table)

Code: [Select]
%1110110101='
%1110110110=-
%1110110111=’

I do the insert.bat and it stops at a line at Pointer 26

Code: [Select]
C:\Users\mog11\Downloads\abcde_v0_0_3>perl abcde.pl -m text2bin -cm abcde::Atlas "DRAGONW2.nes" Atlas.txt
unable to tokenize; best attempt failed at input position 160 at ^ indicator in
]'s coffin.[end-FC]‘'Tis more than a ma
]'s coffin.[end-FC]ΓÇÿ^
(does your table file contain a ""?) in text string starting at Atlas.txt line 1127!

And here's the line as it appears in my atlas.txt

Code: [Select]
puts it back in [name]'s coffin.[end-FC]

‘'Tis more than a man could ask to know such elation at so advanced an age!’[wait][line]

Really baffling what happened here. It's not like this is the first apostrophe in the text.

Also, while I updated the dictionary to save a few bytes (adding a space for "gold", "Goddess", and "key") I found that I missed a bunch of post-final boss NPC dialog that needed adding, so droping it 3% might be out unfortunately.
Title: Re: General NES Hacking Questions
Post by: abw on March 02, 2019, 06:13:33 pm
I do the insert.bat and it stops at a line at Pointer 26

Code: [Select]
C:\Users\mog11\Downloads\abcde_v0_0_3>perl abcde.pl -m text2bin -cm abcde::Atlas "DRAGONW2.nes" Atlas.txt
unable to tokenize; best attempt failed at input position 160 at ^ indicator in
]'s coffin.[end-FC]‘'Tis more than a ma
]'s coffin.[end-FC]ΓÇÿ^
(does your table file contain a ""?) in text string starting at Atlas.txt line 1127!

And here's the line as it appears in my atlas.txt

Code: [Select]
puts it back in [name]'s coffin.[end-FC]

‘'Tis more than a man could ask to know such elation at so advanced an age!’[wait][line]

Really baffling what happened here. It's not like this is the first apostrophe in the text.
Hmm, that does look odd. Based on that output, it looks like your system is defaulting to code page 437 (where "ΓÇÿ" = E2 80 98 = the UTF-8 encoding of U+2018 = "‘"), which means "┬ì" = C2 8D = the UTF-8 encoding of U+008D = Reverse Line Feed, but I have no idea how that managed to get in there. So, it looks like you've got an invisible character sitting between the "‘" and the "'" for some reason (you should be able to verify that hypothesis by viewing your insert script with a hex editor); try deleting that section and re-type the "‘'".

Also, here's a tip from abcde's readme: if you do "chcp 65001" in cmd before running abcde (e.g. at the start of a .bat file), you should get abcde's UTF-8 output showing up as UTF-8 characters instead of whatever code page your system defaults to... though in a case like this involving a non-printable control code, having gobbledygook is probably more helpful in tracking down the cause of the error!

Also, while I updated the dictionary to save a few bytes (adding a space for "gold", "Goddess", and "key") I found that I missed a bunch of post-final boss NPC dialog that needed adding, so droping it 3% might be out unfortunately.
Ah, if you have more text to add anyway, then yeah, trying to fit everything into 2 banks might be more work than just using 3 banks. So much for only needing a 1-byte hack :P.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 05, 2019, 11:14:58 am
Okay figured out the weird little script bug (you were right, there was some weird hex between the opening quote and the apostrophe). And with the recent dialog added 34,221 bytes.

Just to be sure. Your abcde script enters the script in both areas, right? I just want to make sure my math is right. The space remaining that I get when inserting part of it is the total amount between the two sections? Not just one? Because it seems like the best free space to use as a third bank is 1CC30 which is over 13K.

Old Script Part 1: 3FD7 Length (16, 343)
Old Script Part 2: 64E Length (1,614)
Total: 17,957

And to use a third bank I'm basically going to have to duplicate this part of the code:

Code: [Select]
0x03FA91|$0F:$FA81:90 02    BCC $FA85 ; if the pointer index < #$2E, keep the bank 5 default
0x03FA93|$0F:$FA83:A0 02    LDY #$02 ; if the pointer index >= #$2E, load bank 2 instead

And change the pointer index and bank so that it's something like pointer index < #$22 (Pointer 34) then have something for Pointer 35-45 and then have a line for code 2E (46) equal and greater in value. Is that right?
Title: Re: General NES Hacking Questions
Post by: abw on March 05, 2019, 05:18:32 pm
Okay figured out the weird little script bug (you were right, there was some weird hex between the opening quote and the apostrophe).
Hurray!

Just to be sure. Your abcde script enters the script in both areas, right? I just want to make sure my math is right. The space remaining that I get when inserting part of it is the total amount between the two sections? Not just one?
Yup, yup, and yup.

Because it seems like the best free space to use as a third bank is 1CC30 which is over 13K.
I'd probably go with one (or two if you need another one) of the completely unused banks starting at 0x30010, 0x34010, or 0x38010 for a full 16k each, but if you can fit all your script into the free space starting around 0x1CC30, then great.

And to use a third bank I'm basically going to have to duplicate this part of the code:

Code: [Select]
0x03FA91|$0F:$FA81:90 02    BCC $FA85 ; if the pointer index < #$2E, keep the bank 5 default
0x03FA93|$0F:$FA83:A0 02    LDY #$02 ; if the pointer index >= #$2E, load bank 2 instead

And change the pointer index and bank so that it's something like pointer index < #$22 (Pointer 34) then have something for Pointer 35-45 and then have a line for code 2E (46) equal and greater in value. Is that right?
Basically, yeah. You'll just need to find a home for that code, but bank F is already pretty full. There should be enough unused space for your needs at 0x3FFA7 - 0x3FFC9 (0x3FFCA is used!), though. It also possible there's other code elsewhere that might need to be updated too; I haven't done that analysis for you this time either ;).
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 10, 2019, 02:36:55 pm
Oh Happy Day! Feeling overwhelmed by the idea of having to move important code around, I took another crack at editing the dictionary, swapping out entries with about 15 or so uses with ones much higher and I got my script down to 32,378 bytes! And I can totally trim the fat in my script if need be. That should be much easier! What a relief!

So, if I keep bank 5 as default and go with your suggestion of using the space at 30010 (thanks btw, I didn't really think of looking that far, I didn't think there'd be full unused banks) which would be bank... 10, right? That would change the value of 3FA94 to 0A.

Now I just need to add the bit from your earlier post so it can split the script properly. Edit: yes the JMP is updated to reflect the dumping to the new bank.


Code: [Select]
// add this near the top of the insert script:
#VAR(pointerNum, COUNTER) // create a COUNTER variable named pointerNum
#CREATECTR(pointerNum, 8, 0) // pointerNum is an 8-bit value initialized to 0
#AUTOCMD($17FE7, #WLB(pointerNum, $3FA90)) // update the code that controls which pointer starts the next bank

// and then after every #W16 line in the insert script, add:
#INC(pointerNum, 1)

// Jump to start of script
#JMP($14010)
#HDR($C010)
// auto-commands for when DW2 does a mid-string bankswap and resets its read address:
#AUTOCMD($17FE7, #HDR($10))
#AUTOCMD($17FE7, #JMP($30010, $3400F))

Edit: yes the JMP is updated to reflect the dumping to the new bank. I seem to be close. Once trying with my full script (as opposed to pieces to determine length and where the best split would be) I get "#JMP bounded by at $3400F has -1223 ($-4C7) space left" so it seems maybe it's still a bit too big? Did I make a miscalculation somewhere? Either way, 1K to trim down should be easy and inconsequential.
Title: Re: General NES Hacking Questions
Post by: abw on March 10, 2019, 05:05:58 pm
Oh Happy Day! Feeling overwhelmed by the idea of having to move important code around, I took another crack at editing the dictionary, swapping out entries with about 15 or so uses with ones much higher and I got my script down to 32,378 bytes! And I can totally trim the fat in my script if need be. That should be much easier! What a relief!
Nice!

So, if I keep bank 5 as default and go with your suggestion of using the space at 30010 (thanks btw, I didn't really think of looking that far, I didn't think there'd be full unused banks) which would be bank... 10, right? That would change the value of 3FA94 to 0A.
Remember how we expanded the DW1 ROM by adding 4 new banks just before the final fixed bank? Enix did basically the same thing (except in hardware) when porting the game to English; they had to add 8 banks, but didn't end up using 3 of those.

In bank 5, you've got $17FE7 - $14010 = $3FD7 bytes, and bank 12 ($0C) gives you another $4000 bytes for a total of $7FD7 = 32,727 bytes, which should leave you with about 350 bytes to spare if you managed to get your script down to 32,378 bytes. Is that 32,378 bytes the script size after being converted to DW2's 5/10-bit encoding, or is that the file size when encoded as UTF-8?

If you're still having space issues, don't forget about the single-character dictionary entries - if you're e.g. using "p" more than "w", you could kick "w" into the 10-bit range and move "p" into the 5-bit range to get better compression. For English text, you can probably also replace the "q" entry with "qu".
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 10, 2019, 05:24:29 pm
Nice!
Remember how we expanded the DW1 ROM by adding 4 new banks just before the final fixed bank? Enix did basically the same thing (except in hardware) when porting the game to English; they had to add 8 banks, but didn't end up using 3 of those.

In bank 5, you've got $17FE7 - $14010 = $3FD7 bytes, and bank 12 ($0C) gives you another $4000 bytes for a total of $7FD7 = 32,727 bytes, which should leave you with about 350 bytes to spare if you managed to get your script down to 32,378 bytes. Is that 32,378 bytes the script size after being converted to DW2's 5/10-bit encoding, or is that the file size when encoded as UTF-8?

Well, as said a few posts ago, I split my script into two parts to determine how much of it would fit. I took the bytes remaining as reported by abcde and subtracted from the total space available and did it again for the second part then combined the values which is how I got the 32,378 bytes. I had done the same thing before and I was getting over 34,000 bytes, so even if my math is somehow off it's still a significant decrease.

Nice!
Remember how we expanded the DW1 ROM by adding 4 new banks just before the final fixed bank? Enix did basically the same thing (except in hardware) when porting the game to English; they had to add 8 banks, but didn't end up using 3 of those.

In bank 5, you've got $17FE7 - $14010 = $3FD7 bytes, and bank 12 ($0C) gives you another $4000 bytes for a total of $7FD7 = 32,727 bytes, which should leave you with about 350 bytes to spare if you managed to get your script down to 32,378 bytes. Is that 32,378 bytes the script size after being converted to DW2's 5/10-bit encoding, or is that the file size when encoded as UTF-8?

If you're still having space issues, don't forget about the single-character dictionary entries - if you're e.g. using "p" more than "w", you could kick "w" into the 10-bit range and move "p" into the 5-bit range to get better compression. For English text, you can probably also replace the "q" entry with "qu".
Yeah that could work. I would assume, in layman's terms, that the first set of entries use less data than the 4 "C" tables? Or does each table use extra bits of data the further you go down? (Edit : forget that I'm dumb)I honestly still don't quite understand how those work, I initially thought it was like a special table where'd you use two bytes to load a dictionary value, and pretty much every word/letter from the dictionary wound be preceded by the corresponding value and then stuff from the first table fills in the rest with no dictionary value needed.

Edit : Just read the Wiki, I guess it works like I said above but in bits, not bytes?
Title: Re: General NES Hacking Questions
Post by: abw on March 10, 2019, 06:12:36 pm
Yeah that could work. I would assume, in layman's terms, that the first set of entries use less data than the 4 "C" tables? Or does each table use extra bits of data the further you go down? (Edit : forget that I'm dumb)I honestly still don't quite understand how those work, I initially thought it was like a special table where'd you use two bytes to load a dictionary value, and pretty much every word/letter from the dictionary wound be preceded by the corresponding value and then stuff from the first table fills in the rest with no dictionary value needed.

Edit : Just read the Wiki, I guess it works like I said above but in bits, not bytes?
Basically, yeah. I had this typed up before I saw your edit, so I'll post it anyway just in case it's still helpful:
--
Sort of, except as far as the game's concerned, the individual tokens are 5 bits each, not 8, and 4 of the entries from the first 5-bit table are used to switch to the corresponding "C" table. You could split that single table file into multiple table files if you wanted to; I just prefer having all the entries in a single table.

You can tell how much space each entry takes up by looking at its left-hand side. In a hexadecimal table, "80" takes up one byte (or 2 nybbles or 8 bits, depending on how you want to think of it), "80FF" takes up two bytes (/4 nybbles/16 bits), and so on; in a binary table, "11011" takes up 5 bits, "1110101111" takes up 10 bits, and so on. This will be an even bigger issue if you decide to tackle DW4, since it uses a Huffman encoding where the binary representation of individual characters ranges between 3 bits (e.g. for "e") and 18 bits (e.g. for "8").
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 11, 2019, 03:18:44 pm
Basically, yeah. I had this typed up before I saw your edit, so I'll post it anyway just in case it's still helpful:
--
Sort of, except as far as the game's concerned, the individual tokens are 5 bits each, not 8, and 4 of the entries from the first 5-bit table are used to switch to the corresponding "C" table. You could split that single table file into multiple table files if you wanted to; I just prefer having all the entries in a single table.

You can tell how much space each entry takes up by looking at its left-hand side. In a hexadecimal table, "80" takes up one byte (or 2 nybbles or 8 bits, depending on how you want to think of it), "80FF" takes up two bytes (/4 nybbles/16 bits), and so on; in a binary table, "11011" takes up 5 bits, "1110101111" takes up 10 bits, and so on. This will be an even bigger issue if you decide to tackle DW4, since it uses a Huffman encoding where the binary representation of individual characters ranges between 3 bits (e.g. for "e") and 18 bits (e.g. for "8").

Thanks, once I saw that the programmer's calculator had a binary converter, it just clicked.

Anyway, just from doing the above suggestion I'm down another 400 bytes! And just after some needed editing of the intro I'm now down to 760 bytes over the limit. I was really loose and liberal with my initial script (like gratuitous line breaks, pauses, and spaces), so it should be easy to trim the fat without sacrificing much. Although when I tried dumping with the new second address, I'd get horrible garbage dialog. The intro is only the 8th pointer in bank 5, so I'm not too sure what happened there. I know I have to update the ROM with the new second bank, but I'm not sure why dialog in the beginning wouldn't work properly. Did I miss something (other than updating the second bank?)

A couple other weird issues

Still having trouble with closing single quotes for some reason.

(https://i.imgur.com/w2bUVKS.png)

I double checked the ROM and I do indeed have $66 in the dictionary. I also have an entry with "!’" but that has Apostrophes ($67) work fine though

Also

(https://i.imgur.com/VrR1E2T.png)

Not sure what's going on here. There's a couple of windows like this with the oddly premature uncalled for line break. I'm assuming the window counts how many bits are used per line as opposed to individual letters/spaces/characters? Any suggestions? Or is it just a weird game programming/abcde limitation?
Title: Re: General NES Hacking Questions
Post by: abw on March 11, 2019, 08:03:16 pm
Hurray! The proper choice of dictionary entries makes a huge difference to the compression ratio. Just make sure you leave the first 5 end tokens and the 4 "C" table switches alone (since the game cares about those) and fill out the rest of the main 5-bit table with your 23 best tokens.

As for your issues, it's kind of hard to say for sure without seeing the files. If dumping the inserted data didn't work but the game still displays it correctly, then something is wrong with your dump script. For the closing single quotes, my next guess would be an error in the dictionary lengths, though a length error would also mess up all the dictionary entries following the one with the wrong length. The random line breaks is definitely strange too, and not an issue I've come across myself; I've definitely inserted longer strings than that without getting inappropriate line breaks. I haven't looked at the code for it, but just based on observation, DW2's line wrapping algorithm seems pretty solid. Any chance it always happens around the words "What" or "is"? If so, that could indicate that you've got a line break instead of a space in one of the dictionary entries - just a guess!
Title: Re: General NES Hacking Questions
Post by: Choppasmith on March 16, 2019, 06:27:57 pm
I got it! I had used Pointer Tables to extract, edit, and insert the dictionary entries. Yeah, I know it's clunky, but easy for me. It was changing blank spaces (5F) to [no voice] (59). Once I changed it in the ROM it was fine. Similar problem with the closing single quotes and I fixed that too. I was hoping that this could've shrunk the script size, but, alas, it didn't. Oh well, more editing work for me!

Congrats on your Latin translation release, abw! I had looked at the Read Me and you said one of your improvements was editing the main party status windows to show (was this battle or field or both?) full character names instead of just showing the first four letters.

When working on DW1 menus, the thought of doing that for later entries struck me as a "would be nice if possible". You mentioned it was more than a one byte hack. Were there other entries for the window you had to change besides length? Or is it like monster/item/spell/etc names where you had to find that value that affected display length? Btw, I know it'd be easy to tell the magic byte that affects monster name length like DW1, but you did explain how you did it and I have every intention to try myself as part of my learning.
Title: Re: General NES Hacking Questions
Post by: abw on March 17, 2019, 05:53:07 pm
I got it!
Congrats!

Congrats on your Latin translation release, abw! I had looked at the Read Me and you said one of your improvements was editing the main party status windows to show (was this battle or field or both?) full character names instead of just showing the first four letters.

When working on DW1 menus, the thought of doing that for later entries struck me as a "would be nice if possible". You mentioned it was more than a one byte hack. Were there other entries for the window you had to change besides length? Or is it like monster/item/spell/etc names where you had to find that value that affected display length?
Thanks! If you check the screenshots, you'll see that full character names are displayed both in and out of battle; I think I made changes for displaying full names in a total of 37 different menus, which typically also involved widening and repositioning them and sometimes also involved making updates to the menu wiping process; the WEAPON/ARMOR/SHILD/HELMET menus were particularly irritating to deal with in that respect. For the code changes, the basic problem is that DW2 stores the first 4 characters of each hero's name in one spot and the last 4 characters in a completely different spot (probably due to the English version's extra 4 characters being bolted on to the original 4 characters present in the Japanese version), so you can't just find the code that says "read 4 bytes from X" and update one byte to say "read 8 bytes from X", you need to add more code (which needs more space) to read 4 bytes from X and glue them together with 4 bytes from Y.

For the later games in the series, the mini status menu was rearranged into 1 column per hero instead of 1 row per hero, so widening the columns probably wouldn't work out very well due to lack of screen space if everybody has a long name, but you could switch the layout back to rows if you wanted. It's just a question of how much work would be involved.

Btw, I know it'd be easy to tell the magic byte that affects monster name length like DW1, but you did explain how you did it and I have every intention to try myself as part of my learning.
Trace logger is your friend there too!
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 16, 2019, 03:08:52 pm
Basck from vacation and ready to tackle this!

Okay, I'm having a strange pointer issue (at least I think it's Pointer related). I got my script (with around 19 bytes to spare!)

When the game loads the intro, instead of loading the line

"This is the royal castle of the kingdom of Moonbrooke." which is Pointer 7, String 14 it loads instead, "‘We shall await thy return most eagerly!’" Which is a couple lines up at String 12. Granted I removed the "Hold Reset" dialog to save space but I double checked and I don't see any missing end-FC marks I might've missed that would cause the issues. What's weird is, in the next pointer, the first two lines load just fine but everything after is mixed up.

Did I mess up the formatting of my atlas.txt somehow? It's right here
http://www.mediafire.com/file/e7kqqhf720plzpf/atlas.txt/file

(note because of the trouble Chicken Knife had with his script mentioned earlier in this thread, I opted to extract the script with comments:off so it's just the new dialog)

I know I read your post, abw, a couple pages back about the ROM flaw that pointers could get mixed up, but I'm not sure I understand what you mean by checking them. In DW1, I could load up the ROM in Windhex, look at the start of the string, the address, then compare it with the pointer, but I'm not sure how I can do that with DW2's compression.
Title: Re: General NES Hacking Questions
Post by: darthvaderx on April 16, 2019, 05:26:13 pm
Is it possible to run Lua Script in Mesen in the same way as in FCEUX? I've tried to run Metroid in every way but none worked.
Title: Re: General NES Hacking Questions
Post by: abw on April 16, 2019, 09:56:29 pm
When the game loads the intro, instead of loading the line

"This is the royal castle of the kingdom of Moonbrooke." which is Pointer 7, String 14 it loads instead, "‘We shall await thy return most eagerly!’" Which is a couple lines up at String 12.
I'm not seeing anything immediately obvious that would cause that kind of error, and a quick test with a version of the original table file tweaked to include your new characters gets me the expected text displayed during the entire intro sequence, so I suspect your problem lies elsewhere. Getting an earlier string from the same pointer makes me think the game might be counting more end tokens than you want it to... what does your table file look like? If you altered any of the first 5 entries, that might explain this behaviour.

I know I read your post, abw, a couple pages back about the ROM flaw that pointers could get mixed up, but I'm not sure I understand what you mean by checking them.
Basically you just pop open the ROM in a hex editor, look at 0xB772-0xB7D0, and check whether any of those pointers point to $BFD6 or $BFD7. If they do, then you'll need to move the auto-jump point (0x17FE7) back a byte or two in order to force the affected pointer to point into the second script bank instead of letting it read non-script data from the first script bank and make a mess of your text.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 18, 2019, 04:42:11 pm
I'm not seeing anything immediately obvious that would cause that kind of error, and a quick test with a version of the original table file tweaked to include your new characters gets me the expected text displayed during the entire intro sequence, so I suspect your problem lies elsewhere. Getting an earlier string from the same pointer makes me think the game might be counting more end tokens than you want it to... what does your table file look like? If you altered any of the first 5 entries, that might explain this behaviour.
Basically you just pop open the ROM in a hex editor, look at 0xB772-0xB7D0, and check whether any of those pointers point to $BFD6 or $BFD7. If they do, then you'll need to move the auto-jump point (0x17FE7) back a byte or two in order to force the affected pointer to point into the second script bank instead of letting it read non-script data from the first script bank and make a mess of your text.

Okay that went better than I hoped!  :laugh:

So, when you suggested the problem (thanks for that, it's easy for me to overlook little things like that), it was indeed something I did with my table/dictionary. I thought I'd swap the standalone [FF] with the standalone Period that was further down. Once I swapped it back, the intro text displayed fine again. Lesson learned. Adding a note in my copy of the table: DO NOT MESS WITH THE FIRST 5 VALUES! Only problem was I went from just being under the limit by about 20 bytes, to being OVER the limit by about 60. So I had to scour the dictionary again to see if there was some way to get the size back down. After adding a space to the comma entry and replacing the unused ; by realizing I had a lot of words and phrases that ended in "eth" and boom that was enough to put me WELL under with about 140 bytes to spare. WOW! I'm ecstatic! I should be able to restore the little bit I had to cut (mostly consists of long gratuitous laughs, pauses, and a post-final boss NPC line).

Anyway when I asked about changing the second text bank at 3FA94, I figured having the second block at $3400F would make it Bank 10 (0A) but when you replied with an explanation of how the bank swapping work, you mentioned Bank 12 and I'm not sure if you were just giving an unrelated example, subtly correcting me, or just made a typo. I'm getting some messed up text by a couple of the Midenhall Castle NPCs using either value (either blank windows or a sparse random letter) so i figured I'll have to look at those pointers, but I want to make sure I'm not doing this with the wrong bank value.

EDIT: These are my values between b772-B7D0

16 90 73 92 7D 92 87 92 91 92 9B 92 A5 92 AF 92 B9 92 02 94 19 95 3E 96 12 98 37 99 12 9C 62 9E 35 A1 0A A4 CE A7 AB AB 5E AF 68 AF 72 AF 7C AF 86 AF 42 B4 37 BB 43 02 B1 07 93 0E 4A 13 FC 17 7D 1B 88 1E 1C 22 54 27 A0 2D 9D 31 16 35 0A 39 DF B4 EB A0 4D BB 17 F4 F9 C3 E2 57 C0 E7 8F 9D

So, nothing wrong there, then?

Edit 2: So am I understating right that my problem is probably between Pointer 32 and 35 which is pointer B7A2 and B7A8 respectively? Since B7A8 points to the new bank? Pointer 32 has a lot of the Midenhall dialog, some of which is displayed properly. Sorry to say, I'm still puzzled here.
Title: Re: General NES Hacking Questions
Post by: abw on April 19, 2019, 12:01:43 am
Okay that went better than I hoped!  :laugh:
[...]
Adding a note in my copy of the table: DO NOT MESS WITH THE FIRST 5 VALUES!
Hurray! To be fair, I did actually mention that a few posts back (http://www.romhacking.net/forum/index.php?topic=27053.msg372393#msg372393), but I'm glad you've got it working now!

Anyway when I asked about changing the second text bank at 3FA94, I figured having the second block at $3400F would make it Bank 10 (0A) but when you replied with an explanation of how the bank swapping work, you mentioned Bank 12 and I'm not sure if you were just giving an unrelated example, subtly correcting me, or just made a typo.
Heh, that one I managed to write down correctly for a change :P. Banks $0C (starting at 0x030010), $0D (0x034010), and $0E (0x038010) are DW2's 3 empty banks.

I'm getting some messed up text by a couple of the Midenhall Castle NPCs using either value (either blank windows or a sparse random letter) so i figured I'll have to look at those pointers, but I want to make sure I'm not doing this with the wrong bank value.
Yup, that makes sense. The main script's pointer table actually starts at 0xB762, so you're missing the first 8 pointers, but they're probably fine so I'm not too concerned about that. The pointer table also stops at 0xB7C1, so the other 16 bytes you included here are just the start of the original second script bank's text and aren't really relevant. If you look at the rest of the pointer values, you'll see they keep increasing from $9016 at 0xB772 up to $BB37 at 0xB7A6 and then reset (that'll be the first pointer following the auto-jump) to $0243 at 0xB7A8 and start increasing again up to $390A at 0xB7C0, so those pointer values are all off by $8000 and giving you who knows what from system RAM instead of the data you want from cartridge ROM (as an added bonus, the $2002 PPU register is sensitive to reads, so if you're really lucky, you might also get some other graphical mayhem happening :D). Checking your insert script, I see that you've updated where to jump to when the insertion point reaches 0x17FE7 but didn't update the corresponding header value, which is throwing the pointer value calculations off. Try changing that to #AUTOCMD($17FE7, #HDR($28010)) instead and you should get the right pointer values.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 19, 2019, 12:05:26 pm
It occurred to me just before reading your reply that it was probably the pointer values being off for the new bank (you did post that "formula" for pointer values a while back). Had no idea that was what the HDR command in the script was for. Lesson learned for the future, but yep, that did it, it's working beautifully. Just got to start testing and tweaking and then doing all the menu stuff. Man that was nuts but that's a huge hurdle cleared for me thank you so much! :beer:

Edit: Chicken Knife gave me his atlas.txt so I could compare translations and I realized you have the "pointer formula" right in there. Doh! XP
Title: Re: General NES Hacking Questions
Post by: abw on April 20, 2019, 12:51:11 pm
Lesson learned for the future, but yep, that did it, it's working beautifully. Just got to start testing and tweaking and then doing all the menu stuff. Man that was nuts but that's a huge hurdle cleared for me thank you so much! :beer:
Sweet! Let's hope the testing and tweaking goes well too :).
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 22, 2019, 01:54:37 pm
Okay sorry to post in this thread so soon, but I'm genuinely stumped by the plural rules (I foolishly thought it was a bunch of suffixes in a row, kinda like the dictionary)  . With new monster names need a couple of tweaks not covered by the current plural rules

New names

Mummy Boy > Boys
Hunter Mech > Mechs
Madusa > Madusae
Dragonfry > No change
Gigantes > No change (though I'm not 100% sure if a plural is even needed here, I don't think Gigantes are encountered in groups)
Cyclops > No change (actually I just read here (https://www.grammarphobia.com/blog/2013/08/cyclops.html) that Square-Enix goofed and that the correct plural for a cyclops is "Cyclopes", though I suppose if need be, Cyclopses isn't entirely wrong and off limits)
Technically Man o' War is listed as "Men o' War" as its plural but I figure with the way the system counts from the end and adds to the end Man o' Wars would be just fine

The good news is that the new names also free up the need for a few rules

ch > ches (only the Hunter Mech is used and that's a case where it only needs the s added)
dead > no change
ngo > no change
f > ves (unused anyway)
i > ies
Mouse/mouse > Mice/mice (they're rats now)
rus>rii
sh>shes


I mean I get that there's essentially two parts of that code. One looks at the end letters and then points to other part that removes/adds letters at the end. Even for something like editing the "ngo" if I wanted to change it to "fry" I only see the "n" and "g" to change, I don't see the o

Code: [Select]
; -o pluralization handler: -ngo -> -ngo, -o -> -os
0x01C845|$07:$8835:BD F0 60 LDA $60F0,X ; read second-last letter of monster name
0x01C848|$07:$8838:C9 10    CMP #$10 ; "g"
0x01C84A|$07:$883A:D0 E7    BNE $8823 ; if not -go, append "s"
0x01C84C|$07:$883C:BD EF 60 LDA $60EF,X ; read third-last letter of monster name
0x01C84F|$07:$883F:C9 17    CMP #$17 ; "n"
0x01C851|$07:$8841:D0 E0    BNE $8823 ; if not -ngo, append "s"
0x01C853|$07:$8843:F0 EB    BEQ $8830 ; if -ngo, plural = singular

I guess what really confuses me are the if/if not suffix lines. How do I change THOSE?

Edit: Also doing Menus (no trouble understanding those :) ) but are you sure those pointers you listed on the wiki are right, abw? I'm getting some really broken up strings like

Nevermind, I misread the text start value as 7656 instead of 76E6 which was throwing me off.
Title: Re: General NES Hacking Questions
Post by: abw on April 22, 2019, 08:20:23 pm
Okay sorry to post in this thread so soon, but I'm genuinely stumped by the plural rules (I foolishly thought it was a bunch of suffixes in a row, kinda like the dictionary)  .
Nope, the pluralization rules are implemented as actual code, not just a table of suffixes or similar, so the bad news is you're going to have to roll up your sleeves and dig in to it a bit in order to make your changes. On the other hand, since you're going to be making changes anyway, you're free to make all the changes you want - you've got all the space from 0x01C801 to 0x01C8F3 to do whatever you want, and if that isn't enough space, most of the rest of the bank is empty. When this code starts running, the singular monster name has already been laid out in RAM at $6119 for you, and by the end, you just need to write the plural form to RAM starting at $60F1 and SEC before you RTS. You can use the debugger to set a breakpoint at the start and step through the code to watch exactly what it does.

For -ngo specifically, it works like this:

$87FC: LDA $60F1,X    ; read the final letter of the monster name into A (in this case that's "o", a.k.a. #$18; I think this is the part you missed)
$87FF: CMP #$18       ; among other things, this sets the Z (zero) processor flag based on whether A is #$18 ("o") or not
$8801: BEQ $8835      ; since Z is set, BEQ follows the branch

; at this point we know the last letter was "o", so we'll check the second-last letter
$8835: LDA $60F0,X    ; read the second-last letter the of monster name into A (in this case that's "g", a.k.a. #$10)
$8838: CMP #$10       ; as before, this sets the Z flag based on whether A is #$10 ("g") or not
$883A: BNE $8823      ; since A is #$10, Z is not set and we don't take this branch

; at this point we know the last two letters were "go", so we'll check the third-last letter
$883C: LDA $60EF,X    ; read the third-last letter of the monster name (in this case that's "n", a.k.a. #$17)
$883F: CMP #$17       ; as before, this sets the Z flag based on whether A is #$17 ("n") or not
$8841: BNE $8823      ; since A is #$17, Z is not set and we don't take this branch
$8843: BEQ $8830      ; ... which means we do take this branch
$8830: SEC            ; the calling code cares about whether C is set or not
$8831: RTS            ; and at this point we're done, not having changed a single byte of the monster name
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 22, 2019, 10:51:19 pm
Nope, the pluralization rules are implemented as actual code, not just a table of suffixes or similar, so the bad news is you're going to have to roll up your sleeves and dig in to it a bit in order to make your changes. On the other hand, since you're going to be making changes anyway, you're free to make all the changes you want - you've got all the space from 0x01C801 to 0x01C8F3 to do whatever you want, and if that isn't enough space, most of the rest of the bank is empty. When this code starts running, the singular monster name has already been laid out in RAM at $6119 for you, and by the end, you just need to write the plural form to RAM starting at $60F1 and SEC before you RTS. You can use the debugger to set a breakpoint at the start and step through the code to watch exactly what it does.

For -ngo specifically, it works like this:

$87FC: LDA $60F1,X    ; read the final letter of the monster name into A (in this case that's "o", a.k.a. #$18; I think this is the part you missed)
$87FF: CMP #$18       ; among other things, this sets the Z (zero) processor flag based on whether A is #$18 ("o") or not
$8801: BEQ $8835      ; since Z is set, BEQ follows the branch

; at this point we know the last letter was "o", so we'll check the second-last letter
$8835: LDA $60F0,X    ; read the second-last letter the of monster name into A (in this case that's "g", a.k.a. #$10)
$8838: CMP #$10       ; as before, this sets the Z flag based on whether A is #$10 ("g") or not
$883A: BNE $8823      ; since A is #$10, Z is not set and we don't take this branch

; at this point we know the last two letters were "go", so we'll check the third-last letter
$883C: LDA $60EF,X    ; read the third-last letter of the monster name (in this case that's "n", a.k.a. #$17)
$883F: CMP #$17       ; as before, this sets the Z flag based on whether A is #$17 ("n") or not
$8841: BNE $8823      ; since A is #$17, Z is not set and we don't take this branch
$8843: BEQ $8830      ; ... which means we do take this branch
$8830: SEC            ; the calling code cares about whether C is set or not
$8831: RTS            ; and at this point we're done, not having changed a single byte of the monster name


Thanks that explains it a little better. I now have an idea of what to do, I just don't know the commands. I realize fixing "Mechs" would be the easiest thing, I would just have to remove the line that checked the second to last letter for a c $8875-8878

But I looked at your notes on the Wiki and sort of brainstormed what I WANT to do.

Fixing S rules for Gigantes, Magus
Code: [Select]
; read second-last letter of monster name
; "u"
; if not -us, append "es"
; read third-last letter of monster name
; "g"
; if not -gus, append "es"
; read second-last letter of monster name
; "e"
; if not -es, append "es"
; read third-last letter of monster name
; "t"
; if -tes, don't change $8830
; "i"
; replace -us with -i
; Go to $8830
; replace final letter with "i"
; append "es"


Fixing Mummy Boy and Dragonfry
Code: [Select]
; "i"
; read second-last letter of monster name
; "o"
; if "-oy", append "s"
; "r"
; if "-ry", don't change ($8830)

Fixing Madusa

Code: [Select]
; read second-last letter of monster name
; "s"
; if not -sa, append "s"
; read third-last letter of monster name
; "u"
; "e"append e
; Go to $8830

It's something like that right? Again I get the programming gist of it, but I'm not sure what hex notation does what.

On a different note, thankfully window editing has gone quite well. I can see what you're talking about a few posts ago with the US "addition" of extra names. By expanding the Battle Command window, I realized I could display full names at the top of the window now, but strangely any unused character spaces still "cover" the top bar of the window. That's a real shame, otherwise it's neat! I'm thinking of keeping the change.

Edit: So as brought to my attention by laser lambert, apparently the special [(s)] (F2) doesn't work the same way as DW1. If used for "points", whenever there's 1, it just cuts off the string (experience) or doesn't display the whole window at all (points of damage in battle). Don't want to be a bother (I really really don't I swear! ^^'') But even if I used the Trace Logger/Debugger to find the routine I wouldn't know what to look for, I'm mostly just curious, but is there any way to fix that?
Title: Re: General NES Hacking Questions
Post by: abw on April 24, 2019, 12:06:32 am
When I was doing this for Latin, I took my list of singular monster names (I excluded the unique bosses since they never need plural forms), sorted it right-to-left so that I had all the same suffixes grouped together, wrote out the correct plural form for each name, did some extra Latin-specific stuff you won't need to deal with for English, and then wrote out the singular -> plural transformation rules I needed. Once I had that, writing the code was fairly straightforward; it's a little bit long and boring, but the individual sections are pretty simple. This is an oversimplification (particularly for CMP, which does multiple other things simultaneously), but for the purposes of this exercise, you can treat CMP #$hex as "check if A is #$hex", BEQ $addr as "if it is, go to $addr", and BNE $addr as "if it isn't, go to $addr".

As with script editing, I recommend writing code as code rather than typing things in to a hex editor, so you'll want to grab an assembler (anything that works for 65816 should also work for 6502, so pick your favourite SNES or NES assembler; I was actually using Asar (http://www.romhacking.net/utilities/964/), but I've been meaning to give xkas-plus (http://www.romhacking.net/forum/index.php?topic=19640.0) a try), and if you haven't done any ASM before, you'll also want some reference material (I like the handy instruction descriptions in chapter 18 of Programming the 65816 (http://www.romhacking.net/documents/423/), but feel free to consult other resources if that one doesn't suit your style).

Also, if you get the chance to be clever, take it! E.g. if you only have one monster name that ends in "r" and you're writing the code to handle names that end in "r", you don't have to check that the 2nd-last letter is "a" or the 3rd-last letter is "W" or anything else, you can immediately just change the 9th-last letter to "e" to get "Man o' War" pluralized to "Men o' War".

By expanding the Battle Command window, I realized I could display full names at the top of the window now, but strangely any unused character spaces still "cover" the top bar of the window. That's a real shame, otherwise it's neat! I'm thinking of keeping the change.
Check out the screenshots from my translation - I also added some code for changing trailing spaces in hero names to top borders when the names are displayed as part of a border :P.

Edit: So as brought to my attention by laser lambert, apparently the special [(s)] (F2) doesn't work the same way as DW1. If used for "points", whenever there's 1, it just cuts off the string (experience) or doesn't display the whole window at all (points of damage in battle). Don't want to be a bother (I really really don't I swear! ^^'') But even if I used the Trace Logger/Debugger to find the routine I wouldn't know what to look for, I'm mostly just curious, but is there any way to fix that?
Much like the [name] control code, [(s)] just tests the 16-bit value at $8F; the code for that is actually right before the pluralization code:
Code: [Select]
; data -> code
; if $8F-$90 == #$0001, print "s" + [end-FA] to $60F1 and SEC, else print [end-FA] and CLC
; indirect control flow target
; from $02:$BE37 via $8006
0x01C7E8|$07:$87D8:A5 90    LDA $90
0x01C7EA|$07:$87DA:D0 05    BNE $87E1 ; if $90 > 0, add "s"
0x01C7EC|$07:$87DC:A4 8F    LDY $8F
0x01C7EE|$07:$87DE:88      DEY
0x01C7EF|$07:$87DF:F0 0C    BEQ $87ED ; if $90 == 0 and $8F - 1 == 0 (i.e. $8F == 1), do not add "s"
; control flow target (from $87DA)
0x01C7F1|$07:$87E1:A9 1C    LDA #$1C ; "s"
0x01C7F3|$07:$87E3:8D F1 60 STA $60F1
0x01C7F6|$07:$87E6:A9 FA    LDA #$FA ; [end-FA]
0x01C7F8|$07:$87E8:8D F2 60 STA $60F2
0x01C7FB|$07:$87EB:38      SEC
0x01C7FC|$07:$87EC:60      RTS

; control flow target (from $87DF)
0x01C7FD|$07:$87ED:A9 FA    LDA #$FA ; [end-FA]
0x01C7FF|$07:$87EF:18      CLC
0x01C800|$07:$87F0:60      RTS
The [number] control code, which is used for both experience and gold gains, also uses $8F-$90, so I would have expected [(s)] to work for both of those situations.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 24, 2019, 06:41:42 am
When I was doing this for Latin, I took my list of singular monster names (I excluded the unique bosses since they never need plural forms), sorted it right-to-left so that I had all the same suffixes grouped together, wrote out the correct plural form for each name, did some extra Latin-specific stuff you won't need to deal with for English, and then wrote out the singular -> plural transformation rules I needed. Once I had that, writing the code was fairly straightforward; it's a little bit long and boring, but the individual sections are pretty simple. This is an oversimplification (particularly for CMP, which does multiple other things simultaneously), but for the purposes of this exercise, you can treat CMP #$hex as "check if A is #$hex", BEQ $addr as "if it is, go to $addr", and BNE $addr as "if it isn't, go to $addr".

As with script editing, I recommend writing code as code rather than typing things in to a hex editor, so you'll want to grab an assembler (anything that works for 65816 should also work for 6502, so pick your favourite SNES or NES assembler; I was actually using Asar (http://www.romhacking.net/utilities/964/), but I've been meaning to give xkas-plus (http://www.romhacking.net/forum/index.php?topic=19640.0) a try), and if you haven't done any ASM before, you'll also want some reference material (I like the handy instruction descriptions in chapter 18 of Programming the 65816 (http://www.romhacking.net/documents/423/), but feel free to consult other resources if that one doesn't suit your style).

Also, if you get the chance to be clever, take it! E.g. if you only have one monster name that ends in "r" and you're writing the code to handle names that end in "r", you don't have to check that the 2nd-last letter is "a" or the 3rd-last letter is "W" or anything else, you can immediately just change the 9th-last letter to "e" to get "Man o' War" pluralized to "Men o' War".

Thanks. I was worried my post came across too "Wahh I don't wanna! Just do it for me please." which wasn't what I intended at all. But that's exactly the info I was hoping for!

Quote
Check out the screenshots from my translation - I also added some code for changing trailing spaces in hero names to top borders when the names are displayed as part of a border :P.

Ah, you sly dog! Guess I'll have to download your translation and see what you did.

Speaking of. I was earnestly going to try to find monster and spell name length and used your explanation in that previous DW1 thread. But looking it over it confused me more than I thought it would.

In your example you said I could look up HEAL by setting a Read Breakpoint at $B5E6. The thing is looking back at the rom, I can't see what B5E6 is supposed to be. The pointer value was something similar but different like B8B6 (sorry away from my computer right now, something like that).

Am I missing a real obvious conversion or something? I thought the magic RAM to ROM conversion number was 3FF0?

Quote
Much like the [name] control code, [(s)] just tests the 16-bit value at $8F; the code for that is actually right before the pluralization code:
Code: [Select]
; data -> code
; if $8F-$90 == #$0001, print "s" + [end-FA] to $60F1 and SEC, else print [end-FA] and CLC
; indirect control flow target
; from $02:$BE37 via $8006
0x01C7E8|$07:$87D8:A5 90    LDA $90
0x01C7EA|$07:$87DA:D0 05    BNE $87E1 ; if $90 > 0, add "s"
0x01C7EC|$07:$87DC:A4 8F    LDY $8F
0x01C7EE|$07:$87DE:88      DEY
0x01C7EF|$07:$87DF:F0 0C    BEQ $87ED ; if $90 == 0 and $8F - 1 == 0 (i.e. $8F == 1), do not add "s"
; control flow target (from $87DA)
0x01C7F1|$07:$87E1:A9 1C    LDA #$1C ; "s"
0x01C7F3|$07:$87E3:8D F1 60 STA $60F1
0x01C7F6|$07:$87E6:A9 FA    LDA #$FA ; [end-FA]
0x01C7F8|$07:$87E8:8D F2 60 STA $60F2
0x01C7FB|$07:$87EB:38      SEC
0x01C7FC|$07:$87EC:60      RTS

; control flow target (from $87DF)
0x01C7FD|$07:$87ED:A9 FA    LDA #$FA ; [end-FA]
0x01C7FF|$07:$87EF:18      CLC
0x01C800|$07:$87F0:60      RTS
The [number] control code, which is used for both experience and gold gains, also uses $8F-$90, so I would have expected [(s)] to work for both of those situations.

Thanks again for this. How strange but I guess that's why the table only uses it for Gold and nothing else, maybe the devs just couldn't get it working properly? In a way I don't find it with fretting over. I could just tweak the script and then change my "point(s)" dictionary entry and be able to save MORE space that way.
Title: Re: General NES Hacking Questions
Post by: abw on April 24, 2019, 08:09:25 pm
Thanks. I was worried my post came across too "Wahh I don't wanna! Just do it for me please." which wasn't what I intended at all. But that's exactly the info I was hoping for!
We aim to please ;D.

Ah, you sly dog! Guess I'll have to download your translation and see what you did.
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.

Speaking of. I was earnestly going to try to find monster and spell name length and used your explanation in that previous DW1 thread. But looking it over it confused me more than I thought it would.

In your example you said I could look up HEAL by setting a Read Breakpoint at $B5E6. The thing is looking back at the rom, I can't see what B5E6 is supposed to be. The pointer value was something similar but different like B8B6 (sorry away from my computer right now, something like that).

Am I missing a real obvious conversion or something? I thought the magic RAM to ROM conversion number was 3FF0?
Sorry, part of the problem here is that I can't type properly :'(. I've updated that post to use the correct breakpoint of $BE56 as shown in the debugger snapshot instead of $B5E6; after that, it goes back to the relationship between RAM and ROM addresses: the read breakpoint uses RAM address $BE56, which for DW1 corresponds to a ROM offset of 0x3E66 (not the address you're looking for), 0x7E66 (pick me because I say "HEAL"!), or 0xBE66 (also not the address you're looking for), or theoretically 0xFE66 (but this is reserved for the fixed bank, so it's also not the address you're looking for). Does it make any more sense like this?
DW1 ROM Offset     DW1 RAM Address   DW1 RAM to ROM Conversion Number
$0010 - $400F      $8000 - $BFFF     -$7FF0
$4010 - $800F      $8000 - $BFFF     -$3FF0
$8010 - $C00F      $8000 - $BFFF     +$10
$C010 - $1000F     $C000 - $FFFF     +$4010
Thanks again for this. How strange but I guess that's why the table only uses it for Gold and nothing else, maybe the devs just couldn't get it working properly? In a way I don't find it with fretting over. I could just tweak the script and then change my "point(s)" dictionary entry and be able to save MORE space that way.
Wait a minute... Am I missing something, or is getting 1 piece of gold in this game actually impossible? Slimes are worth 2 gold, unique saleable items go for 2 gold, and even buying an Antidote Herb with a Golden Card still gets you a discount of 2 gold...

Hmm, yup, that F2 is just plain broken when $8F-$90 is #$0001. Instead of
Code: [Select]
LDA #$FA
CLC
RTS
which as you've seen results in the rest of the string getting cut off, it should be doing
Code: [Select]
LDA #$FA
STA $60F1
SEC
RTS
So the good news is: it's not you, it's the game :P. Replacing the CLC/RTS with BNE $87E3 should be enough to fix that up.
Title: Re: General NES Hacking Questions
Post by: Choppasmith on April 25, 2019, 02:47:18 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.

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.
Title: Re: General NES Hacking Questions
Post by: abw 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.
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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?
Title: Re: General NES Hacking Questions
Post by: abw 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.
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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.
Title: Re: General NES Hacking Questions
Post by: abw 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!
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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.
Title: Re: General NES Hacking Questions
Post by: abw 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).
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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.

(https://i.imgur.com/CC0s7l2.png)
(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.
Title: Re: General NES Hacking Questions
Post by: abw 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 (http://www.romhacking.net/forum/index.php?topic=27053.msg374493#msg374493), 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.
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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?
Title: Re: General NES Hacking Questions
Post by: abw 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.
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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?
Title: Re: General NES Hacking Questions
Post by: abw 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.
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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"

(https://i.imgur.com/7AxRlHp.png)

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
Title: Re: General NES Hacking Questions
Post by: abw 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
Title: Re: General NES Hacking Questions
Post by: Choppasmith 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?
Title: Re: General NES Hacking Questions
Post by: abw 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 (https://drive.google.com/open?id=1d5miZn-VBNnmTc7B9RvIFjj2PgN1FNtu) 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.
Title: Re: General NES Hacking Questions
Post by: gamingcat02261991 on July 07, 2019, 11:05:07 pm
How do you edit palettes and sprites for SMB2 (or SMUSA for the Japanese)?
Title: Re: General NES Hacking Questions
Post by: Chicken Knife 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.
Title: Re: General NES Hacking Questions
Post by: abw 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.
Title: Re: General NES Hacking Questions
Post by: Chicken Knife on July 08, 2019, 09:32:06 pm
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.
How revoltingly...sensible of a suggestion. There we are.

PS: Don't be surprised when I change the subject further to Dragon Warrior 1, 2 & 3  ;)
Title: Re: General NES Hacking Questions
Post by: abw on July 09, 2019, 08:46:19 pm
How revoltingly...sensible of a suggestion. There we are.
I try to come up with one of those every now and then. :laugh:

PS: Don't be surprised when I change the subject further to Dragon Warrior 1, 2 & 3  ;)
I await the day! :thumbsup:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 24, 2019, 12:11:24 pm
@abw

Ok, the day has arrived that I'm seriously trying to get extraction and insertion rolling. I would have loved to have gotten further than step 1 on my own. :P

The first challenge I'm facing is the fact no one seems to have posted the start and end addresses of the dialogue pointers for DW3 like was done for the first two games. It's easy enough to see the actual storage of the dialogue based on loading the posted table file into a hex editor but I'm not having much success in my attempts to trace back to the block of pointers based on my formerly useful methods. I have a feeling you're going to tell me that debugging is the best way to determine them and... I need to get better at that. Also, I'd imagine this would have to be broken up into a part 1 and part 2 based on the previous extractions? I think that had to do with the final strings being a different length but I'm not 100 percent clear.

**EDIT I just want to clarify, I'm not waiting for you to find the pointer table for me. I'm going to continue to be poking and prodding.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on August 24, 2019, 06:09:02 pm
The first challenge I'm facing is the fact no one seems to have posted the start and end addresses of the dialogue pointers for DW3 like was done for the first two games. It's easy enough to see the actual storage of the dialogue based on loading the posted table file into a hex editor but I'm not having much success in my attempts to trace back to the block of pointers based on my formerly useful methods. I have a feeling you're going to tell me that debugging is the best way to determine them and... I need to get better at that. Also, I'd imagine this would have to be broken up into a part 1 and part 2 based on the previous extractions? I think that had to do with the final strings being a different length but I'm not 100 percent clear.
Debugging is always a way, but there's nothing wrong with trying an educated guess or two first. You already know from the first two games that they only store a pointer to the first string in a block of 16 strings, so maybe DW3 does the same. If you take the start of the text you can read easily at 0x40010, count ahead 16 strings to 0x40190, convert those to RAM addresses $8000 and $8180, and then search the ROM for 00808081, you should get a hit at 0x28080. Et voilà!

DW3's text is approximately twice the size of DW2's, and it's not compressed, so it sprawls over 6 banks and not every bank ends with a full 16 strings, so you'll need to split the extraction into several parts, but other than being a bit dull and repetitive, it shouldn't pose any problems.

Hmm, the Text section of the DW3 ROM map on the wiki does look woefully inadequate... let's see if we can pump it up a little ;).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 24, 2019, 07:00:11 pm
Debugging is always a way, but there's nothing wrong with trying an educated guess or two first. You already know from the first two games that they only store a pointer to the first string in a block of 16 strings, so maybe DW3 does the same. If you take the start of the text you can read easily at 0x40010, count ahead 16 strings to 0x40190, convert those to RAM addresses $8000 and $8180, and then search the ROM for 00808081, you should get a hit at 0x28080. Et voilà!

DW3's text is approximately twice the size of DW2's, and it's not compressed, so it sprawls over 6 banks and not every bank ends with a full 16 strings, so you'll need to split the extraction into several parts, but other than being a bit dull and repetitive, it shouldn't pose any problems.

Hmm, the Text section of the DW3 ROM map on the wiki does look woefully inadequate... let's see if we can pump it up a little ;).
The problem with my attempts to search for the pointer was getting way too many hits. Combining two addresses being pointed to and then searching is one hell of a great idea. This is what I pay you for! :laugh:

Doing some updates to the ROM information sounds like a good idea. I'll make sure to do that.

As far as counting the strings manually at the ends of rom banks and setting up separate sections for each, that sounds doable!

One more thing I'm foggy on though. I'd say that our script increased in size somewhere between 5-10 percent. Seeing the massive chunk of blank space after the existing text made this seem like not much of a problem. But how big of a problem would it be if the text creeps into another rom bank?

Also, to your comment of DW2 and DW3's text size being roughly equivalent, that's actually shocking to hear. DW3 not only has more towns but has a day / night cycle that would seem to almost double the text. The translating / writing process definitely *felt* like it took 3x as long.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on August 26, 2019, 01:52:05 pm
Speaking of translating and inserting, I'm ready to start inserting my changes and testing DQ2.

Abw, I downloaded abcde v4 and saw your setup and tables for all the various things (seriously WOW). Unless I missed something, when extracting, the atlas.txt didn't add the table changes (easy to add myself) or the JMP commands for jumping to various parts of the ROM (a little trickier). Was abcde SUPPOSED to add those? (I did sort of Frankenstein my whole atlas.txt adding the other parts from the new version (credits, menus, etc) to my original which was just the script plus item and monster names). I'm wondering if I missed something somewhere and should just rip from scratch, or if I just have to add those JMP commands. Thanks.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 01, 2019, 01:42:57 pm
Combining two addresses being pointed to and then searching is one hell of a great idea. This is what I pay you for! :laugh:
*cha-ching* :P.

Doing some updates to the ROM information sounds like a good idea. I'll make sure to do that.
That was actually a (very) roundabout way of hinting that I had just fleshed out the text section a little bit. Definitely add anything I missed, though!

I'd say that our script increased in size somewhere between 5-10 percent. Seeing the massive chunk of blank space after the existing text made this seem like not much of a problem. But how big of a problem would it be if the text creeps into another rom bank?
Overflowing any of the ROM banks is a problem, but hopefully not one that will be difficult to overcome. The existing text is uncompressed, so if you're only over by 5-10%, adding a simple compression like DTE (which usually gets you 30-40% compression) should be more than enough. The existing text is also spread over multiple banks and there is a large chunk of free space in the final text bank, so probably there's a tiny data table somewhere that controls which bank gets loaded for each string, and you could modify that to shift the text around between banks or even extend it to use one (or more) of the existing empty banks.

Also, to your comment of DW2 and DW3's text size being roughly equivalent, that's actually shocking to hear. DW3 not only has more towns but has a day / night cycle that would seem to almost double the text. The translating / writing process definitely *felt* like it took 3x as long.
DW3 definitely has much more text than DW2. It depends exactly what you count and how, but 3x sounds about right. That "twice" was clearly a typo for "thrice" and not at all me just throwing out a number based on some vague recollection from a script size comparison I did months ago ;).

Abw, I downloaded abcde v4 and saw your setup and tables for all the various things (seriously WOW).
Heh, possibly my setup is overkill, but I like having the non-text data embedded in the script show up all nice and pretty in my script dumps; it saves me from having to go back to look up what the data is for every time I'm editing things, plus I can do all of its editing/inserting as part of the same process for editing/inserting the script.

Unless I missed something, when extracting, the atlas.txt didn't add the table changes (easy to add myself) or the JMP commands for jumping to various parts of the ROM (a little trickier). Was abcde SUPPOSED to add those?
Yeah, I've been of two minds about this. When you're not making any changes to the text engine, it would be nice to have more of the insert commands generated for you by the extract process, but when you are making engine changes, having insert commands based on the old engine is kind of annoying. Hmm, maybe I'll just add an option for that and let the end user decide what they want. For now, though, abcde does NOT add everything you'll want in your insert script, but usually it only takes a couple of minutes to add the missing parts yourself.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on September 11, 2019, 11:26:39 pm
So, I was running into some problems

First more of a program usage question abw, when trying to use abcde with all those tables I get

Code: [Select]
table 'C:\Users\mog11\Downloads\abcde_v0_0_4\menu_params.tbl' contains a control code table switch parameter to non-existant table 'heights' at C:\Users\mog11\Downloads\abcde_v0_0_4/abcde/Table/Table.pm line 82. at Atlas.txt line 0!

C:\Users\mog11\Downloads\abcde_v0_0_4>pause
Press any key to continue . . .

They're all in the same folder so I'm not sure what I'm missing here.

Also, for the asar usage, in your coding suggestions I see an added table file with inputting text with you noting "you can input these manually if you don't want to bother with a table $36,$18,$16,$0E,$FA ;" I thought I'd try this and just entered those bytes on a line and asar said it didn't understand the command. Is it db or something else? Also, just curious is the warnpc: address I see in some asm files is that a way to warn you if your code goes past a certain point?

Okay, so even worse news for me is that somehow or another my "base" rom (pre-script insert but had the new dictionary and item/monster name values changed) became corrupt somehow so I had to start over. I changed the dictionary and also from my notes changed the second script bank from 02 to 0C (bank 12) via x03FA92 and I'm getting garbled text (it also freezes once you get past the Prologue when starting a new game) I even cut out the extra stuff from the atlas.txt to focus just on the script, and I have no idea what happened.

This still looks correct, right?

Quote
// Define, load, and activate a TABLE
#VAR(Table, TABLE)
#ADDTBL("dw2_script_NEW.tbl", Table)
#ACTIVETBL(Table)

// add this near the top of the insert script:
#VAR(pointerNum, COUNTER) // create a COUNTER variable named pointerNum
#CREATECTR(pointerNum, 8, 0) // pointerNum is an 8-bit value initialized to 0
#AUTOCMD($17FE7, #WLB(pointerNum, $3FA90)) // update the code that controls which pointer starts the next bank

// Jump to start of script
#JMP($14010)
#HDR($C010)

// auto-commands for when DW2 does a mid-string bankswap and resets its read address:
#AUTOCMD($17FE7, #HDR($28010))
#AUTOCMD($17FE7, #JMP($30010, $3400F))

Really at a loss here.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 12, 2019, 07:35:30 pm
First more of a program usage question abw, when trying to use abcde with all those tables I get

Code: [Select]
table 'C:\Users\mog11\Downloads\abcde_v0_0_4\menu_params.tbl' contains a control code table switch parameter to non-existant table 'heights' at C:\Users\mog11\Downloads\abcde_v0_0_4/abcde/Table/Table.pm line 82. at Atlas.txt line 0!

They're all in the same folder so I'm not sure what I'm missing here.
What command were you running? The Atlas.bat script included in the examples folder does include all the required tables and works for me. It sounds like maybe you didn't include heights.tbl on the command line or inside your Atlas.txt file.

Also, for the asar usage, in your coding suggestions I see an added table file with inputting text with you noting "you can input these manually if you don't want to bother with a table $36,$18,$16,$0E,$FA ;" I thought I'd try this and just entered those bytes on a line and asar said it didn't understand the command. Is it db or something else? Also, just curious is the warnpc: address I see in some asm files is that a way to warn you if your code goes past a certain point?
Yup, the full line would be something like "db $36,$18,$16,$0E,$FA". I did say that I hadn't tested it :P. The xkas/Asar documentation describes what warnpc is supposed to do, though I vaguely recall having issues at some point with it not actually working. Might be worth giving it a test to confirm its behaviour.

Okay, so even worse news for me is that somehow or another my "base" rom (pre-script insert but had the new dictionary and item/monster name values changed) became corrupt somehow so I had to start over. I changed the dictionary and also from my notes changed the second script bank from 02 to 0C (bank 12) via x03FA92 and I'm getting garbled text (it also freezes once you get past the Prologue when starting a new game)
And this is why having a fully scripted insert process backed by source file version control is a Good Idea™ :P. For the crash, try modifying 0x3FA94 instead - 0x3FA92 is the +$02 in "BCC +$02", so changing that to "BCC +$0C" would probably have disastrous results.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on September 17, 2019, 12:10:40 am
So 1. I was using the old bat file I was using for my initial script inserts. Didn't realize you had to add ALL the tables to the command line. Lesson learned.

2. After a good 3 HOURS of trial and error, I found that it was indeed my dictionary text causing problems. I still don't know what exactly but since I was using the DW2 menu table to edit it, there must've been a random wrong byte getting swapped in somehow. To avoid future problems I just made a separate dictionary table and all is well again.

3.
Quote
And this is why having a fully scripted insert process backed by source file version control is a Good Idea™ :P. For the crash, try modifying 0x3FA94 instead - 0x3FA92 is the +$02 in "BCC +$02", so changing that to "BCC +$0C" would probably have disastrous results.

In my defense, having the same values right next to each other is sure easy to change the wrong one.

4. Now I can start messing around with those battle routines and I'm not having much luck so far. But so far with enemies I'm actually getting stuff like "(Hero name) appears!" for single enemies. Takign your suggestions from other posts, I did manage to combine a couple.

Code: [Select]
norom

org $1150C
base $94FC

LDA #$52
STA $A8 ; initialize per-group string ID to use in multi-group battles
LDA #$00
STA $A7 ; initialize total # of empty groups processed
process_group_string:
JSR $9EEE ; given an index (in A) into the array of structures at $0663, set $B5-$B6 to the address of the corresponding item inside that structure
LDY #$09
LDA ($B5),Y
STA $8F ; number of monsters in this group
BEQ done_display_string ; 0 monsters => no string to print
INC $A8 ; string ID to use for this group
LDY #$00
LDA ($B5),Y
STA $0161 ; current monster ID
LDX #$00
JSR $9CD6 ; write monster name in A (+ monster number within its group in X, if > 0) to $6119
LDA $60D8 ; total number of non-empty enemy groups in the current battle
CMP #$01
BEQ display_string ; if there's only 1 group, then use string ID #$0001 (change the text to be appropriate)
LDA $A8 ; otherwise use the per-group string ID (also change those texts to be appropriate)
display_string:
JSR $9CCA ; for A < #$60, display string ID specified by A; for A >= #$60, display string ID specified by A + #$A0
done_display_string:
INC $A7
LDA $A7
CMP #$04
BCC process_group_string
LDA $60D8 ; total number of non-empty enemy groups in the current battle
BNE next_section
LDA #$02 ; String ID #$0002: But it wasn't real.[end-FC]
JSR $9CCA ; for A < #$60, display string ID specified by A; for A >= #$60, display string ID specified by A + #$A0
LDA #$FD
STA $98 ; outcome of last fight?
JMP $9685
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP

next_section:

Code: [Select]
norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $00BF00 ; set the ROM file insertion point
base $8EF0 ; set the starting RAM address

LDA $0161 ; monster ID for the current group
CMP #$4E ; bosses have IDs >= #$4E (so does the "Enemies" monster, but that's not a monster ID you can encounter)
BCS no_change
SEC ; not strictly necessary since we got here by BCS and nothing has changed C
RTS
LDY $8F    ; number of monsters in group
DEY        ; count from 0 instead of 1
BEQ one     ; 0 => only one monster => handle "A" vs "An"
LDX #$00    ; read index
LDY #$00    ; write index
loop:
LDA some,X ; Monster Counts text
STA $60F1,Y ; start of text variable buffer
INY       
INX       
CMP #$FA    ; [end-FA]
BNE loop  ; if not end token, keep copying
done:
SEC        ; SEC to trigger read of [end-FA]-terminated string from $60F1, CLC to use A
RTS       
some:
db $36,$18,$16,$0E,$FA ;"Some" not using a table here
one:
; at this point we know Y = 0
LDA #$24 ; "A"
STA $60F1,Y ; start of text variable buffer
LDA $6119 ; first letter of monster name
CMP #$24 ; "A"
BEQ an
CMP #$28 ; "E"
BEQ an
CMP #$2C ; "I"
BEQ an
CMP #$32 ; "O"
BEQ an
CMP #$38 ; "U"
BNE no_change
an:
LDA #$17 ; "n"
INY
STA $60F1,Y ; start of text variable buffer
no_change:
LDA #$FA ; [end-FA]
STA $60F1,Y ; start of text variable buffer
BNE done

Also I meant to ask you if this "s" fix looked right to you

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

; data -> code
; if $8F-$90 == #$0001, print "s" + [end-FA] to $60F1 and SEC, else print [end-FA] and CLC
; indirect control flow target
; from $02:$BE37 via $8006
    LDA $90
    BNE s ; if $90 > 0, add "s"
    LDY $8F
    DEY
  BEQ end ; if $90 == 0 and $8F - 1 == 0 (i.e. $8F == 1), do not add "s"

s:
    LDA #$1C ; "s"

fix:
STA $60F1
    LDA #$FA ; [end-FA]
STA $60F2
    SEC
    RTS

end:
  LDA #$FA ; [end-FA]
    BNE fix
As I recall it's those last 2 bytes that needed fixing and you suggested a quick branch as an easy fix that would fit into the existing space. I just wanted to make sure I have this right.

But moving priorities a bit.

I was looking at your Latin translation so I could apply your border names code. I extracted the Latin script with Cartographer and strangely noticed that with mine, the original, the pointer and strings count up normally from 0 while yours jumps straight to 30 after 0 and seems to combine a bunch of those strings together. Did you maybe shift some pointers around or is it just Cartographer being weird?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 17, 2019, 09:00:11 pm
So 1. I was using the old bat file I was using for my initial script inserts. Didn't realize you had to add ALL the tables to the command line. Lesson learned.
You have to tell abcde where your table files are somehow; you can do that on the command line or inside the command files, but it's not going to go around opening random files and trying to use them as tables. A table's ID and file name can be completely different, so guessing at the file name based on the ID doesn't really work (and in v0.0.5 I re-added a pre-release idea where you can have multiple tables inside the same file, so it really doesn't work there).

2. After a good 3 HOURS of trial and error, I found that it was indeed my dictionary text causing problems. I still don't know what exactly but since I was using the DW2 menu table to edit it, there must've been a random wrong byte getting swapped in somehow. To avoid future problems I just made a separate dictionary table and all is well again.
The menus definitely use a different table - it's very similar to the table used for most other things, but not quite the same. Spaces in particular can be $81 in the menus, but putting a $81 in the dictionary might result in weirdness happening.

3. In my defense, having the same values right next to each other is sure easy to change the wrong one.
Yup, there are plenty of pitfalls in this business - I'm just saying that having a scripted insert process is one way of avoiding some of them :P.

4. Also I meant to ask you if this "s" fix looked right to you
Yeah, I think that was the smallest modification that would fix the F2 control code. For the 0xBF00 code, you can shuffle things around a little bit to save a couple of bytes:
Code: [Select]
norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $00BF00 ; set the ROM file insertion point
base $8EF0 ; set the starting RAM address

LDY $8F ; number of monsters in group
DEY ; count from 0 instead of 1
BEQ one ; 0 => only one monster => handle unique monsters and "A" vs "An"
LDX #$00 ; read index
LDY #$00 ; write index
loop:
LDA some,X ; Monster Counts text
STA $60F1,Y ; start of text variable buffer
INY
INX
CMP #$FA ; [end-FA]
BNE loop ; if not end token, keep copying
done:
SEC ; SEC to trigger read of [end-FA]-terminated string from $60F1, CLC to use A
RTS
some:
db $36,$18,$16,$0E,$FA ;"Some" not using a table here
one:
; at this point we know Y = 0
LDA $0161 ; monster ID for the current group
CMP #$4E ; bosses have IDs >= #$4E (so does the "Enemies" monster, but that's not a monster ID you can encounter)
BCS no_change
LDA #$24 ; "A"
STA $60F1,Y ; start of text variable buffer
LDA $6119 ; first letter of monster name
CMP #$24 ; "A"
BEQ an
CMP #$28 ; "E"
BEQ an
CMP #$2C ; "I"
BEQ an
CMP #$32 ; "O"
BEQ an
CMP #$38 ; "U"
BNE no_change
an:
LDA #$17 ; "n"
INY
STA $60F1,Y ; start of text variable buffer
no_change:
LDA #$FA ; [end-FA]
STA $60F1,Y ; start of text variable buffer
BNE done

I was looking at your Latin translation so I could apply your border names code. I extracted the Latin script with Cartographer and strangely noticed that with mine, the original, the pointer and strings count up normally from 0 while yours jumps straight to 30 after 0 and seems to combine a bunch of those strings together. Did you maybe shift some pointers around or is it just Cartographer being weird?
I think I mentioned it earlier, but I did reorder the menus to make them easier for me to work with (e.g. storing similar menus side by side), so what you're seeing sounds right.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 20, 2019, 12:08:37 am
@abw,

After much dragging of feet with DQ3, I finally got down to figuring out the start and end addresses of the pointers related to each of the six rom banks, along with segregating the final pointer for each bank and counting the number of strings for it.

Something unexpected came up where there is some text data appearing at the end of the bank $15 text that doesn't have an EF end token following it. It starts at 0x05616F and ends at 0x056197. I'm thinking this has a different end token, EE? Should I count that text as an additional string in my cartographer file?

As I go through the initial text in bank $10--which has a ton of in game command related text, those end tokens would seem to be EE as well. I suppose I would just need my table file to tell abcde that both EE and EF are end tokens, right?

Now the main thing I need to do before extracting is to make sure my table file is optimal. I'm also a little foggy on the concept of the base pointer. Would I use a base pointer of $10 for all the segments of the DQ3 script or would I need to make any adjustments to that?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 21, 2019, 11:09:20 am
Something unexpected came up where there is some text data appearing at the end of the bank $15 text that doesn't have an EF end token following it. It starts at 0x05616F and ends at 0x056197. I'm thinking this has a different end token, EE? Should I count that text as an additional string in my cartographer file?

As I go through the initial text in bank $10--which has a ton of in game command related text, those end tokens would seem to be EE as well. I suppose I would just need my table file to tell abcde that both EE and EF are end tokens, right?
It looks like I have all of EE, EF, FE, and FF listed as end tokens; FE and FF get used outside of the main script (spell/monster/item names etc.). For the main script, it's the same basic idea as in DW2 - EF is a full string end token and EE is a sub-string end token for when the game needs to chop up a longer string into smaller sections, generally to supply different values for variable control codes that get used multiple times in the full string. So yes, mark them all as end tokens!

I'm also a little foggy on the concept of the base pointer. Would I use a base pointer of $10 for all the segments of the DQ3 script or would I need to make any adjustments to that?
BASE POINTER is just how much you need to add to the pointer value (a RAM address) in order to get to the string in the ROM file (including any header). So if your pointer at 0x28080 has a value of $8000 and the corresponding string starts at 0x40010, you need a BASE POINTER value of 0x40010 - $8000 = 0x38010. Later on, when your pointer at 0x280B4 also has a value of $8000 but the corresponding string starts at 0x44010 instead, you need to update the BASE POINTER value to 0x44010 - $8000 = 0x3C010. Typically, updating the BASE POINTER value goes hand-in-hand with extracting data from a new ROM bank, but games are free to do whatever kind of craziness their programmers came up with, so that's not a hard and fast rule.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 23, 2019, 11:27:11 pm
 :woot!: :woot!: :woot!:

Just got the main script fully dumped--All 11 sections of it. (11 and not 12 because bank $11's final pointer conveniently addressed 16 strings.

I then went through a rather pleasurable exercise of tweaking my table file's opcode representation to present the grammar in as natural a style as possible for writing purposes. As I think about this, I should probably get the spell / item / monster lists included now as part of the extraction as to make their insertion easier down the road. I'll start working on that promptly, and will also continue to scour the document for any unidentified opcodes. It seems like it's easiest to fix them now in the dump stage of the process.

Once I get those items done, I suppose I'll be adding in the mostly finished script line by line. Since the compression you mentioned before is totally new territory for me, should I be doing anything differently with my formatting or simply prepare the insertion script the same way as I did for DQ1 and 2? After that I will be reaching out to you for help with adding code for the compression. Also, this is not a concern right now, but I believe I'll be setting up a separate boundary for each $4000 rom bank in the atlas file, correct?

September 24, 2019, 08:05:48 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Ok, another thing. The game seems to have an opcode for his/her: $B0. Since there is a ton of misgendering in the original script when you pick a female hero (getting called son, boy, etc) we went for a more gender neutral approach (child, etc). I haven't yet ventured into the realm of creating new opcodes but I assume the idea of making one like son/daughter or he/she would pose quite a challenge. But again, it's not something I'm too worried about since we are relatively happy with our current gender neutral language.

September 24, 2019, 09:35:37 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
**UPDATE

It would appear that $B6 is an opcode for son/daughter. It's amazing that these things exist in the game but the game doesn't use them 9/10 of the time  :laugh:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 24, 2019, 09:42:44 pm
:woot!: :woot!: :woot!:

Just got the main script fully dumped--All 11 sections of it. (11 and not 12 because bank $11's final pointer conveniently addressed 16 strings.
Congratulations!

Since the compression you mentioned before is totally new territory for me, should I be doing anything differently with my formatting or simply prepare the insertion script the same way as I did for DQ1 and 2? After that I will be reaching out to you for help with adding code for the compression. Also, this is not a concern right now, but I believe I'll be setting up a separate boundary for each $4000 rom bank in the atlas file, correct?
No, the insert script formatting is pretty much the same either way. Bank boundaries will take a little extra work, but not too much; basically I just set up per-bank insertion ranges and then update the ROM -> RAM address calculation offset, so something like:
Quote
#JMP($40010, $43FE7)
#HDR($38010)
// bank $10 script here

#JMP($44010, $47FE7)
#HDR($3C010)
// bank $11 script here

// etc.
As for fitting your larger script in, try to cram as much as you can into each bank and then see if the rest will fit in all the extra space in bank $15. If it does, then great; it looks like the code for controlling which bank to load for a given string starts at 0x03AE9F, so updating a couple of numbers there should be enough to make things work. If not, then you get to decide whether you want to add compression or whether you want to use up some of the other giant empty areas of space.

I haven't yet ventured into the realm of creating new opcodes but I assume the idea of making one like son/daughter or he/she would pose quite a challenge. But again, it's not something I'm too worried about since we are relatively happy with our current gender neutral language.
You mean like the B6=[son/daughter] or B2=[he/she] control codes that already exist? :D If you're happy with a gender-neutral script, that's fine, but the original game does come equipped with several control codes that display different text based on the hero's gender, so you have the option of using gender-specific language too.

For control codes, here's what I had (I think the A* ones were not used in the main script, but you can confirm that):
Quote
B0=[his/her]
B1=[himself/herself]
B2=[he/she]
B3=[him/her]
B4=[man/lady]
B5=[he's/she's]
B6=[son/daughter]
B7=[(s)-B7]
B8=[check if orb placed]

A0=[y/ies]
A1=[an/en]
A2=[ol/lls?]
A3=[i/ls?]
A4=[(es)-A4]
A5=[(s)-A5]
A6=[a/e]
A7=[no plural]

C0=[(s)-C0]
EB=[line]\n
ED=[sacrificial merchant's name]
/EE=[end-EE]\n\n
/EF=[end-EF]\n\n
F0=[class]
F2=[letter]
F3=[spell]
F4=[item]
F5=[name]
F7=[number]
F8=[number]
F9=[hero]
FD=[wait]
/FE=[end-FE]\n\n
/FF=[end-FF]\n\n
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 24, 2019, 10:10:18 pm
Just like what has frequently happend, I figured out that son/daughter is an opcode right before you told me. In fact I had cracked every single one on your list except for the A sequence which, yes, wasn't in the script. FYI you may have a problem with assigning both $F7 and $F8 the same designation: [number]. I used [value] for $F8.

I seem to recall you saying that you weren't exactly planning to do anything with DQ3. I'm very amused that you seem to have done all this charting out ahead of me simply for fun.  :laugh:

I've decided to just leave the spell/monster/item lists for the insertion, which is what I did last time for DQ2 according to my notes. That means it's time to start porting in the script. This will be lengthy but shouldn't be much of a headache. After that I'll start playing around with the bank loading code you pointed out. We'll almost certainly be discussing that further but I'll give it a crack.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 24, 2019, 11:45:13 pm
Just like what has frequently happend, I figured out that son/daughter is an opcode right before you told me. In fact I had cracked every single one on your list except for the A sequence which, yes, wasn't in the script.
See? You don't need me for this stuff at all anymore ;).

FYI you may have a problem with assigning both $F7 and $F8 the same designation: [number]. I used [value] for $F8.
Hmm, yup, good catch. I guess that must have been the point where I got sidetracked, since I had the other duplicate texts separated. Based on its usage in the script, F7 must be used for cardinal numbers (One, Two, Three, ...) and F8 for digits (1, 2, 3, ...).

I seem to recall you saying that you weren't exactly planning to do anything with DQ3. I'm very amused that you seem to have done all this charting out ahead of me simply for fun.  :laugh:
Don't you know by now that you can't believe everything you read on the internet? :P Translating just 1 and 2 feels wrong - either finish the Erdrick trilogy or the NES quadrilogy! But I got distracted by other things and didn't get much further than an initial script dump + replay (for refreshing my memory, checking some control codes I wasn't sure about, and generating a decent CDL file to use for disassembling).

I've decided to just leave the spell/monster/item lists for the insertion, which is what I did last time for DQ2 according to my notes. That means it's time to start porting in the script. This will be lengthy but shouldn't be much of a headache. After that I'll start playing around with the bank loading code you pointed out. We'll almost certainly be discussing that further but I'll give it a crack.
Sounds like a plan to me!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: tvtoon on September 28, 2019, 10:03:50 pm
So I finally translated the biggest RAM mapping work I have done for these games, the DQ3 GBC version. I have been stocking this here for more than half a decade, always forget to post this massive stuff but when I saw this topic, flashes happened! I was going to do the NES and SNES versions too, but time is short plus it shares many traits with them.

The work is now available at Data Crystal, enjoy! (https://datacrystal.romhacking.net/wiki/Dragon_Quest_III_%28Game_Boy_Color%29:RAM_map) Off: it is about time to update those templates!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Grimoire LD on September 29, 2019, 08:29:20 am
Spectacular! I was shocked at how little information there was on this legendary game and that about satisfied my curiosity for the most part (for most matters outside of battle). Great work!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 07, 2019, 10:57:07 pm
So I finally translated the biggest RAM mapping work I have done for these games, the DQ3 GBC version. I have been stocking this here for more than half a decade, always forget to post this massive stuff but when I saw this topic, flashes happened! I was going to do the NES and SNES versions too, but time is short plus it shares many traits with them.

The work is now available at Data Crystal, enjoy! (https://datacrystal.romhacking.net/wiki/Dragon_Quest_III_%28Game_Boy_Color%29:RAM_map) Off: it is about time to update those templates!
Great work! We may find some value in this for the NES projects and it certainly looks like a nice win for Dragon Quest hacking community in general.

@abw

nejimakipiyo and I are quite far along in getting the Atlas file ready for DQ3 but we ran into a roadblock with miscellaneous text. We are having a difficult time verifying it against the Japanese. In some cases, it is dependent on rare items; in other cases my partner would have to do another playthrough; in yet other cases we have no idea what the pieces of text connect to in the game. Therefore we decided that we would need to do an extraction of the DQ3 Japanese rom's text.

We spent tonight building a kana table file and then were going to try to locate the beginning of the script along with relevant pointers. The first problem we hit was that I can't get Windhex32 to display the kana. I spent a fair amount of time investigating forums and some people seem to indicate that Windhex32EX is the version I need but that doesn't seem to be available anywhere. Anyway, I moved on to an idea I caught from a forum to use romaji instead of kana in the table file. It gets a little dicey with hiragana vs katakana vs small hiragana all translating to the same combinations of letters but we worked out a .tbl that seemed sensible. Once I loaded that, I didn't see any great swaths of text that I was expecting. The text seems to be limited to a couple short segments, and with nejimakipiyo looking over them, they appeared to be related to items. Now I'm getting DQ2 flashbacks of the compressed script, something that wouldn't surprise me considering the infamous storage issues they had with Japanese DQ3 resulting in a cut title screen and fanfare.

So to boil that all down to a couple questions: 1, any thoughts about my kana viewing issues in a hexeditor? 2, do you think my suspicions of compression are correct? And 3, if compression, could the solution be relatively simple like the bit based table file we created for DQ2? Going down this kana extraction path has created some real headaches but I think it's pretty important. I wouldn't feel great about knowing that several English lines were left alone and never vetted. I'm not exactly the "good enough is good enough" type, fortunately and unfortunately.

abw, thank you as always...
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 09, 2019, 08:41:44 pm
The work is now available at Data Crystal, enjoy! (https://datacrystal.romhacking.net/wiki/Dragon_Quest_III_%28Game_Boy_Color%29:RAM_map)
Great work! We may find some value in this for the NES projects and it certainly looks like a nice win for Dragon Quest hacking community in general.
+1 :cookie:! It'll be interesting to see how well the GBC RAM map matches up to the NES RAM map.

Therefore we decided that we would need to do an extraction of the DQ3 Japanese rom's text.
Wait, if you didn't have a script dump of either the English or Japanese text, what were you translating from?

1, any thoughts about my kana viewing issues in a hexeditor?
Saving your table file encoded in Shift-JIS, loading it in WindHex, and then enabling the "View Text Data As Unicode" menu option does the trick for me. If you're going with romaji and want/need to differentiate between the kana systems, one thing I've done in the past is to use e.g. lowercase for hiragana and uppercase for katakana.

2, do you think my suspicions of compression are correct? And 3, if compression, could the solution be relatively simple like the bit based table file we created for DQ2?
Yes, DQ3's text encoding appears to be quite similar to DQ4's from a structural point of view. It's a 6-bit encoding with hiragana <=> katakana switches on a $3C (a.k.a. %111100) and dictionary switches on $3D/3E/3F. The major obvious difference between the two encodings is the dictionary contents and some of the kana being different/reordered. For table file building, you can use the DQ4 example that ships with abcde as a basis; DQ3's 6-bit -> 8-bit hiragana lookup table starts at 0x3BB8A, its katakana lookup table starts at 0x3BBC6 (these two mostly follow the order of tiles in the PPU, but not exactly), and the 6 dictionary pointers are at 0x3BC74, pointing to $FE-terminated dictionary entries in ROM bank $10 (i.e. starting at 0x28B4B). Once you've got that sorted out, it looks like the main script pointer table starts at 0x3BC02.


In other news, I did a little bit of poking around the text engine code for DW3, and adding in DTE was pretty easy; the $80 - $AF byte range was apparently unused and had its own little code path, so I stole that for the new DTE entries, and $30 DTE entries is enough to compress the original script by over 27%, so if you're only 5% - 10% larger than the original, you should have plenty of room to spare. Assuming Choppasmith is eventually going to want to insert a script that's somewhere around 100% larger than the original, I also looked at the code that sets up the bank and pointer for a given string ID, and rewrote it to make using extra banks easy; in combination with the DTE compression, using 3 of the existing empty ROM banks should be enough space to hold double the original text.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 10, 2019, 03:32:16 pm
Quote
Wait, if you didn't have a script dump of either the English or Japanese text, what were you translating from?
Well, I said above that I had an English dump so we are definitely using that. :P It probably would have been more efficient for us to crack our heads getting the Japanese dump at the beginning of the process, but instead we obtained *most* of the Japanese script through various resources online and a Japanese playthrough. I have a bad habit of choosing the longer and less technically difficult path, which is quite foolish when here I am struggling with the technicalities of a Japanese extraction regardless.

Quote
Saving your table file encoded in Shift-JIS, loading it in WindHex, and then enabling the changing the settings to "View Text Data As Unicode" menu option does the trick for me. If you're going with romaji and want/need to differentiate between the kana systems, one thing I've done in the past is to use e.g. lowercase for hiragana and uppercase for katakana.
I ended up downloading the Notepad++ software after investigating Shift-JIS and kind of fell in love with it in general. As far as viewing kana in WindHex, I'm stuck on your instruction of "View Text Data As Unicode". I do see the option of "View Text Data As Japanese" under options, but I've scoured the tabs at the top several times and can't find the Unicode option.

Quote
Yes, DQ3's text encoding appears to be quite similar to DQ4's from a structural point of view. It's a 6-bit encoding with hiragana <=> katakana switches on a $3C (a.k.a. %111100) and dictionary switches on $3D/3E/3F.
Ok, the concepts of 3 table files and switches are making my head hurt. This reminds me of the numerous table files used for fixing the SHILD issue in DW2 but I'd be lying if I said I actually understood that incredible web of files you sent me. Now I'll try to comprehend this (since 3 is better than 20).

So if I understand correctly, every time the game alternates between displaying a word in hiragana vs katakana that a switch byte--$3C appears and causes the game to pull from a different character table. Does this $3C switch appear in the code that tells the game to display the text or does it appear in the text itself? I assume that my Cartographer instructions would have to load all the table files and then tell abcde to perform the same switches between tables based on the presence of that byte. If you could point out the instructions that do that in your DQ4 cartographer doc that would be helpful.

Quote
DQ3's 6-bit -> 8-bit hiragana lookup table starts at 0x3BB8A, its katakana lookup table starts at 0x3BBC6 (these two mostly follow the order of tiles in the PPU, but not exactly), and the 6 dictionary pointers are at 0x3BC74, pointing to $FE-terminated dictionary entries in ROM bank $10 (i.e. starting at 0x28B4B). Once you've got that sorted out, it looks like the main script pointer table starts at 0x3BC02.
This is another very confusing element here. In fact, I'm so confused I can hardly even articulate an appropriate question. I did see in the table files that the characters with diacritics used 8 bits instead of 6. Wouldn't they just be pairs of bytes at this point and could be saved in the table file as such? And therefore wouldn't they essentially be uncompressed and I could rely on the byte information showing in a PPU viewer?

Quote
so if you're only 5% - 10% larger than the original, you should have plenty of room to spare.
During my second big round of editing as I've been adding our script lines into the insertion file one at a time, I've found several opportunities to reduce redundancies and make for punchier language. Nothing was compromised, and in fact I strongly prefer dense, to the point writing (in spite of what my RHDN forum activity would probably indicate.) That all said, it would seem likely that I may not have a problem with text space. But we shall see. Dealing with that problem can't be any more daunting than these obstacles around extracting DQ3's Japanese script.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: filler on October 10, 2019, 06:57:30 pm
As far as viewing kana in WindHex, I'm stuck on your instruction of "View Text Data As Unicode". I do see the option of "View Text Data As Japanese" under options, but I've scoured the tabs at the top several times and can't find the Unicode option.

Those are both the same command, essentially telling WindHex to display bytes that appear in a table file as their corresponding Japanese characters. The reason for the change in wording is likely because "View Text as Unicode" was not accurate since it reads table files in S-JIS format and that setting simply renders the characters in Japanese. It's more accurate to say "View Text Data as Japanese" and Bongo` changed the wording in subsequent version(s).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 10, 2019, 09:58:39 pm
Those are both the same command, essentially telling WindHex to display bytes that appear in a table file as their corresponding Japanese characters. The reason for the change in wording is likely because "View Text as Unicode" was not accurate since it reads table files in S-JIS format and that setting simply renders the characters in Japanese. It's more accurate to say "View Text Data as Japanese" and Bongo` changed the wording in subsequent version(s).
Thanks for the clarification. I did experiment with that and tried it again just now. I loaded the Japanese Dragon Quest 2 rom, loaded a hiragana table file that has been converted to SHIFT-JIS, and changed to the mode of View Text Data as Japanese.

It showed basically all the data as kanji characters, but I didn't see any of the hiragana. I used that same table file several months ago to do a text dump of the kana and it came out more or less correctly. So that all still doesn't solve the issue. hmm..
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 10, 2019, 10:19:38 pm
I have a bad habit of choosing the longer and less technically difficult path, which is quite foolish when here I am struggling with the technicalities of a Japanese extraction regardless.
Sometimes it can be very tricky indeed to tell whether the path that looks easy will actually end up being any faster than the path that looks difficult. That's a pain I'm sure most of us here can sympathize with ;).

Ok, the concepts of 3 table files and switches are making my head hurt.
Alright, how about an example? If you talk to the old man standing by the pool in the lower left corner of Aliahan castle at the start of a new game, he says:
Quote
とうぞくバコタの つくった
カギは かんたんなドアを
すべて あけたそうじゃ

That text starts partway through the byte at 0x2D3D2:

      E7 F8 BC DD 01 8A F1 8D 91 1E E3 FA F0 3D
C4 F1 9D 85 B4 FB 54 F3 73 00 F2 CE 8C DF D3 D2
D8 02 0F FA 5E 7E

Which in binary is:

                  11100111 11111000 10111100 11011101 00000001 10001010 11110001 10001101 10010001 00011110 11100011 11111010 11110000 00111101
11000100 11110001 10011101 10000101 10110100 11111011 01010100 11110011 01110011 00000000 11110010 11001110 10001100 11011111 11010011 11010010
11011000 00000010 00001111 11111010 01011110 01111110


More specifically, the old man's text starts at the second-last bit of 0x2D3D2, so if we ignore the first 6 bits (which are the end token for the previous string), we get

                        11 11111000 10111100 11011101 00000001 10001010 11110001 10001101 10010001 00011110 11100011 11111010 11110000 00111101
11000100 11110001 10011101 10000101 10110100 11111011 01010100 11110011 01110011 00000000 11110010 11001110 10001100 11011111 11010011 11010010
11011000 00000010 00001111 11111010 01011110 01111110


DQ4 uses 6-bit tokens instead of 8-bit, so considering that string of bits in groups of 6 gives us:

111111 100010 111100 110111 010000 000110 001010 111100 011000 110110 010001 000111 101110 001111 111010 111100
000011 110111 000100 111100 011001 110110 000101 101101 001111 101101 010100 111100 110111 001100 000000 111100
101100 111010 001100 110111 111101 001111 010010 110110 000000 001000 001111 111110 100101 111001 111110

which tokenizes as:

Table File   Token   Text/Effect
(hiragana)   111111   [switch to dictionary $3F for 1 token]
(dict_$3F)   100010   とう[add dakuten to next token]そく
(hiragana)   111100   [switch to katakana]
(katakana)   110111   [add dakuten to next token]
(katakana)   010000   ハ
(katakana)   000110   コ
(katakana)   001010   タ
(katakana)   111100   [switch to hiragana]
(hiragana)   011000   の
(hiragana)   110110   
(hiragana)   010001   つ
(hiragana)   000111   く
(hiragana)   101110   っ
(hiragana)   001111   た
(hiragana)   111010   [line]
(hiragana)   111100   [switch to katakana]
(katakana)   000011   カ
(katakana)   110111   [add dakuten to next token]
(katakana)   000100   キ
(katakana)   111100   [switch to hiragana]
(hiragana)   011001   は
(hiragana)   110110   
(hiragana)   000101   か
(hiragana)   101101   ん
(hiragana)   001111   た
(hiragana)   101101   ん
(hiragana)   010100   な
(hiragana)   111100   [switch to katakana]
(katakana)   110111   [add dakuten to next token]
(katakana)   001100   ト
(katakana)   000000   ア
(katakana)   111100   [switch to hiragana]
(hiragana)   101100   を
(hiragana)   111010   [line]
(hiragana)   001100   す
(hiragana)   110111   [add dakuten to next token]
(hiragana)   111101   [switch to dictionary $3D for 1 token]
(dict_$3D)   001111F   へ
(hiragana)   010010   て
(hiragana)   110110   
(hiragana)   000000   あ
(hiragana)   001000   け
(hiragana)   001111   た
(hiragana)   111110   [switch to dictionary $3E for 1 token]
(dict_$3E)   100101   そう[add dakuten to next token]しゃ
(hiragana)   111001   [end]

(those extra 6 bits at the end are the start of the next string)
So, every time the game reads a $3C (%111100), it toggles between hiragana and katakana and stays in the new table until the next time it reads a switch token; when it reads a $3D, $3E, or $3F (%111101/%111110/%111111), it switches to the corresponding dictionary for 1 token (or at least that's the high level effect; the actual ASM divides the bits up differently and treats the dictionary as 6 parts with 32 entries each rather than 3 parts with 64 entries each).

In the sample DQ4 table files, DQ4's table switches happen on the
Quote
!%111100=,<@katakana>:%111100
!%1111=,<@dictionary>:1
lines. You'll notice that I split the 12 bits for the dictionary switch + dictionary entry into 4 bits for switching and 8 bits (1 byte) for the entry; keeping them as 6 bits each will give you the exact same effect, so which form you prefer is entirely up to you.

This is another very confusing element here. In fact, I'm so confused I can hardly even articulate an appropriate question. I did see in the table files that the characters with diacritics used 8 bits instead of 6. Wouldn't they just be pairs of bytes at this point and could be saved in the table file as such? And therefore wouldn't they essentially be uncompressed and I could rely on the byte information showing in a PPU viewer?
DQ3's dictionary entries are a series of 8-bit values, so they get to use the full 8-bit range, but the hiragana and katakana entries are only 6-bit values and they get translated into 8-bit values via a pair of lookup tables, one for hiragana (e.g. hiragana %000000 translates to $0B, which is あ in the PPU viewer) and one for katakana (e.g. katakana %000000 translates to $3D, which is ア in the PPU viewer). You should be able to read the dictionary entries and 6-to-8-bit lookup tables with a byte-based table file, but the script itself is still encoded as a series of 6-bit tokens, so you won't be able to see that as easily.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 13, 2019, 01:40:17 am
Assuming Choppasmith is eventually going to want to insert a script that's somewhere around 100% larger than the original, I also looked at the code that sets up the bank and pointer for a given string ID, and rewrote it to make using extra banks easy; in combination with the DTE compression, using 3 of the existing empty ROM banks should be enough space to hold double the original text.

Thank you for this! From earlier posts I was looking at the amount of space going, with the first two games so far, I'll probably need DTE at least.

For control codes, here's what I had (I think the A* ones were not used in the main script, but you can confirm that):

I had heard about the mostly gender neutral, but infamous "boy" dialog in the Japanese version as well. This is great for me because the mobile script just gives the female hero a separate string, while there's some like below where they ADD dialog for Female Hero, there's a lot of duplicate lines.

Code: [Select]
My father was always telling me stories about the mighty hero Ortega.<10
And now here I am working in my dad's place, and there you are adventuring in yours.<10
It's true what they say, isn't it? Like father, like son!<41<63 Well, daughter in your case!<64<0F

I think it was something the Japanese script did to help correct said dialog problem in the original.

Also I just saw as I'm typing this there ARE cases where the gender is adjusted for strings. Weird

Code: [Select]
We expected no less of you, <41son<63daughter<64 of Ortega! We have witnessed the birth of a true hero!
So I finally translated the biggest RAM mapping work I have done for these games, the DQ3 GBC version. I have been stocking this here for more than half a decade, always forget to post this massive stuff but when I saw this topic, flashes happened! I was going to do the NES and SNES versions too, but time is short plus it shares many traits with them.

The work is now available at Data Crystal, enjoy! (https://datacrystal.romhacking.net/wiki/Dragon_Quest_III_%28Game_Boy_Color%29:RAM_map) Off: it is about time to update those templates!


Hey thanks for this! I still plan on tackling the GBC remakes down the line. So, the more info on III, the better!



So abw, sorry to bring up DW2, I really hope this is the last thing. But I allllmost got the code right for changing battle dialog to:

1: Ignore counting the last few bosses
2: Replace the multiple enemy counts with "Some" and "A/An"
3: Change the extra groups that appear to "And/AND some [monster]"

here's my code

Code: [Select]
norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $00BF00 ; set the ROM file insertion point
base $BEF0 ; set the starting RAM address

LDA $0161 ; monster ID for the current group
CMP #$4E ; bosses have IDs >= #$4E (so does the "Enemies" monster, but that's not a monster ID you can encounter)
BCS no_change
LDY $8F    ; number of monsters in group
DEY        ; count from 0 instead of 1
BEQ one     ; 0 => only one monster => handle "A" vs "An"
LDX #$00    ; read index
LDY #$00    ; write index
loop:
LDA some,X ; Monster Counts text
STA $60F1,Y ; start of text variable buffer
INY       
INX       
CMP #$FA    ; [end-FA]
BNE loop  ; if not end token, keep copying
done:
SEC        ; SEC to trigger read of [end-FA]-terminated string from $60F1, CLC to use A
RTS       
some:
db $36,$18,$16,$0E,$FA ;"Some" not using a table here
one:
; at this point we know Y = 0
LDA #$24 ; "A"
STA $60F1,Y ; start of text variable buffer
LDA $6119 ; first letter of monster name
CMP #$24 ; "A"
BEQ an
CMP #$28 ; "E"
BEQ an
CMP #$2C ; "I"
BEQ an
CMP #$32 ; "O"
BEQ an
CMP #$38 ; "U"
BNE no_change
an:
LDA #$17 ; "n"
INY
STA $60F1,Y ; start of text variable buffer
no_change:
LDA #$FA ; [end-FA]
STA $60F1,Y ; start of text variable buffer
BNE done
no_cardinal:
LDA #$FA ; [end-FA] the game will handle trimming the empty space from the
STA $60F1
BNE done

The thing that has me stumped is the A/an part. In battle if I get a single enemy with a consonant letter I get, for example _ Dracky where the underscore is an extra space the A should go. Yet getting a single Iron Ant gives me "A Iron Ant"

(to my credit, I was getting nothing but garbage before, so this has come a long way before this post)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 14, 2019, 12:07:39 pm
@abw

Thank you for the very detailed breakdown of how the compressed script works. This was helpful but there are still some things I need to understand before I can do this.

First, I did figure out the issue with viewing kana in WindHEX. It's essentially what you all were saying. I needed to use a software like Notepad++ to change the coding from UTF-8 variants to Shift-JIS. Interestingly, when I change the encoding to the latter, it makes the Japanese characters unviewable to me in the table files so not a good situation for editing. Perhaps I need to download something for windows to allow my PC to read Shift-JIS? The kana become things like x82xAD, etc. When I take that same garbled table file, load it in windhex and view data in Japanese it actually works. Let me qualify that: it works in a non compressed Japanese roms like DQ2, but not compressed ones like DQ3 or DQ4. When I try to load your included hira table file (reencoded to Shift-JIS) for DQ4 into the game, it doesn't show me anything at all--probably because Windhex isn't equipped to view data in that 6 bit format. With that being the case, I don't know how I'm going to be able to locate certain things like start address of the script. I would imagine it starts at the beginning of a rom bank and if you told me what the address of the first script bank was, I could probably use the pointers to figure out how many banks hold text and get the rest of the info I need. Well, I might need the address of the final script pointer since you only gave me the first. :P

The other thing I need help with is understanding some aspects of your DQ4 example files. The cartographer.txt file you included has all the different sections for different parts of the script (all with mysteriously different string lengths) but the only table file that gets referenced is the hira.tbl. You explained how the switch bytes cause the game to switch between the two character sets and the dictionary but you didn't seem to explain how abcde is going to do the switching. Since I don't see any table switching instructions in the cartographer file, I also looked at the table files themselves and the only thing that might be the instructions are
!%111100=,<@katakana>:0
!%1111=,<@dictionary>:1
I'd think that these were the switching instructions if it wasn't for the fact that the table names aren't included here. But I do notice theres a little @katakana symbol at the top of the kata.tbl file. Is that the reference point that this instruction points at allowing the switching to happen during extraction?

Well, that's the extent of my questions for now. I truly wish I was better at figuring these kinds of things out on my own. I am certainly trying my hardest before coming back to you.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 14, 2019, 10:11:43 pm
The thing that has me stumped is the A/an part. In battle if I get a single enemy with a consonant letter I get, for example _ Dracky where the underscore is an extra space the A should go. Yet getting a single Iron Ant gives me "A Iron Ant"
Have you tried stepping through the code in a debugger to follow along with exactly what it's doing and where it's going wrong?
Spoiler:
It looks like the Y values aren't getting updated correctly between writes to $60F1,Y, so the last letter you write is getting clobbered by $FA; making sure there's an INY after each write should help.

I don't know how I'm going to be able to locate certain things like start address of the script.
If you want to play along, Trace Logger + Debugger tells all. It looks like the main part of the text engine code starts somewhere around $0E:$B9D1, so that would be a good place for an execute breakpoint. The bank specified by $A8 gets swapped in before reading from the script and the engine setup code sets $A8 to either #$10, #$11 (via INC $A8), or #$02 based on the string index, so those banks ought to match up with the script pointers.

You explained how the switch bytes cause the game to switch between the two character sets and the dictionary but you didn't seem to explain how abcde is going to do the switching.
No, that part gets covered in abcde's readme where I spend several hundred words and many examples explaining how table file switching works by default and various ways you can control specific details of the switching process in order to mirror your game's behaviour :P. The following excerpt is particularly relevant here:
Quote from: readme.txt
# matchType says how many matches to make in the new table before falling back to the current table:
# * 0 => keep going as long as you can;
# * X => make exactly X matches in the new table, where X is any positive decimal integer;
# * -1 => fall back right away;

I'd think that these were the switching instructions if it wasn't for the fact that the table names aren't included here.
You can also find where the table files get referenced by looking at the example insert batch file / shell script:
Quote from: Atlas.bat
perl ..\..\..\abcde.pl -m text2bin -t hira.tbl -t kata.tbl -t dict.tbl -cm abcde::Atlas Atlas.nes Atlas.txt
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 20, 2019, 01:31:02 am
Have you tried stepping through the code in a debugger to follow along with exactly what it's doing and where it's going wrong?
Spoiler:
It looks like the Y values aren't getting updated correctly between writes to $60F1,Y, so the last letter you write is getting clobbered by $FA; making sure there's an INY after each write should help.

So I was in fact able to figure out on my own that, yeah, something was going on with reading the first letter of the Monster name (somehow it was reading an M instead of an I in Iron Ant) But I had no idea it was because of a missing Increment (INY). Thank you so much. Am I correct in understanding that Y, in this case, is basically the "cursor" in reading and printing letters/strings and that's why you need to increment it after a printed letter?

Also, in the other thread when I brought up rewriting the dialog into present tense instead of past tense, namely for "[monster] appear/s" you suggested using the "Special S" but I quickly realized unlike nouns the usage of s in verbs is reversed. Unlike 1 Coin/10 Coins, you have 1 monster appears/3 monsters appear (I even thought, "Oh! Draws near! Wait, no, that's the same thing".) I just want to ask if there was something you were thinking of that I'm not thinking of otherwise I think it's a pretty negligible sacrifice to use the past tense "appeared". Sure am glad to see DW3 seems to use present tense "appear" and "appears". :)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 20, 2019, 04:19:59 pm
Am I correct in understanding that Y, in this case, is basically the "cursor" in reading and printing letters/strings and that's why you need to increment it after a printed letter?
Yup, in that particular code, Y is used as the write index: "STA $60F1,Y" means to store the current value of A to the address $60F1 + Y, so when Y is 0, that $60F1, when Y is 1, that's $60F2, etc. If you open the Hex Editor, load the appropriate DW2 table file, and scroll down to $60F1, you can step through the code and watch the string being assembled there.

Also, in the other thread when I brought up rewriting the dialog into present tense instead of past tense, namely for "[monster] appear/s" you suggested using the "Special S" but I quickly realized unlike nouns the usage of s in verbs is reversed. Unlike 1 Coin/10 Coins, you have 1 monster appears/3 monsters appear (I even thought, "Oh! Draws near! Wait, no, that's the same thing".) I just want to ask if there was something you were thinking of that I'm not thinking of otherwise I think it's a pretty negligible sacrifice to use the past tense "appeared". Sure am glad to see DW3 seems to use present tense "appear" and "appears". :)
Hmm, yes, that is a good point. If you have enough space, you could add a new control code that does the opposite of what that $F2 does, i.e. prints "s" when $8F-$90 is 1 instead of not 1, and then use that in your script. But using "appeared" instead of "appear"/"appears" is also fine too.


In other news, I noticed on TCRF (https://tcrf.net/Dragon_Warrior_II_(NES)) that Cannock Castle also had a map change between the Japanese and English releases, so I figured I'd make a restoration patch for that too, and while I was at it, I figured I might as well also upload some patches for DW1 and DW2, so hopefully those will be approved shortly!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 22, 2019, 12:02:59 am
In other news, I noticed on TCRF (https://tcrf.net/Dragon_Warrior_II_(NES)) that Cannock Castle also had a map change between the Japanese and English releases, so I figured I'd make a restoration patch for that too, and while I was at it, I figured I might as well also upload some patches for DW1 and DW2, so hopefully those will be approved shortly!

Yeah I saw that, it's really minor change that just makes you go "Why?" There's a lot more in DW3, but the Data Crystal entry says map graphics are essentially like text. I would assume they're done in rows so I hope it turns out to be easier to edit.



So, abw, I did a "fresh" rip of DW2 with abcde v5. Copied my script over and changed the appropriate variables and there's two weird things. While my previous Atlas.txt was kinda all over the place, my new one is more in line with the rip.

First: It ripped the Prologue and everything else fine, but when I try to re-insert it says it can't tolkenize spaces and points to the first space I have there (Left side of the first line). I realized I needed to add the Table line to make sure it uses the spacer.tbl file but the Atlas readme isn't too insightful on how to use different tables I have it as:

Code: [Select]
#VAR(nonScriptTBL, TABLE)
#ADDTBL("spacer.tbl", main) // or whatever you named your table file
#ACTIVETBL(main)

I'm sure it's something painfully obvious I'm missing. If I don't add the main part it says it tries to call a table that doesn't exist, and when it's added it says main table unknown. @_@

Second: As I said in a previous post, I incorporated your full name hack (thank you again for that :))and I ripped the script in the menus to see what you did. I see that the new value $9C is for names in battle with trailing spaces, but I'm having trouble with the new field menu party list. YOUR Script shows for the beginning solo Midenhall status like this

Code: [Select]
═NOMEN═════GR══SL══LM[border line]
<$5F>[Midenhall's short name]  [Midenhall's level]<$5F>[Midenhall's current HP]<$5F>[Midenhall's current MP][line]

I think something might be going wrong with the fact that NORMALLY $5F and $81 are both spaces. I guess I'm stumped because I expected some kind of new value instead of "Midenhall's short name". Does the $5F really do something different here needing a change to the menu_params.tbl?

EDIT: Oh! I see your patches have just been approved! Maybe I'll use the menu improvement patch instead of trying to reverse engineer it from your Latin translation!

EDIT2: Between your Latin version and seeing how your new menu improvement patch works, I'm getting really turned around from the pointer values jumping back and forth. Makes it super confusing to edit! I totally see what you did but I just need to know: If I rip that part of the script with abcde/cartographer, with it's random Pointer Jumps (going from pointer #73 to Pointer #8) and edit the menus will Atlas still insert it properly? I'm curious how you even went in and said "Okay $7694 is practically the same as this menu pointed to $7690 so just point to that one"?(within something like abcde, I get how you'd do it manually)

EDIT3: Not a question, just a minor observation, but I'm surprised with your battle menu edit, you didn't just move the command menu to the left a couple of spaces over so that the monster name window doesn't overlap with the command window. That's what I did *shrug*
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 22, 2019, 08:36:51 pm
Yeah I saw that, it's really minor change that just makes you go "Why?"
Yup, that's pretty much exactly what I said when I saw that too :P.

There's a lot more in DW3, but the Data Crystal entry says map graphics are essentially like text. I would assume they're done in rows so I hope it turns out to be easier to edit.
Let's hope so - editing DW2's maps is only fun in a masochistic sort of way :(.

I realized I needed to add the Table line to make sure it uses the spacer.tbl file but the Atlas readme isn't too insightful on how to use different tables I have it as:

Code: [Select]
#VAR(nonScriptTBL, TABLE)
#ADDTBL("spacer.tbl", main) // or whatever you named your table file
#ACTIVETBL(main)

I'm sure it's something painfully obvious I'm missing. If I don't add the main part it says it tries to call a table that doesn't exist, and when it's added it says main table unknown. @_@
The variable name you create with #VAR has to match up with the variable name you use in #ADDTBL and #ACTIVETBL. In my insert script, I just went with a plain old boring:
Code: [Select]
#VAR(Spacer, TABLE)
#ADDTBL("spacer.tbl", Spacer)
#ACTIVETBL(Spacer)
but you can use whatever names you want as long as you use them consistently.

I see that the new value $9C is for names in battle with trailing spaces
In the menu patch I uploaded separately, menu control code $9C now prints all 8 bytes of the current hero + 1's name with both $5F and $60 spaces replaced by top borders. The version I used in my translation is a bit different - it only replaces $60 spaces, which worked since I changed Cannock/Moonbrooke's names to use $60 instead of $5F (matching Midenhall, who also uses $60 spaces).

EDIT2: Between your Latin version and seeing how your new menu improvement patch works, I'm getting really turned around from the pointer values jumping back and forth. Makes it super confusing to edit! I totally see what you did but I just need to know: If I rip that part of the script with abcde/cartographer, with it's random Pointer Jumps (going from pointer #73 to Pointer #8) and edit the menus will Atlas still insert it properly? I'm curious how you even went in and said "Okay $7694 is practically the same as this menu pointed to $7690 so just point to that one"?(within something like abcde, I get how you'd do it manually)
I'm not sure what you're saying here - I did re-order how the menu data is stored, but the menu pointed at by $7694 is still the same menu in both the original and patched versions (I've dubbed it "Menu ID #$21: Mini status window, top, Midenhall + Cannock + Moonbrooke"), and it's still a separate menu from the menu pointed at by $7690 ("Menu ID #$1F: Mini status window, bottom, Midenhall + Cannock + Moonbrooke"), which is likewise also the same menu in both cases. If it bothers you that much you can re-sort the menus to be in the same order as their pointers; I just found the original ordering to be both counter-intuitive and counter-productive for editing purposes, so I changed it.

EDIT3: Not a question, just a minor observation, but I'm surprised with your battle menu edit, you didn't just move the command menu to the left a couple of spaces over so that the monster name window doesn't overlap with the command window. That's what I did *shrug*
After trying it both ways for a while, I eventually decided I liked the overlapping menu effect more. I was trying to keep everything within the bounds of the 24-tile main dialogue window, and mostly succeeded, except the 16-tile equipment list and 10-tile attack/defense power list didn't quite fit and moving the attack/defense power window just looked weird.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Swordmaster on October 23, 2019, 05:05:45 am
In other news, I noticed on TCRF (https://tcrf.net/Dragon_Warrior_II_(NES)) that Cannock Castle also had a map change between the Japanese and English releases, so I figured I'd make a restoration patch for that too, and while I was at it, I figured I might as well also upload some patches for DW1 and DW2, so hopefully those will be approved shortly!

Just wanted to clarify that the original location of Cannock/Samaltria was changed before even the Japanese release.  'Twas a casualty of last minute balancing before release.  And we all know how perfectly balanced the finished product is.   :laugh:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 23, 2019, 03:27:27 pm

I'm not sure what you're saying here - I did re-order how the menu data is stored, but the menu pointed at by $7694 is still the same menu in both the original and patched versions (I've dubbed it "Menu ID #$21: Mini status window, top, Midenhall + Cannock + Moonbrooke"), and it's still a separate menu from the menu pointed at by $7690 ("Menu ID #$1F: Mini status window, bottom, Midenhall + Cannock + Moonbrooke"), which is likewise also the same menu in both cases. If it bothers you that much you can re-sort the menus to be in the same order as their pointers; I just found the original ordering to be both counter-intuitive and counter-productive for editing purposes, so I changed it.

Sorry, allow me to simplify:

-I ripped the menu dialog using the defualt example script provided

-This makes the output text jump to pointers randomly. Instead of Pointer 0:Text, Pointer 1:Text, Pointer 2:Text, etc, this causes the output file to Pointer 0:Text, Pointer 30: text, Pointer 31: Text, Pointer 9: Text, etc.

-I also noticed with the way the text was reordered a lot of the pointers would just display a lot of the same dialog

-This was tricky to figure out with your Latin translation because I would see stuff like CUI and go "Crap, which menu does this refer to?" After using Google Translate and playing the patched rom I was able to figure it out. 

What it really comes down to is: Since there's a separate patch for the English version now, I just need to change a couple letters like Armor->Armour, the Healer/Chruch Menu etc. Is it safe to edit and re-insert the text like this or am I going to need to take a different approach?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 23, 2019, 10:09:16 pm
-I ripped the menu dialog using the defualt example script provided
Keep in mind the example script is for the original game, so if you're going to re-dump from the patched ROM, you'll need to adjust the #SCRIPT STOP to $7F3D otherwise the last few bytes of menu data will get cut off.

-This makes the output text jump to pointers randomly. Instead of Pointer 0:Text, Pointer 1:Text, Pointer 2:Text, etc, this causes the output file to Pointer 0:Text, Pointer 30: text, Pointer 31: Text, Pointer 9: Text, etc.
Yup. And? As long as the pointers keep pointing to the right thing, it mostly doesn't matter what order the things are arranged in (on the NES, anyway).

-I also noticed with the way the text was reordered a lot of the pointers would just display a lot of the same dialog
I'm not sure what you're seeing here - no two of the menu pointers point to the same string.

-This was tricky to figure out with your Latin translation because I would see stuff like CUI and go "Crap, which menu does this refer to?" After using Google Translate and playing the patched rom I was able to figure it out. 
Yeah, it took a little while to track down which menu was which, particularly with all those WHOM menus. If you check the commented disassembly (http://datacrystal.romhacking.net/wiki/Dragon_Warrior_II::ROM_map/ASM_bank_01), the menu pointer table at $01:$B642 is a handy reference for stuff like that.

What it really comes down to is: Since there's a separate patch for the English version now, I just need to change a couple letters like Armor->Armour, the Healer/Chruch Menu etc. Is it safe to edit and re-insert the text like this or am I going to need to take a different approach?
Editing and re-inserting should be fine... the only thing to watch out for is that the code for printing bordered names starts at $7F40, so if you need to use any of that space, you'll have to update the ASM file to move the border code somewhere else and then re-assemble it.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on November 16, 2019, 04:11:11 pm
Keep in mind the example script is for the original game, so if you're going to re-dump from the patched ROM, you'll need to adjust the #SCRIPT STOP to $7F3D otherwise the last few bytes of menu data will get cut off.
Yup. And? As long as the pointers keep pointing to the right thing, it mostly doesn't matter what order the things are arranged in (on the NES, anyway).
I'm not sure what you're seeing here - no two of the menu pointers point to the same string.
Yeah, it took a little while to track down which menu was which, particularly with all those WHOM menus. If you check the commented disassembly (http://datacrystal.romhacking.net/wiki/Dragon_Warrior_II::ROM_map/ASM_bank_01), the menu pointer table at $01:$B642 is a handy reference for stuff like that.
Editing and re-inserting should be fine... the only thing to watch out for is that the code for printing bordered names starts at $7F40, so if you need to use any of that space, you'll have to update the ASM file to move the border code somewhere else and then re-assemble it.

Thanks abw, I've procrastinated quite a bit, but it's coming together nicely now. I'm just having a weird issue with abcde/atlas. I fixed the table issue I mentioned above, but now it gives me the message

Code: [Select]
table 'C:\Users\mog11\Downloads\abcde_v0_0_5\eg\NES\Dragon Warrior II\spacer.tbl' contains a control code table switch parameter to non-existant table 'main' at C:\Users\mog11\Downloads\abcde_v0_0_5/abcde/Table/Table.pm line 111. at Atlas.txt line 0!
I thought I'd try to start fresh with a new unzipped copy of abcde, but there I get

Code: [Select]
attempt to write beyond $7F3D at C:\Users\mog11\Downloads\abcde_v0_0_5c/abcde/Atlas.pm line 476, <COMMAND_FILE> line 3088.
variable 'Table' has already been declared at Atlas.txt line 3088!

Line 3088 Is the Credits part of my Atlas.txt which is setup as
#VAR(Credits, TABLE)
#ADDTBL("credits_spacer.tbl", Credits)
#ACTIVETBL(Credits)

Another weird thing is that after inserting the new Prologue the game just skips it (Start new game > Fades to black > Moonbrooke cutscene) I figured maybe I have a a couple of lines too long. I thought it would be like doing the title screens in DW1. Room for 32 spaces with an even amount of spaces on either side of the text to center it as long as it adds up to 32. Could that not be the case here?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on November 17, 2019, 01:58:49 pm
@abw

I thought I'd provide my own miserable update. The last we left off, you referred me to the table switching section of abcde's documentation. Over the last few weeks I've made numerous attempts to digest it. "It" being copied below:

Quote
# Table switch entries are new (and/or improved, depending on what you're already familiar with); this can get a bit complicated, so let's add some more table files and see some examples.
# The table switch entry format looks like this: !lhs=<label>,<@table ID>:matchType,<@table ID>:matchType,<@table ID>:matchType,...
# Where <label> is an optional label for the control code that, if provided, appears in text output,
# <@table ID>: is an optional table ID that will be used to continue matching; if you don't provide a table ID, one of two things will happen:
# * if you don't provide any value here, you get raw hexadecimal-encoded output;
# * if you provide the special value <binary> (note the lack of "@"), you get raw binary-encoded output;
# matchType says how many matches to make in the new table before falling back to the current table:
# * 0 => keep going as long as you can;
# * X => make exactly X matches in the new table, where X is any positive decimal integer;
# * -1 => fall back right away;
# * $hex or %bin => keep going until you match $hex or %bin again (the "$" or "%" are required here so that we can tell whether 10 means ten, sixteen, or two).
# Once the matching condition for the table that was switched into has been satisfied, translation will continue with the table that did the switching.
#
# For table entries that require exactly X matches, the default match counting behaviour is for each matched table entry in the new table to count as 1 match.
# However, different games can count matches in different ways, so abcde provides support for modifying the counting behaviour in a couple of ways:
# * you can change the number of matches a table entry counts as by suffixing the left-hand side of that entry with "<Y>" for any non-negative decimal integer Y; the table entry will then be counted as Y matches instead of 1 match;
# * you can do the same thing with matchType when using $hex or %bin;
# * matchType can be followed by a "+" to indicate that matches in the new table should also contribute towards the number of required matches in the current table.
In short, your explanation reads to me like something written from a programmer to a programmer, and I personally can't make heads of tales of it. I was able to follow everything above that section of the doc, probably due to A: being already knowledgeable on the topics, and B: the concepts being simpler in general. I feel like you need a whole separate set of instructions written for the laypeople (if laypeople ultimately have any business trying to take on these kinds of projects in the first place.)

What might be a lot more helpful to me is attempting to simply copy the examples you've provided from DQ4. I may try that in a few days with my next opportunity to be alone in a quiet house. I do want to acclimate myself to actually being able to read these kinds of instructions, but I feel like I need to get a hold of some books that provide a general introduction to programming before that is possible. It's a shame to feel this stuck when so much work has been done for the DQ3 re-translation. Maybe I return to the idea of grinding for all the 1/256 rare drops that we ultimately need the Japanese text from.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on November 24, 2019, 07:39:17 pm
Sorry for leaving you both hanging - I've been offline again for the past little while.

I fixed the table issue I mentioned above, but now it gives me the message

Code: [Select]
table 'C:\Users\mog11\Downloads\abcde_v0_0_5\eg\NES\Dragon Warrior II\spacer.tbl' contains a control code table switch parameter to non-existant table 'main' at C:\Users\mog11\Downloads\abcde_v0_0_5/abcde/Table/Table.pm line 111. at Atlas.txt line 0!
That means the 'spacer.tbl' file wants to be able to switch to the table whose ID is 'main', but none of the table files that got loaded have a 'main' ID (@main), so you're missing at least one table file.

I thought I'd try to start fresh with a new unzipped copy of abcde, but there I get

Code: [Select]
attempt to write beyond $7F3D at C:\Users\mog11\Downloads\abcde_v0_0_5c/abcde/Atlas.pm line 476, <COMMAND_FILE> line 3088.
variable 'Table' has already been declared at Atlas.txt line 3088!
That looks like a) whatever text you were trying to insert (if it was capped at $7F3D, it's probably the menu text) was too long and b) you tried to declare 'Table' as a variable name multiple times (i.e. you have multiple "#VAR(Table, ****)" commands where **** is the type, which I'm guessing is probably TABLE).

Another weird thing is that after inserting the new Prologue the game just skips it (Start new game > Fades to black > Moonbrooke cutscene) I figured maybe I have a a couple of lines too long.
Hmm, that one does sound odd. Assuming you haven't (possibly accidentally) made any code changes, my first guess would be that your new prologue text starts with an end token, causing the game to skip ahead to the Moonbrooke cutscene, though I haven't spent much time looking at bank 7, so it could easily be something else. The text length shouldn't be an issue; I haven't tried it, but I think the game just keeps printing text until it reaches an end token.

I thought it would be like doing the title screens in DW1. Room for 32 spaces with an even amount of spaces on either side of the text to center it as long as it adds up to 32. Could that not be the case here?
If you look at spacer.tbl, you'll see the first byte controls the left indent (if you need an indent outside the 1 - 15 range, you can add it to the table file yourself), and then text is stored using the main (non-script) 8-bit encoding, with lines terminated by $FF, so that's quite different than the DW1 title screen, which was bascially a 32x28 rectangle with some RLE.

In short, your explanation reads to me like something written from a programmer to a programmer, and I personally can't make heads of tales of it.
That was actually my sad attempt at end-user documentation right there - I was hoping the examples would flesh out the technical descriptions, but apparently not :P. Table switching is by far the most complicated thing about table files, and if you're going to be writing your own, you need to know the gory details.

If a basic table entry looks like "03=cat" and means that the byte 03 corresponds to the text "cat", then one kind of table switch entry looks like "!00=<[Animal Name]>,<@animals>:1". That means that the byte 00 triggers a switch to a new table with the ID "animals", reads exactly 1 match from that table and then reverts to the current table (the one that contains that "!00=<[Animal Name]>,<@animals>:1" entry), and that the text "[Animal Name]" appears in the extracted text immediately before whatever got matched in the "animals" table. So if your main table (which I'm going to call "main") and "animals" table look like this:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
80=main

@animals
03=[cat]
04=[dog]
then the bytes 000380 would correspond to the text "[Animal Name][cat]main" and the bytes 000480 would correspond to the text "[Animal Name][dog]main". But different games implement table switching in different ways and you might not want to see all the switches listed in your text, so there are lots of options. First off, the "label" part is optional, so you could say:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
80=main

@animals
03=[cat]
04=[dog]
and then the bytes 010380 would correspond to the text "[cat]main". You might want to read exactly 2 or exactly 3 matches from the "animals" table instead, so you could say:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
and then the bytes 02030480 would correspond to the text "[Animal Name][cat][dog]main" and the bytes 0303040580 would correspond to the text "[Animal Name][cat][dog][parakeet]main". You can do that for any positive number of matches, not just 1, 2, or 3. If you want to read exactly 1,000,000 matches from the "animals" table, go for it:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
and then the bytes 04... would get you a really long text! On the other hand, maybe you don't want to read a predetermined exact number of matches. Maybe you want to keep reading animal names until you come across a certain terminator, such as if your list of animals was terminated with a FF byte:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
In that case, the bytes 050304FF80 would correspond to the text "[Animal Name][cat][dog]main". Or maybe there is no explicit terminator and you want to keep reading animal names until you come across something that doesn't match any known animal:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
and then the bytes 06030480 would correspond to the text "[Animal Name][cat][dog]main". Another way of accomplishing the FF-terminated example is this:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
!FF=<>,-1
and then the bytes 060304FF80 would also correspond to the text "[Animal Name][cat][dog]main". You're also not limited to switching to just one table; if a 07 byte means that the game reads an animal name and then a colour, you could represent that as:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
!07=<[Animal Name/Colour]>,<@animals>:1,<@colours>:1
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
!FF=<>,-1

@colours
00=
and then the bytes 07030080 would correspond to the text "[Animal Name/Colour][cat]main". And then you can play with how many matches each table entry counts as; if there's something special about elephants and they count for twice as much as cats or dogs, you could represent that as:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
!07=<[Animal Name/Colour]>,<@animals>:1,<@colours>:1
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
06<2>=[elephant]
!FF=<>,-1

@colours
00=
and then the bytes 020680 would correspond to the text "[Animal Name][elephant]main". You're also not limited to switching only one table deep; with tables like these:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
!07=<[Animal Name/Colour]>,<@animals>:1,<@colours>:1
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
06<2>=[elephant]
!07=<[Dog Breed]>,<@dogbreeds>:1
!FF=<>,-1

@colours
00=

@dogbreeds
00=[Labrador]
01=[Chihuahua]
the bytes 00070080 would correspond to the text "[Animal Name][Dog Breed][Labrador]main". Counting can also be transitive, so if you needed to include matches in the "dogbreeds" table when counting matches from the "main" table, you could say:
Quote
@main
!00=<[Animal Name]>,<@animals>:1
!01=<>,<@animals>:1
!02=<[Animal Name]>,<@animals>:2
!03=<[Animal Name]>,<@animals>:3
!04=<[Animal Name]>,<@animals>:1000000
!05=<[Animal Name]>,<@animals>:$FF
!06=<[Animal Name]>,<@animals>:0
!07=<[Animal Name/Colour]>,<@animals>:1,<@colours>:1
80=main

@animals
03=[cat]
04=[dog]
05=[parakeet]
06<2>=[elephant]
!07=<[Dog Breed]>,<@dogbreeds>:1
!08=<[Dog Breed]>,<@dogbreeds>:1+
!FF=<>,-1

@colours
00=

@dogbreeds
00=[Labrador]
01=[Chihuahua]
and then the bytes 02080080 would also correspond to the text "[Animal Name][Dog Breed][Labrador]main", where "[Labrador]" gets counted as a match against both the "animals" -> "dogbreeds" switch and the "main" -> "animals" switch.

Maybe I return to the idea of grinding for all the 1/256 rare drops that we ultimately need the Japanese text from.
Instead of spending hours grinding for rare drops from multiple rare enemies, some other approaches include finding where your party's items are stored in RAM and editing the desired items into your inventory, finding the drop rate data and pumping all the drop rates up to the maximum, or finding the code that decides whether you get a drop or not and forcing it to always give a drop. Actually obtaining the items in-game gives you the benefit of seeing the mystery strings in more context than a text dump gives, so you can observationally verify which items use which strings rather than having to wade through the code or make questionable assumptions such as the order of item text being in any way related to the order of the items.


As for my little update, it turns out that DW3 uses 8 different control codes for various English monster name pluralization rules, but 1 of them is a "do nothing" rule and 3 of them are wrong, so really it only needs 4 codes. For translation, however, it took me a fair bit of work to get down to 14 codes... looks like I've got some more ASM work in my future!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on December 07, 2019, 12:35:14 pm
@abw

Thank you as always. I wanted to provide a different kind of update. I've been taking some time off from working specifically on the steps I'm at with this project in order to focus on learning the basics of 6502. I know I've said that for awhile, but I've finally made it an element of my schedule where I spend some time doing learning and exercises every day. I'm very surprised to find that if I had a shit day or even had a few drinks that evening, the daily consistency still allows me to  continue to make distinct progress. Virtually all the problems we've been facing lately have required me to have some kind of ASM / debugging knowledge so I thought it was time to make that the focus. It's not like I have more than 3 people clamoring for a release date of DQ3 Delocalized anyway.  :laugh:

I'm sure I'll have questions in the future, but hopefully they will be at a higher level and I won't require these 3 page answers.

See ya'll soon.  :beer:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on December 08, 2019, 09:45:56 pm
No worries! Glad to hear the 6502 learning is progressing well - as with most things in life, practice brings improvement :thumbsup:.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on January 07, 2020, 10:09:24 pm
Okay big update from me. After a bunch of frustration and procrastination, I figured out and fixed the kinks that were giving me trouble.

If some newbie romhacker (or maybe just new to abcde) is reading this, then you might want to give this a nice long read!

One thing I was missing before that I stupidly thought atlas/cartographer/abcde handled by itself before was adding #JMP commands before every block. Looking at an unaltered ROM I was noticing that the Prologue was being inserted directly AFTER the menu text. So yeah #JMP($Address) or #JMP($Start Address,$End Address) is very important!

Okay now maybe I messed up somewhere and this works perfectly fine for abw and anyone else, but I was still getting an error message that there was a duplicate table ID, @main. Again, if there's newbie romhackers using this, make sure your atlas.bat has all the tables you need! I double checked and the only table I had that was labelled @main was dw2.tbl. I fixed it and found success by changing the table used in various menus (directions, names, etc) from dw2.tbl to menu.tbl and editing menu.tbl to add values FA=[End-FA] and FF=[End-FF]. Worked like a charm!

Then there was the Prologue. First I was getting instances where it just completely skipped the text and now it was hanging on a blank screen doing nothing. Drove me nuts, I thought maybe my lines were too long or something.

abw I love you, but I think your spacer.tbl is wonky.

I think there's a genuine typo in your DW2 Cartographer.txt as well. After comparing an untouched ROM with one that's been altered I FINALLY noticed that Atlas/abcde was changing the pointer at $1CAB2 from 8A to 0A which is silly because there's only one string in the Prologue and I'm not changing its location. Now correct me if I'm wrong, but I think this is because the base pointer in cartographer.txt is listed at 14010 when it should be 1C010. At least that's the only reason I can think of that the pointer value is 8000 lower than it should be. Have to admit, I've figured that part out, but don't know how to fix it, I'm just manually editing $1CAB2 after I do an insertion.

Okay so back to spacer.tbl. Once I figured out the pointer problem I was getting text in game, but it would freeze when it got to my third line in the first stanza. It's supposed to be this

Code: [Select]
Once upon a time, a young hero
  descended from the legendary
  warrior Erdrick defeated the
dreaded Dragonlord, and restored
 peace and light to the world.

Yeah those are some long lines, I figured even if you have to do a total of 32 lines (number left spaces*2 + number of letters in a line)

I tried cutting it down just for testing sakes and got this

Code: [Select]
       Once upon a time,
         a young hero         
       descended from the
    warrior Erdrick defeated
      dreaded Dragonlord
    and restored peace and
      light to the world.

And what's weird, this is how it looked in game

(https://i.imgur.com/esKiWQc.png)

And I looked in the ROM and instead of having $07 for 7 spaces it put in $0F and $5F. I mean this doesn't mean I'm stuck I'll probably just use Pointer Tables since I don't have to worry about Pointers here, but I figured you should know.

Also, thanks Chicken Knife for giving me your latest Atlas.txt you used. I thought maybe you had a working "complete" version (menus, names, and everything) so I could see what was wrong with mine, but it was still helpful.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on January 08, 2020, 10:08:29 am
I actually have all the menu stuff on a separate atlas file. I really only needed that for one purpose (fixing SHILD) so I didn't bother combining it all together. I can send you the separate file tonight.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on January 08, 2020, 11:08:01 pm
One thing I was missing before that I stupidly thought atlas/cartographer/abcde handled by itself before was adding #JMP commands before every block.
Good news, I've made some upgrades for the eventual v0.0.6 release - the Cartographer code will now output #VAR/#ADDTBL/#ACTIVETBL and #HDR/#JMP commands for you!

Again, if there's newbie romhackers using this, make sure your atlas.bat has all the tables you need!
v0.0.6 might also help with this - there was a line buried in the abcde::Atlas help text about how you were supposed to load all your table files on the command line instead of inside the Atlas command file, but I've cleared that up now.

I fixed it and found success by changing the table used in various menus (directions, names, etc) from dw2.tbl to menu.tbl and editing menu.tbl to add values FA=[End-FA] and FF=[End-FF]. Worked like a charm!
Be careful with this - if you try inserting 2 or more adjacent spaces with the menu table, you'll get the menu's $82 - $87 control codes, which will quite possibly result in a mess when non-menu code encounters them.

abw I love you, but I think your spacer.tbl is wonky.
;D

I think there's a genuine typo in your DW2 Cartographer.txt as well. After comparing an untouched ROM with one that's been altered I FINALLY noticed that Atlas/abcde was changing the pointer at $1CAB2 from 8A to 0A which is silly because there's only one string in the Prologue and I'm not changing its location. Now correct me if I'm wrong, but I think this is because the base pointer in cartographer.txt is listed at 14010 when it should be 1C010.
For the prologue, I've got #JMP($1CAC2, $1CC22) and #HDR($14010) in both my translation's actual insert script and abcde's example, and both of those commands are correct. The value of the pointer at $1CAB1 is $8AB2, and $8AB2 + $14010 = $1CAC2. I also get $8AB2 as the pointer value when running abcde's example insert script, so I think something else is going on here. Any chance you could send me a link to your insert script so I can take a look?

I tried cutting it down just for testing sakes and got this
I notice your quote has a bunch of trailing spaces on the second line ("hero         "); my guess is that those are probably what's causing the issues on the third line. It looks like the prologue display code might only handle 30 bytes per line, so 32 bytes could cause some weirdness - what happens if you take those extra spaces out?

I thought maybe you had a working "complete" version (menus, names, and everything) so I could see what was wrong with mine, but it was still helpful.
I probably had a complete insert script when I started my translation, but it got cannibalized along the way and has been altered to work with all the ASM changes I made, so it doesn't really apply to the original script very well any more.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on January 10, 2020, 12:56:39 pm
Good news, I've made some upgrades for the eventual v0.0.6 release - the Cartographer code will now output #VAR/#ADDTBL/#ACTIVETBL and #HDR/#JMP commands for you!

Nice! That'll be a huge help!

Quote
Be careful with this - if you try inserting 2 or more adjacent spaces with the menu table, you'll get the menu's $82 - $87 control codes, which will quite possibly result in a mess when non-menu code encounters them.

Well the only thing I really need dw2.tbl for anyway is stuff like Crests and Moonbrooke/Cannock names, and those can just be edited manually if need be, but I'll keep a lookout thanks!

Quote
;D
For the prologue, I've got #JMP($1CAC2, $1CC22) and #HDR($14010) in both my translation's actual insert script and abcde's example, and both of those commands are correct. The value of the pointer at $1CAB1 is $8AB2, and $8AB2 + $14010 = $1CAC2. I also get $8AB2 as the pointer value when running abcde's example insert script, so I think something else is going on here. Any chance you could send me a link to your insert script so I can take a look?
I notice your quote has a bunch of trailing spaces on the second line ("hero         "); my guess is that those are probably what's causing the issues on the third line. It looks like the prologue display code might only handle 30 bytes per line, so 32 bytes could cause some weirdness - what happens if you take those extra spaces out?

Okay, yeah I did have some extra spaces there and it worked fine when I removed them (I think I was going to add those spaces for trial and error, then decided against it and forgot. Typicial). I noticed I was still getting some freezing, and noticed it was just spacer.tbl messing things up. Some lines it would put a space ($5F) instead of $FF at the end of a line and the game NEEDS that byte for the number of spaces ($01-$0F) and as said above it seems Atlas/abcde seemed to misinterpret some of those preceding spaces as regular ($5F) spaces. Also, worth noting, when you get to around 28 characters in a line (not including the spaces) things will flicker a bit.

Also, here's my atlas.txt
http://www.mediafire.com/file/o0hmhps1m4ss5oa/Atlas%25282%2529.txt/file

I'm really curious what's causing that Prologue pointer to be changed.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on January 11, 2020, 09:59:50 pm
Nice! That'll be a huge help!
Yeah, it's slow progress in between other things, but at least it is progress!

I noticed I was still getting some freezing, and noticed it was just spacer.tbl messing things up.
The freezing appears to be due to trying to insert lines longer than 30 bytes - it seems like the game really doesn't like that. I haven't spent much time looking at the prologue code, so I'm not sure what its actual limitations are.

Some lines it would put a space ($5F) instead of $FF at the end of a line and the game NEEDS that byte for the number of spaces ($01-$0F) and as said above it seems Atlas/abcde seemed to misinterpret some of those preceding spaces as regular ($5F) spaces.
I wasn't able to reproduce this myself, but I see that our table files have diverged a fair bit, so that isn't terribly conclusive evidence, especially if you were using the menu table when inserting the prologue.

Also, worth noting, when you get to around 28 characters in a line (not including the spaces) things will flicker a bit.
Yeah, the original game keeps its line lengths down to 28 bytes including spaces, 24 excluding. My translation seemed okay at 29 bytes including spaces, 26 excluding. I was getting some flickering with your "One hundred years passed..." line; you might want to try splitting/shortening that one.

I'm really curious what's causing that Prologue pointer to be changed.
You're missing the #HDR($14010) command to adjust the pointer calculations for ROM bank 7, which means the #HDR($-3FF0) is still active; $1CAC2 - $-3FF0 = $20AB2, which has $0AB2 as its low 2 bytes.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 18, 2020, 07:21:23 pm
Hey abw,

Question for you. I'm working with DQ2 again, and something that makes me a little crazy is the following entry on the table file:

1110110011=[..][..]

What I'd really like is a bit entry for a single pair of ellipses, not a double. I'm racking my head trying to think of how to edit this, and I can't come up with anything. As it stands, I have to either look at .... or . . . and I can't decide which one I hate more.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 18, 2020, 08:41:10 pm
Well, two options that come to mind are:You'll have to decide for yourself which one works better, but off the top of my head, the first option is the easiest and probably the best looking.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 18, 2020, 09:45:23 pm
Good idea. I've forgotten too much already about how text works in this game. I had to update my table file with material you posted in order to see the [..][..]

With the two options you proposed, I think the ideal one is a third. I need to change the dictionary entry to only [..] so that it will fire off regardless of whether the third dot is [. ] or [.']

If I remember correctly, there's a table nearby where I can change the number of bytes allocated to each dictionary entry. I should be able to find that somewhere in my notes or these forum posts. I did a lot of dictionary editing a while ago in order to get the dictionary optimized for my non-medieval text.

**EDIT

And yes, the chart that allocates space for each entry was in nibble format directly above the dictionary. I never found any notes, but at least it came back to me. :D
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 19, 2020, 10:19:48 am
Yup, if you're going to have ellipses run into other punctuation, then the third option definitely sounds the best :thumbsup:.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 22, 2020, 08:52:57 am
Hmm.. Having an odd issue with DQ2 text. I wanted to add a * symbol into the dictionary. So I worked with %1111110000 which was assigned to "hee" and replaced "hee" with "*". I adjusted the nibble in the counting table above the dictionary, adjusted table files, and I selected the hiragana character located at memory location $80, rom location $3453, and replaced that with the * tile from DQ1.

Yet, when I plug this into my script, insert, and load the game, the game is rendering 0 instead of * in every instance where * should appear. Can't figure out how this would be happening. May have made a stupid mistake somewhere but I've checked everything over.

*EDIT

I was brainstorming on the drive to work... Now, I'm wondering if only half of that set of PPU tiles is accessible in the text windows. As I think back, all the text that's used in the dialogue boxes seems to be from that top half, which would be 00-7F. I used the very next PPU address, 80.

When I get home, I'll experiment and try to confirm. Space in that top half may be quite limited, but I'll try to figure something out.

*EDIT 2

I had someone send me a shot of the top half of those PPU graphics. Assuming that my theory is correct (big assumption), I'm curious if anything actually uses those thin font characters? I don't remember them, and they are very odd. Some capitalized, some lower case. I could either switch out one of those, or I could use one of the multiple blank spaces perhaps.

*EDIT 3

So yes, my theory was right. Only the first 8 rows of the CHR can be used for characters that appear in dialogue. I replaced an odd capital A assigned to byte 58. That whole thin font set doesn't seem to be used, regardless.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 22, 2020, 09:15:57 pm
On the other hand, if I take a fresh copy of the ROM and change e.g. 0xB4DB from 0x31 ("N") to 0x80 ("じ") and try talking to nobody, I do get "じo one is in that direction." as expected, so I think you've got something else going on there.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 25, 2020, 10:02:12 am
I strongly suspect that 3 hours of sleep a couple nights in a row was the root cause of my issue. I did end up using one of those weird letter tiles that don't seem to be used anywhere, and that solved it. Maybe at some point, I'll do the exercise again and be as befuddled as you were about me having the issue in the first place.

In the meantime, I'm digging deep into the sprite tile and palette assignment functions in DQ3. The system is about 10x more complicated than it was in DQ1 since the code has to load tile data into the PPU in tiny chunks as opposed to everything at once like it did in DQ1. But figuring this out is what it will take to fix the wrongly animated female martial artist sprite, the old man sprite, and get ghosts turned into coffins.

If I can manage to solve this, I should feel up to taking another crack at the DQ3 script extraction / insertion in coming weeks.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 25, 2020, 10:22:34 pm
I strongly suspect that 3 hours of sleep a couple nights in a row was the root cause of my issue.
Yeah, sleep deprivation + anything requiring mental alertness = recipe for failure :(.

Regardless, the main thing is that you did get it working, so hurray!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on April 30, 2020, 03:13:51 pm
Hey abw I'm getting a strange glitch with your random names patch. While the names are randomly chosen the first 4 letters are replaced by zeros

(https://i.imgur.com/pMHA9rk.png)

Obviously something from my work is conflicting with yours but I can't find what it is. I double checked my new menu data definitely doesn't overwrite your longer menu names code as you had warned me about. I thought it MIGHT have been from one of my Cannock names was too long, Randolph, but I changed it to Randolf and still no change.

I have a patch right here:
http://www.mediafire.com/file/ut13h20ea3h1ebj/DQ2_Request_B2.xdelta/file
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 30, 2020, 05:16:49 pm
Your patch is doing LDA $6D79,X at $06:$AD20 instead of LDA $AD79,X; my guess is this is an error with your insert script, probably a missing/incorrect #HDR to set the appropriate pointer offsets for Cannock/Moonbrooke's names.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 30, 2020, 06:33:38 pm
@abw

Question for you. I already posted my big DQ1 Delocalized update today, but there's one lingering thing in my mind that could be improved. Every enemy encounter in the game says something like "A Slime has appeared!". That text works fine for pretty much every encounter, but I'd love to introduce unique text for the Dragon King (Dragonlord). Something like "The Dragon King attacks!". "A Dragon King has appeared!" Just sounds idiotic in that scenario. Adding a new line of text would probably be the easy part, but I assume that getting the game to point to it only in the case of the Dragon King fight would be the challenge. Any thoughts on the feasibility?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 30, 2020, 07:58:10 pm
A few minutes with a debugger says that the "A Dragonlord draws near!" text (the 0xE2'th string) comes from the 0xE2 following $03:$E595, so if you wanted different text for the Dragonlord, you'd need to change 0xE2 to whatever string you wanted to use instead. It looks like the current enemy ID is stored in RAM at $E0, so something like this should do the trick:
Code: [Select]
; $03:$E595
JSR choose_text
NOP

; free space somewhere else
choose_text:
LDA $E0
CMP #$26 ; enemy ID for Dragonlord's first form
BEQ @use_awesome_text
; otherwise use the normal text
JSR $C7CB
.byte E2 ; normal string ID
RTS
@use_awesome_text:
JSR $C7CB
.byte ?? ; whatever free string ID you want to use for your new text
RTS
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on April 30, 2020, 10:36:02 pm
@abw

By all appearances, your reply is extremely useful toward the goal of implementing this improvement. But I'm going to have to ask you for a different way of explaining the following elements that don't make sense to me:

Quote
(the 0xE2'th string)
I'm not sure where 0xE2'th is coming from / what it's referring to. I know that under my insert script, this line of text falls 3 lines under #W16($802E). I've never necessarily become as clear as I should be about the mechanics with how the script runs. I know there's pointers to each string, and the code counts end tokens to find the line it wants, but I probably need to understand the mechanics better, and maybe play with them in a hex editor.

Quote
comes from the 0xE2 following $03:$E595,
Still lost here. Clearly related to the above question.

The code section is also pretty much a mystery. It looks like debugger info with what I assume to be notations from you. I understand most of the asm commands. JSR for jumps. LDA for loading accumulator, CMP for compare to value, BEQ for branch on equal. What I don't understand is the significance of your formatting. For instance, what is ; $03:$E595 on the top left. Then why are the instructions below  indented. What is something like this: "@use_awesome_text:"

I'm sure that what you're presenting to me is pretty standard syntax to someone with a respectable amount of programming knowledge. If you want to point me anywhere to learn that syntax, great. Otherwise, I'm going to keep bugging you with questions if that's ok. I've been feeling hardier and more persistent than usual when it comes to figuring things out lately. I'm experiencing great success with my graphical hacking endeavors. About to publish some patches for graphical issues that no one has yet fixed in Dragon Warrior 3. But I need to strengthen my script handling skills.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on April 30, 2020, 11:28:32 pm
By all appearances, your reply is extremely useful toward the goal of implementing this improvement. But I'm going to have to ask you for a different way of explaining the following elements that don't make sense to me:
Oh, sorry. Let's try this a different way, then!

I'm not sure where 0xE2'th is coming from / what it's referring to. I know that under my insert script, this line of text falls 3 lines under #W16($802E). I've never necessarily become as clear as I should be about the mechanics with how the script runs. I know there's pointers to each string, and the code counts end tokens to find the line it wants, but I probably need to understand the mechanics better, and maybe play with them in a hex editor.
If you look at the main dialogue and count the strings starting from 0, "A Dragonlord draws near!" (or whatever the monster's name happens to be) is the 226th string, or E2 in hex. If you don't want to count them all, recall that each pointer points to a group of 16 strings, and if you kept the pointer comments from the extraction script, this string is the 2nd string (counting from 0) of the 14th pointer (counting from 0), or E2. Alternately, you know the pointer table starts at 0x8010, the pointer for this string is at 0x802E, and there are 2 bytes per pointer, so this is the (0x802E - 0x8010) / 2 = 0xF'th pointer (counting from 1), or 0xE (counting from 0). The game needs some way of knowing which string to display, so they're all referred to by their index, from string 0x0 all the way up to 0x139. String 0xE2 is the one you care about here.

If you want to trace through the code for displaying a string, $C7CB is a fine place to start. It'll do some stack manipulation to read the E2 data byte and then figure out which dialogue pointer to follow, scan through the dialogue data counting end tokens until it finds the right string, and then go through all the logic for handling control codes (such as the one for inserting the current monster's name), formatting it, and writing it to the PPU.

The code section is also pretty much a mystery. It looks like debugger info with what I assume to be notations from you. I understand most of the asm commands. JSR for jumps. LDA for loading accumulator, CMP for compare to value, BEQ for branch on equal. What I don't understand is the significance of your formatting. For instance, what is ; $03:$E595 on the top left. Then why are the instructions below  indented. What is something like this: "@use_awesome_text:"
Most of that is fairly standard, though the assembler-specific commands are from ca65 (https://www.cc65.org/doc/ca65.html) since that's what I've been working with the most lately; something like Asar (http://www.romhacking.net/utilities/964/) involves a lot less work to get set up, but you'll have to convert the syntax very slightly from what ca65 uses (Asar is based on xkas which uses "." instead of "@" and "db" instead of ".byte"). Semicolons and anything following them are comments, labels are followed by a colon, and ca65 uses @ to denote a local label. Indenting is a personal preference, but you'll often see assembly written that way; I like having my labels and block comments stand out. The $03:$E595 was just a comment to tell you where the first bit of code needs to go; the other section can go anywhere that has room and is accessible from the first place (there are some chunks of free space in the fixed bank that are large enough to hold that code).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 03, 2020, 08:57:49 am
@abw,

That explanation was clearer. I had to read it a few times, but it gave me a lot of helpful info. I think I'm going to come back to this a little later, though. Since I figured out how to use FCEUX's code logger utility, essentially a whole new world of graphics editing has opened up. I think I'll continue with that work until all the things I want to fix in the NES DQ games are fixed. Soon after, I'll make another big push at inserting our DQ3 script, and that would seem to be the right time to work on this Dragon King text.

As far as your discussion of assemblers, I'm a little unclear about why I would want to use an assembler. I've played with them a bit in my asm learning exercises, but I don't have a clear idea why assemblers are important while hacking roms. Do they essentially allow you to add and subtract code as easily as manipulating script, table or menu elements via abcde?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 03, 2020, 12:06:43 pm
Since I figured out how to use FCEUX's code logger utility, essentially a whole new world of graphics editing has opened up.
Level up! Chicken Knife's hacking skill increased by 2! :D

As far as your discussion of assemblers, I'm a little unclear about why I would want to use an assembler. I've played with them a bit in my asm learning exercises, but I don't have a clear idea why assemblers are important while hacking roms. Do they essentially allow you to add and subtract code as easily as manipulating script, table or menu elements via abcde?
If the alternative is directly hex editing a ROM, using an assembler for code changes provides several benefits. Probably the biggest one is automatic pointer calculation; if you thought that was great for insert scripts that only have a dozen pointers, you'll really love it for assembly that has thousands of pointers. Like text scripts, you can also store your assembly as separate text files and add comments to those files to explain what you're doing and why, and since they're text files, they're far easier to manage with whatever version control system you like (e.g. git) and are easy to integrate into a build process, so you never have to worry about losing work.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 04, 2020, 09:51:30 am
Level up! Chicken Knife's hacking skill increased by 2! :D
*joyous Final Fantasy level up fanfare plays*

If the alternative is directly hex editing a ROM, using an assembler for code changes provides several benefits. Probably the biggest one is automatic pointer calculation; if you thought that was great for insert scripts that only have a dozen pointers, you'll really love it for assembly that has thousands of pointers. Like text scripts, you can also store your assembly as separate text files and add comments to those files to explain what you're doing and why, and since they're text files, they're far easier to manage with whatever version control system you like (e.g. git) and are easy to integrate into a build process, so you never have to worry about losing work.
I'm sold. This process sounds like an important thing to explore in the near future. What's your recommendation as far as the most useful general purpose assembler? I almost care more about what software has the most robust and newbie friendly documentation. :laugh: Any learning resources or helpful communities you could point me towards would be helpful. (not that this isn't a helpful community). Otherwise, prepare for an agonizing perpetual barrage of questioning when the time comes.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 05, 2020, 07:03:15 pm
Your patch is doing LDA $6D79,X at $06:$AD20 instead of LDA $AD79,X; my guess is this is an error with your insert script, probably a missing/incorrect #HDR to set the appropriate pointer offsets for Cannock/Moonbrooke's names.

Thanks for the that, after the problem with the Prologue I should've known it would be that. I've gotten the hang of that HDR command now!  :laugh:

btw, maybe just for posterity's sake the Data Crystal wiki should have those pointers in the ROM Map 1AD13 Cannock Names Pointer and 1AD31 Moonbrooke Names Pointer (I'm only bringing this up because you have a Wiki account setup already)

So this is a problem that's seemingly plagued me for a while even after all my latest updates. Some text of Osterfair/Dirkandor was reported as glitched. So, near the end of Pointer #34 has the line (string 13) that should be

Code: [Select]
%u2018Ahh... [wait]'Tis a most gratifying thing indeed to see a strong man do battle... The bravery... The blood...! &swoon&%u2019[end-FC]
But instead I get

(https://i.imgur.com/d1aqyFV.png)

The interesting thing is, I can recognize the ORIGINAL line from Don Calico/Mahone at Pointer 45 (the last pointer of the first block where the first block of my script also is)

What's weird is Pointer 35 dialog (which has some other NPCs from the same area) seems to be okay and displaying fine. And if it's displaying stuff from the old script, surely there's still some space there. Is abcde/atlas not seeing enough room and switching over prematurely or maybe the space is JUST short enough it can't fit the whole set of strings? But if that were true why not just post the whole set in the new bank?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 05, 2020, 11:01:42 pm
*joyous Final Fantasy level up fanfare plays*
Wrong thread - you get the Dragon Warrior fanfare in this one, silly :P.

I'm sold. This process sounds like an important thing to explore in the near future. What's your recommendation as far as the most useful general purpose assembler? I almost care more about what software has the most robust and newbie friendly documentation. :laugh: Any learning resources or helpful communities you could point me towards would be helpful. (not that this isn't a helpful community). Otherwise, prepare for an agonizing perpetual barrage of questioning when the time comes.
I tend to use Asar for small patches, and assuming you're already familiar with 6502 ASM, you can get pretty far without needing to learn more than a handful of assembler syntax things, but the documentation for ca65 is definitely more extensive, so it's probably better for larger/more adventurous projects.

So this is a problem that's seemingly plagued me for a while even after all my latest updates.
Hmm, I'm not sure off the top of my head. I'll try to take a look tomorrow and see what I can see.

Edit: Alright, it looks like the issue here is with the code for switching from the first bank to the second bank for strings where the pointer points to the first bank but the string crosses over into the second bank. You'll need to update which bank to swap in at $FE11 (i.e. LDA #$0C) and the address within that bank to keep reading from at $FE32-$FE33 (i.e. 00 80).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 07, 2020, 06:26:59 pm
I just liken asar to programming like you'd use a script inserter to text as opposed to using a hex editor. Very much learned the benefits from all the battle dialog hacks abw helped me with.

Quote
Edit: Alright, it looks like the issue here is with the code for switching from the first bank to the second bank for strings where the pointer points to the first bank but the string crosses over into the second bank. You'll need to update which bank to swap in at $FE11 (i.e. LDA #$0C) and the address within that bank to keep reading from at $FE32-$FE33 (i.e. 00 80).

I'm really grateful for your help, but sad to say this didn't seem to change a thing. Is my Atlas file (http://www.mediafire.com/file/e7kqqhf720plzpf/atlas.txt/file) okay? Granted when I inserted my script I get a perfect 0 bytes remaining for the main script insertion so I fear something might be getting cut off in the two parts (but then if I'm still using Bank 07 for Part 1, why is there still old original text still there? That's what baffles me)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 07, 2020, 09:19:14 pm
Thanks guys. As of tonight, I think I've gotten as far as I can get with my code logging efforts alone. I fixed all the sprite issues and background palette issues, so I set out to start drawing crosses in Lancel, Necrogond, and a certain Buddhist symbol in Dharma Temple. I narrowed down the section of data that has draw instructions for the Lancel map in both the English and Japanese versions. Of course, the Japanese section is larger because of the presence of the added detail of the cross, and of course there is no immediate room for that extra data in the English version.

Is this the kind of issue I can fix with Asar, similar to what you (abw) did in the Temple of Hargon? If I understand this correctly, I would use Asar to essentially move all the code before or after the background drawing data? Since there are huge, continuous blocks of code before and after, wouldn't I essentially have to find every pointer for every single table? That seems like a nightmare. Or perhaps, I could make a jump into some other rom bank for that specific segment of data and then hopefully be able to rely on the Japanese draw instructions?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 07, 2020, 10:16:08 pm
I'm really grateful for your help, but sad to say this didn't seem to change a thing.
After applying your patch to a clean ROM and loading a save state near Osterfair, I was able to see garbage text from NPCs, though I got different garbage text than in your screenshot, but after changing those 3 bytes and reloading the ROM, I was getting the correct dialogue.

Is my Atlas file (http://www.mediafire.com/file/e7kqqhf720plzpf/atlas.txt/file) okay?
Have you tried extracting text from your patched ROM? If you do, I think you'll discover you've got a few more issues with pointers being off by some multiple of $4000, including at least the Osterfair fortune teller's dialogue, the end credits, and a particularly snazzy crash when acquiring a Crest.

(but then if I'm still using Bank 07 for Part 1, why is there still old original text still there? That's what baffles me)
You're getting leftover original text from bank 2 because the mid-pointer bank swap code is swapping in bank 2, not bank C where the rest of your new text is.

Is this the kind of issue I can fix with Asar, similar to what you (abw) did in the Temple of Hargon?
Redrawing the DW2 maps was all about changing the data, not the code, so it wasn't really an assembly task, though without a disassembly of the map drawing code I would not have wanted to have to try to guess at the map data format. Assuming DW3 uses the same system as DW2, you can try coming up with a different set of drawing instructions that takes up at most the same number of bytes as the original instructions. If that doesn't work (or is too hard; I never did come up with a decent algorithm for converting a map to the game's instruction format), the next easiest approach would probably be to find the pointer (or pointers, though probably there's only one and probably it's in a pointer table along with pointers to all the other maps) to the map and re-point it to some free area of ROM in the same bank and use that.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 07, 2020, 11:32:42 pm
After applying your patch to a clean ROM and loading a save state near Osterfair, I was able to see garbage text from NPCs, though I got different garbage text than in your screenshot, but after changing those 3 bytes and reloading the ROM, I was getting the correct dialogue.
Have you tried extracting text from your patched ROM? If you do, I think you'll discover you've got a few more issues with pointers being off by some multiple of $4000, including at least the Osterfair fortune teller's dialogue, the end credits, and a particularly snazzy crash when acquiring a Crest.
You're getting leftover original text from bank 2 because the mid-pointer bank swap code is swapping in bank 2, not bank C where the rest of your new text is.
Redrawing the DW2 maps was all about changing the data, not the code, so it wasn't really an assembly task, though without a disassembly of the map drawing code I would not have wanted to have to try to guess at the map data format. Assuming DW3 uses the same system as DW2, you can try coming up with a different set of drawing instructions that takes up at most the same number of bytes as the original instructions. If that doesn't work (or is too hard; I never did come up with a decent algorithm for converting a map to the game's instruction format), the next easiest approach would probably be to find the pointer (or pointers, though probably there's only one and probably it's in a pointer table along with pointers to all the other maps) to the map and re-point it to some free area of ROM in the same bank and use that.

Okay, I was able to fix the crashes because the Sigil Names and the Direction Names had a messed up pointer which my current patch still has. Once I fixed that the crashes for the fortune teller stopped and worked just fine.

I know you posted a chart or table of how memory addresses relate to ROM addresses. Can you post that again, please? I want to try to extract my new script like you suggested and I'm struggling to figure out if $28010 is in fact the correct HDR value for the second part of the script. It's every 3FFF bytes where the relation between pointers and locations change right? What's really blowing my mind is if the game changes banks for the text automatically how can I even keep track? I keep thinking it's Part 1 in Bank 7 and Part Two in Bank C but am I right in thinking some of that Part 1 text is in Bank C now and I have to find the pointer and update it?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 08, 2020, 09:25:59 am
I know you posted a chart or table of how memory addresses relate to ROM addresses. Can you post that again, please?
DW2 uses the MMC1 mapper, which operates on $4000 byte banks, so every $4000 bytes of ROM is a separate bank. ROM banks get loaded into RAM at either $8000 or $C000, though in DW2's case only ROM bank F ever gets loaded into RAM $C000. From there, a little bit of arithmetic tells you everything you need to know about translating between ROM and RAM addresses for DW2.

I want to try to extract my new script like you suggested and I'm struggling to figure out if $28010 is in fact the correct HDR value for the second part of the script. It's every 3FFF bytes where the relation between pointers and locations change right?
Unless you've moved data to a different bank than the one it was originally located in, you'll want the #HDR values in your insert script to match the #BASE POINTER values from your extract script.

What's really blowing my mind is if the game changes banks for the text automatically how can I even keep track? I keep thinking it's Part 1 in Bank 7 and Part Two in Bank C but am I right in thinking some of that Part 1 text is in Bank C now and I have to find the pointer and update it?
That's what all the #AUTOCMD stuff in your insert script is for - keeping track of how much of your script fits into the first script bank (which is bank 5, not bank 7) and then automatically switching to the second bank (originally bank 2, but bank C in your version) once the first bank is full and writing the index of the first pointer that points to the second bank to the code for determining which bank to load when starting to scan through a pointer. Since your version changes the bank and starting address of the second bank, you also need to update the separate section of code that handles the case where a group of strings starts in the first bank and crosses over into the second bank and tell it which bank to swap in (that's the line at RAM $FE11) and where to start reading from (that's RAM $FE23-$FE24).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 08, 2020, 10:09:53 am
DW2 uses the MMC1 mapper, which operates on $4000 byte banks, so every $4000 bytes of ROM is a separate bank. ROM banks get loaded into RAM at either $8000 or $C000, though in DW2's case only ROM bank F ever gets loaded into RAM $C000. From there, a little bit of arithmetic tells you everything you need to know about translating between ROM and RAM addresses for DW2.
Unless you've moved data to a different bank than the one it was originally located in, you'll want the #HDR values in your insert script to match the #BASE POINTER values from your extract script.
That's what all the #AUTOCMD stuff in your insert script is for - keeping track of how much of your script fits into the first script bank (which is bank 5, not bank 7) and then automatically switching to the second bank (originally bank 2, but bank C in your version) once the first bank is full and writing the index of the first pointer that points to the second bank to the code for determining which bank to load when starting to scan through a pointer. Since your version changes the bank and starting address of the second bank, you also need to update the separate section of code that handles the case where a group of strings starts in the first bank and crosses over into the second bank and tell it which bank to swap in (that's the line at RAM $FE11) and where to start reading from (that's RAM $FE23-$FE24).

This explanation is helpful. I've been wondering why I only have to worry about one unified storage limit for DQ2's text when multiple banks are involved.

Here's a question. There's a ton of banks for the script in DQ3, and I have a feeling my script insert is going to be a pretty tight fit. The last DQ3 script bank has an absolute ton of empty space. Would it be possible--or should I say easily doable--to set up autocommands resembling this setup for my DQ3 insert in order to unify all the storage into one total?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 08, 2020, 06:35:40 pm
In order to set the commands up you'll need to know how DQ3 handles its strings. DW3 doesn't work in the same way as DW2, so if you wanted to have strings automatically wrap into a new bank, you would have to add code to make that happen. How much that change would actually benefit you depends on how much free space your new script leaves at the ends of the first few banks. DW3 also has a few empty banks, so you can use those too if you need to.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 09, 2020, 07:36:32 am
In order to set the commands up you'll need to know how DQ3 handles its strings. DW3 doesn't work in the same way as DW2, so if you wanted to have strings automatically wrap into a new bank, you would have to add code to make that happen. How much that change would actually benefit you depends on how much free space your new script leaves at the ends of the first few banks. DW3 also has a few empty banks, so you can use those too if you need to.
I see. So DW2 was essentially built for this wrapping text, while DW3 was not. Let's see how it looks when I actually insert, and we will go from there.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 09, 2020, 12:49:58 pm
At some point last year, I made a patch for adding DTE and making it easy to access other banks; I figured it should be enough to let Choppasmith insert double the original script, but I didn't do any extensive testing or anything. You can give it a try (https://drive.google.com/open?id=1NlffKOmhXaDKXOsYgLxe-p4G_8dlDsI-) if you want!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 09, 2020, 01:39:57 pm
Perfect. That sounds easier since it's mostly ready to go. I'll let you know how the fit is looking when I get there soon.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 11, 2020, 07:29:38 pm
DW2 uses the MMC1 mapper, which operates on $4000 byte banks, so every $4000 bytes of ROM is a separate bank. ROM banks get loaded into RAM at either $8000 or $C000, though in DW2's case only ROM bank F ever gets loaded into RAM $C000. From there, a little bit of arithmetic tells you everything you need to know about translating between ROM and RAM addresses for DW2.
Unless you've moved data to a different bank than the one it was originally located in, you'll want the #HDR values in your insert script to match the #BASE POINTER values from your extract script.
That's what all the #AUTOCMD stuff in your insert script is for - keeping track of how much of your script fits into the first script bank (which is bank 5, not bank 7) and then automatically switching to the second bank (originally bank 2, but bank C in your version) once the first bank is full and writing the index of the first pointer that points to the second bank to the code for determining which bank to load when starting to scan through a pointer. Since your version changes the bank and starting address of the second bank, you also need to update the separate section of code that handles the case where a group of strings starts in the first bank and crosses over into the second bank and tell it which bank to swap in (that's the line at RAM $FE11) and where to start reading from (that's RAM $FE23-$FE24).

I'm such a dum dum. Until you posted this I thought you were posting a ROM address not a RAM address. Doh! Once I figured it out, sure enough the line worked for me!

But going back to this for a second. I tried making myself a RAM to ROM cheatsheet I could reference in the future as so:

Code: [Select]
MMC1 RAM-ROM Cheatsheet
Bank 0 (0-3FFF)    RAM -  7FF0 = ROM
Bank 1 (4000-7FFF) RAM -  3FF0 = ROM
*Bank 2 (8000-BFFF) RAM +  10   = ROM
Bank 3 (C000-FFFF) RAM +  4010 = ROM
Bank 4             RAM +  8010 = ROM
Bank 5             RAM +  C010 = ROM
Bank 6             RAM + 10010 = ROM
For every bank after just add 4000 (Bank 8 would be +18010)
*=Usually the default 

But thing is, I still, for the life of me, couldn't figure out a way to convert the addresses you gave me to ROM addresses. Only reason I figured it out was I found it in the ASM notes on Data Crystal. Obviously the above would be a great reference when I'm trying to calculate pointer values, but as far as I can tell there's no way to quickly go, "Oh, $8186 in RAM that's x***** in ROM". I'm looking back at this post.

DW2 uses the MMC1 mapper, which operates on $4000 byte banks, so every $4000 bytes of ROM is a separate bank. ROM banks get loaded into RAM at either $8000 or $C000, though in DW2's case only ROM bank F ever gets loaded into RAM $C000. From there, a little bit of arithmetic tells you everything you need to know about translating between ROM and RAM addresses for DW2.

And I noticed Everything before Bank F starts at $8000 while Bank F starts at C000. So something like $C120 would likely be in Bank F, but going back to the above example I made up, if you told me it's in $8186 how would I know what bank that's in? Or am I overthinking it and that's just not possible without looking at a debugger or ASM notes.

At some point last year, I made a patch for adding DTE and making it easy to access other banks; I figured it should be enough to let Choppasmith insert double the original script, but I didn't do any extensive testing or anything. You can give it a try (https://drive.google.com/open?id=1NlffKOmhXaDKXOsYgLxe-p4G_8dlDsI-) if you want!

Oh I was thinking about this the other day, glad you have it ready to go. Thank you! :D I'm really chomping at the bit to get to III. At least there's a light at the end of the tunnel that I'm getting closer and closer too :)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 12, 2020, 09:18:47 am
I'm such a dum dum. Until you posted this I thought you were posting a ROM address not a RAM address. Doh! Once I figured it out, sure enough the line worked for me!
Huzzah!

[...] going back to the above example I made up, if you told me it's in $8186 how would I know what bank that's in? Or am I overthinking it and that's just not possible without looking at a debugger or ASM notes.
Unless you're dealing with a game that doesn't use a memory mapper, ROM is larger (usually very much larger) than RAM, so there can't be any 1:1 mapping between RAM and ROM addresses. In general, whenever you have a RAM address, it could refer to any of a number of different ROM addresses, so in DW2's case, RAM $8186 could be ROM 0x196, 0x4196, 0x8196, ..., 0x38196 (or theoretically even 0x3C196, though DW2 doesn't actually mess around with its fixed bank settings).

Oh I was thinking about this the other day, glad you have it ready to go. Thank you! :D I'm really chomping at the bit to get to III. At least there's a light at the end of the tunnel that I'm getting closer and closer too :)
When you get around to using it, let me know how well it works!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 14, 2020, 09:43:42 pm
Okay small little update. No problems so far. *knock on wood*

First of all, a lot of my new script uses a surprising amount of 'Tis. Maybe it's just me but I don't think these weren't really intended to be placed by opening single quotes.

(https://i.imgur.com/QOZLT8k.png)

I'm not missing anything the Closing Single Quote and the Apostrophe, despite having unique and separate values are pretty much the same graphic right or have I messed up somewhere?

I mean I suppose I could use one of those unused letters and make a custom 'T letter graphic but I found by replacing one of the redundant dictionary entries with "(space)'Tis(space)" game me a whole 60 bytes of extra space!

Okay some fun info, I'm sure you guys have probably come across this, but early on, I really wanted to make the Cannock/Moonbrooke names go over the Japanese names especially since a lot of the Mobile/Switch names actually match the Japanese. At the time I thought, What if someone *expected* to see a certain name from playing it on Mobile?

Of course this is moot now as I applied abw's random name patch, but I was still curious and for the sake of posterity, the names are in ORDER (but with backwards kana)

Code: [Select]
″トンラ Rand
ンイカー Kain
サーア Arthur
ンナコ Conan
ーキック Cookie
ラヌント Tonnura
んさけす Sukesan
ロウ°ハ Paulo
ンりイア Eileen
アりマ Maria
  ナナ Nana
 なきあ Akina
ンり°フ Purin (Flan/Pudding)
 こいま Maiko
″タンり Linda
サンマサSamantha

So looking back at my script rip, the names are stored in the same order!

Code: [Select]
ランド    カイン アーサー  コナン      クッキー  トンヌラ  すけさん  パウロ  アイリン マリア  セティア  ユーイ   プリン   レナレナ  リンダ  サマンサ
Randolph  Kain   Arthur   Conrad     Caradoc   Thomas   Sigurd   Paul    Eileen  Maria Fleurette  Isolde  Peronel  Ginny    Lynda  Elaine

Note: The English here are the official English names, not translated. Interesting that Cannock kept all his names but Moonbrooke got couple new ones swapped in. Setia/Fleurette refers to the same character in DQ Swords (I had to go with Fleur because of the 8 character limit).

Lastly, abw I presume for that opening copyright splash screen you just used the existing letters and maybe edited your own?

(https://i.imgur.com/lUOygUk.png)

Because I happened to find myself watching the Secret of Evermore credits, and the small font they use is REAAAALLLY close. I didn't see any font in the Fonts section so I'm going to see if I can rip that font. Of course if there's some other font you used forget what I said then.

(https://www.vgfacts.com/attachments/full/1/1612.jpg)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 15, 2020, 09:04:02 am
Okay small little update. No problems so far. *knock on wood*
Yay progress!

I'm not missing anything the Closing Single Quote and the Apostrophe, despite having unique and separate values are pretty much the same graphic right or have I messed up somewhere?

I mean I suppose I could use one of those unused letters and make a custom 'T letter graphic but I found by replacing one of the redundant dictionary entries with "(space)'Tis(space)" game me a whole 60 bytes of extra space!
Closing single quotes and apostrophes use separate tiles (and separate code points, which is the important part for the associated logic) that just happen to look identical. If " 'Tis " is working well, then great; some other options to consider include changing the graphics for the opening and closing quotes to double quotes and stealing an unused tile to make an apostrophe aligned along the right edge of the tile instead of the left edge.

Lastly, abw I presume for that opening copyright splash screen you just used the existing letters and maybe edited your own?
Yup, mostly I was able to re-use the existing letters for my translation; I think I only had to draw a couple of letters by hand. The good news there is that it's harder to go wrong when trying to add missing letters for a 1px VWF :P.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 19, 2020, 09:00:48 pm
Well I feel silly, there was one already there!

(https://i.imgur.com/QSzQecu.png)

Plus I forgot, I can't do a space before the apostrophe. It worked out well.

Also, the SoE font worked great! You can hardly tell it's a different font.

(https://i.imgur.com/wdViGMa.png)

I would've ripped it, but not sure if I was able to get it displayed right in TLP especially because some tiles like OK and the p and q seemed to dip down in a weird way. But anyway, not worth the headache and we'd be getting off topic.

So apparently I have one last problem. The guard in the Tantegel throne room actually crashes the game (In JNes the emulator itself crashes)

Now, to my credit, I ran trace logger and found that it seems to crash at $B3C9 which is related to the Dictionary

The line it crashes at is

 
Code: [Select]
‘Well met, friends! You are the descendants of mighty Erdrick, are ye not? Seek ye an audience with the King?’[wait][line]
‘Alas, His Majesty is not here. He was, um...called away upon some urgent matter, and...’[wait][line]
‘Fie on't! I shall not lie. Fearing Hargon’s wrath, he hath hid himself from the world. 'Tis an embarrassment indeed...’[end-FC]

And it actually gets as far as printing som in that second line there and that's where it crashes. I DO have an entry for "ome" in my dictionary and I double checked nothing weird going on there, right values.

Interesting enough this is Pointer 34 String 10 (or A if you prefer) just a couple lines up from the Dirkandor string that was giving me trouble that needed the bank switch code update. Is it possible this string is right on the border or something (Between Part 1 and Part 2)?

Here's the log I made
https://www.mediafire.com/file/njbwbb71h2wstkq/dw2log.txt/file
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 20, 2020, 09:59:03 pm
So apparently I have one last problem.
As it turns out, I think we all have a problem, actually.

But first, your crash is due to some pointless bankswap code in the original game. Aside from setting the variable for which bank to swap in when reading the next text token, the routine that sets the bank and start address of the next text block when it detects overflow from the first text bank also immediately swaps the next text bank in, which means that when that routine is called from bank 2, its RTS doesn't end up back in bank 2 but in your bank C, where it starts executing your script as code and crashes when it hits a byte corresponding to an invalid opcode. Fun times.

The good news is that this one is easy to fix - just NOP out the problematic JSR $FCF6 at $0F:$FE16 (0x03FE26).

The other problem we all have is that I missed a detail in how DW2's text engine handles transitioning from the first text bank to the second text bank - it actually requires a copy of the first byte of the second text bank to be placed after the last byte of the first bank. In the original game, this means that $05:$BFD7 (0x017FE7) has to have the same byte value as $02:$B7B2 (0x00B7C2); Choppasmith's version will require $05:$BFD7 to be a copy of $0C:$8000 instead.

The bad news is that abcde can't currently handle this for you, so you'll have to copy your second bank's first script byte to 0x017FE7 on your own in the meantime. If you want to automate that in your build script, something like this should do the trick:
Code: [Select]
perl -e "open(my $ROM, '+<', 'Dragon Warrior II (U) [LA].nes'); seek($ROM, 0x0B7C2, 0); read($ROM, my $byte, 1); seek($ROM, 0x017FE7, 0); print $ROM $byte;"
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 21, 2020, 09:06:37 pm
As it turns out, I think we all have a problem, actually.

But first, your crash is due to some pointless bankswap code in the original game. Aside from setting the variable for which bank to swap in when reading the next text token, the routine that sets the bank and start address of the next text block when it detects overflow from the first text bank also immediately swaps the next text bank in, which means that when that routine is called from bank 2, its RTS doesn't end up back in bank 2 but in your bank C, where it starts executing your script as code and crashes when it hits a byte corresponding to an invalid opcode. Fun times.

The good news is that this one is easy to fix - just NOP out the problematic JSR $FCF6 at $0F:$FE16 (0x03FE26).

The other problem we all have is that I missed a detail in how DW2's text engine handles transitioning from the first text bank to the second text bank - it actually requires a copy of the first byte of the second text bank to be placed after the last byte of the first bank. In the orginal game, this means that $05:$BFD7 (0x017FE7) has to have the same byte value as $02:$B7B2 (0x00B7C2); Choppasmith's version will require $05:$BFD7 to be a copy of $0C:$8000 instead.

The bad news is that abcde can't currently handle this for you, so you'll have to copy your second bank's first script byte to 0x017FE7 on your own in the meantime. If you want to automate that in your build script, something like this should do the trick:
Code: [Select]
perl -e "open(my $ROM, '+<', 'Dragon Warrior II (U) [LA].nes'); seek($ROM, 0x0B7C2, 0); read($ROM, my $byte, 1); seek($ROM, 0x017FE7, 0); print $ROM $byte;"

Worked like a charm, thanks! For Chicken Knife (and anyone else lurking) adding this to your Atlas file is a quick and easy way to get rid of the Subroutine that abw mentioned above

Code: [Select]
#JMP($3FE26)
// Remove problematic script subroutine
<$EA><$EA><$EA>

And that should do it, outside of some final tweaks, getting some comparison screens, and actually uploading to RHDN I'm done with DQ2! I saw this the other day about how it sums up the game in general, but man I couldn't help but make one little tweak to sum up this experience

(https://i.imgur.com/KbVA7d3.png)

Thank you SO much abw, you're awesome!  :thumbsup: Please know, I'm immeasurably grateful!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 21, 2020, 09:47:33 pm
Ha! That made my day. So much truth in that meme.

Code: [Select]
#JMP($3FE26)
// Remove problematic script subroutine
<$EA><$EA><$EA>
As far as this code, I simply plug this anywhere into the upper part of my insert file and this will avoid the hazards discussed above, eh?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 22, 2020, 12:19:23 am
Ha! That made my day. So much truth in that meme.

Code: [Select]
#JMP($3FE26)
// Remove problematic script subroutine
<$EA><$EA><$EA>
As far as this code, I simply plug this anywhere into the upper part of my insert file and this will avoid the hazards discussed above, eh?

That and you need to add this to your Atlas.bat file

Code: [Select]
perl -e "open(my $ROM, '+<', 'Dragon Warrior II (U) [LA].nes'); seek($ROM, 0x0B7C2, 0); read($ROM, my $byte, 1); seek($ROM, 0x017FE7, 0); print $ROM $byte;"

I'm sure there's a bunch of ways to do it, I added this after the "pause"and then added another pause after this. Replace Dragon Warrior II (U) [LA].nes with your output file (the same output file that was already in the bat).

You can manually do this by opening up your rom and go to 17FE7 and see if it's the same as B7C2. So for example, in my case, 17FE7's byte read 1F, so you'd go to B7C2 to see if THAT says 1F. If it does you're good.

Looking forward to NOT having to deal with this system for III.

Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 22, 2020, 09:23:05 am
I'm torn between "a woman's work is never done" and "working like a dog", cuz, you know :P.

Disabling the bank swap is only required if you've changed the second text bank to not be bank 2, though you'll also save some cycles by not swapping banks.

The game should only care about 4 bits from 0x017FE7, so there's something like a 1/16 chance that your script was okay, subject to your script's token distribution and pointer alignment. You can test it by finding the string that gets split between banks and checking it out in game; probably your current version will have one incorrect token, but if you were unlucky and one of the C0 - C4 switches was affected, then the entire rest of the string could be messed up.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 22, 2020, 09:45:19 am
It sounds like erring on the side of caution is a good thing. Although I didn't notice an issue on any of my plays, one incorrect token is enough to drive me mad. It sounds like I should add these tweaks as a precaution.

FYI, I don't run the inserts via a .bat file. I have a text file with all the relevant insert / extract commands I use and I just copy and paste them into command prompt. I think I had a problem doing it via .bat initially and never bothered to revisit. I'm a little unclear how I would combine that new command with my existing command that runs the insertion.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 22, 2020, 11:08:09 pm
FYI, I don't run the inserts via a .bat file. I have a text file with all the relevant insert / extract commands I use and I just copy and paste them into command prompt.
That's essentially what a .bat file is :P.

As long as you copy the byte after you've finished inserting your script, it shouldn't matter where in your process you do that, so you could just add that perl line to your text file after your insert command.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 27, 2020, 08:40:15 am
I have a problem I'm not certain how to approach. I'm currently in the middle of a polishing effort of my text in DQ2, and I have a scenario that is making me a bit crazy. I let the issue slide previously, but now that I'm being more focused on perfect grammar, I can't sit idle. I'm hoping you guys might be able to help.

The original pointer 4 line: Of Experience points thou has gained [number][FF] is causing me some major grief.

In a normal battle, the code puts a space at the end of that after the number and then prints: "and earned [number] piece[(s)] of gold." from pointer 8.

My issue here is that it forces me into using bad grammar. The only way to avoid needing a comma in that sentence after the experience amount earned is if you could phrase it like" You have obtained X experience and X pieces of gold. Yet, the text engine doesn't accommodate a point[(s)] situation for experience like it does for gold. The irony is that it doesn't even need to switch between singular and plural for pieces of gold. One thing I've tried is putting a comma right before the [FF] on the first line, but that becomes problematic when you find a random drop from an enemy. The system no longer puts a space but it puts a period or something, which leaves you with a comma and a period, if I remember correctly.

I vaguely recall the two of you discussing something along these lines in the past. Any ideas?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 27, 2020, 09:14:28 am
I have a problem I'm not certain how to approach. I'm currently in the middle of a polishing effort of my text in DQ2, and I have a scenario that is making me a bit crazy. I let the issue slide previously, but now that I'm being more focused on perfect grammar, I can't sit idle. I'm hoping you guys might be able to help.

The original pointer 4 line: Of Experience points thou has gained [number][FF] is causing me some major grief.

In a normal battle, the code puts a space at the end of that after the number and then prints: "and earned [number] piece[(s)] of gold." from pointer 8.

My issue here is that it forces me into using bad grammar. The only way to avoid needing a comma in that sentence after the experience amount earned is if you could phrase it like" You have obtained X experience and X pieces of gold. Yet, the text engine doesn't accommodate a point[(s)] situation for experience like it does for gold. The irony is that it doesn't even need to switch between singular and plural for pieces of gold. One thing I've tried is putting a comma right before the [FF] on the first line, but that becomes problematic when you find a random drop from an enemy. The system no longer puts a space but it puts a period or something, which leaves you with a comma and a period, if I remember correctly.

I vaguely recall the two of you discussing something along these lines in the past. Any ideas?

Huh? The line in Pointer 8 is actually the post battle Gold acquisition. Mine is
[no voice][line][number] gold coin[(s)] obtained![end-FC]

However when an enemy drops a treasure chest after battle it'll play the line in Pointer 4 used for gold in treasure boxes which for me is:
[line]What luck! [name] finds [number] gold coin[(s)]![end-FC] 

The line after that is:
[FD][number] experience point[(s)] earned![FF][wait]Their strength increases by [number].[end-FC]

I think the original tries to combine it like a pair of sentences but I made sure it starts a new line which is what it does in Mobile/Switch.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 27, 2020, 09:24:28 am
Yeah, the original game's punctuation and capitalization left a few things to be desired. The situation is actually more complicated than you describe, since if you find a random drop, you also need to account for whether the first hero with an empty inventory slot is alive or not.

Checking the disassembly (https://datacrystal.romhacking.net/wiki/Dragon_Warrior_II::ROM_map/ASM), it looks like strings are displayed in the following order:

String ID #$0049: [FD]Of Experience points thou has gained [number][end-FF]
(if you get a drop:)
   String ID #$008A: .[end-FC]
   String ID #$014A: [wait][name] had the Treasure Chest.[wait][end-FC]
   String ID #$0105: Seeing a treasure chest, [name] opened it.[wait][end-FC]
   String ID #$0104: And there [name] discovered the [item]![end-FC]
   (if hero with the first empty inventory slot is dead:)
      String ID #$0117: gave the [item] to the ghost of [name].[end-FC]
   String ID #$0048: And earned [number] piece[(s)] of gold.[end-FC]
(if you did not get a drop:)
   String ID #$008B: [no voice]and earned [number] piece[(s)] of gold.[end-FC]

Does that help any? If you can come up with new text that works within that model, then great; if not and you want to start changing the logic for which strings get displayed, the code for that can be found at $04:$9768 - $04:$98CB. You should be able to use the [(s)] control code for experience points too, you'll just need to update the dictionary first (and you'll want to apply the Main Script F2 Fix (http://www.romhacking.net/hacks/4751/) if you do so).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 27, 2020, 09:32:04 pm
Yeah, the original game's punctuation and capitalization left a few things to be desired. The situation is actually more complicated than you describe, since if you find a random drop, you also need to account for whether the first hero with an empty inventory slot is alive or not.

Checking the disassembly (https://datacrystal.romhacking.net/wiki/Dragon_Warrior_II::ROM_map/ASM), it looks like strings are displayed in the following order:

String ID #$0049: [FD]Of Experience points thou has gained [number][end-FF]
(if you get a drop:)
   String ID #$008A: .[end-FC]
   String ID #$014A: [wait][name] had the Treasure Chest.[wait][end-FC]
   String ID #$0105: Seeing a treasure chest, [name] opened it.[wait][end-FC]
   String ID #$0104: And there [name] discovered the [item]![end-FC]
   (if hero with the first empty inventory slot is dead:)
      String ID #$0117: gave the [item] to the ghost of [name].[end-FC]
   String ID #$0048: And earned [number] piece[(s)] of gold.[end-FC]
(if you did not get a drop:)
   String ID #$008B: [no voice]and earned [number] piece[(s)] of gold.[end-FC]

Does that help any? If you can come up with new text that works within that model, then great; if not and you want to start changing the logic for which strings get displayed, the code for that can be found at $04:$9768 - $04:$98CB. You should be able to use the [(s)] control code for experience points too, you'll just need to update the dictionary first (and you'll want to apply the Main Script F2 Fix (http://www.romhacking.net/hacks/4751/) if you do so).
Ah! You know I kinda forgot all about that little thing and never really looked into it figuring it was way too minor to bother with. Right now in my hack, whenever an enemy drops an item it just goes

Code: [Select]
"What Luck! [Hero] finds the [item]!
What luck! [Hero] find [number] gold coin[s]"

Instead of the default
Code: [Select]
"[no voice][line][number] gold coin[s] obtained!"
Didn't realize it's just an easy one byte fix.

BTW, this made me think about that weird little flaw when facing a single enemy group, say, 3 Slimes. If you fight mixed enemies, it'll say you defeated "the enemies" but for the Slimes it'll just say "You defeated the Slime." Because of the monster IDs, yeah. I was trying to figure a way we might be able to fix that. Now, this isn't a huge deal, but I was trying to think of what I've learned to explore the possibility. So here's how it originally

Code: [Select]
0x011752|$04:$9742:AD 60 01 LDA $0160  ; ID of only monster (/monster group) or #$53 for "Enemies" if there are multiple groups
0x011755|$04:$9745:A2 00    LDX #$00   
0x011757|$04:$9747:20 D6 9C JSR $9CD6  ; write monster name in A (+ monster number within its group in X, if > 0) to $6119
0x01175A|$04:$974A:A9 19    LDA #$19    ; String ID #$0019: Thou hast defeated the [name].[end-FC]
0x01175C|$04:$974C:20 CA 9C JSR $9CCA  ; for A < #$60, display string ID specified by A; for A >= #$60, display string ID specified by A + #$A0
0x01175F|$04:$974F:AD 61 01 LDA $0161  ; current monster ID
0x011762|$04:$9752:C9 52    CMP #$52   
0x011764|$04:$9754:D0 05    BNE $975B 
0x011766|$04:$9756:A9 00    LDA #$00   

If we added  JSR $87F5 (plural code) after $9747 wouldn't that effectually add the plural if need be? When it jumps back it would say "Thou hast defeated the Slimes.", right? The only problem I see with that is since my dialog is more present tense "The [name] is defeated." you'd have to change the is to are for plural or make a new letter/dictionary entry like #F2 where it prints is or are based on the Y value (number of monsters). Even if that was plausible I wouldn't want to waste valuable script space.

Like I said, this was just a bit of a thought exercise/thinking out loud.

EDIT: On a related note I just saw that Bank 06 has the code pertaining to the Gold+Copper Sword combo you get from the King of Midenhall at beginning of the game. And I don't have enough room to add the new line from the mobile version D:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on May 28, 2020, 11:28:25 am
I would definitely be on board with wanting to pluralize the word for monsters when a group of a single type is defeated. If we *cough abw cough* are able to do this, I think it would be a valuable independent fix patch as well.

Btw, thank you guys for the the suggestions above. I had a very dull moment in thinking that the [(s)] function wouldn't work more universally. I'm very satisfied with the results of adjusting the dictionary, tweaking the text and incorporating the Main Script F2 Fix. I don't think I need to make any more aggressive changes with the battle rewards text.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 28, 2020, 07:31:30 pm
If we added  JSR $87F5 (plural code) after $9747 wouldn't that effectually add the plural if need be?
I think the problem with this was that we didn't know whether the number of monsters was still available in RAM, let alone where that value was stored, which makes it hard for the pluralization code to do the right thing.

EDIT: On a related note I just saw that Bank 06 has the code pertaining to the Gold+Copper Sword combo you get from the King of Midenhall at beginning of the game. And I don't have enough room to add the new line from the mobile version D:
You could get adventurous and try to expand the text into a third bank >:D. You can use Dragon Warrior III as an example of one way of coding that.

I had a very dull moment in thinking that the [(s)] function wouldn't work more universally.
[(s)] works based on the same RAM addresses as [number], so as long as you use the two of them together, it should be fine, but if you try to use it in any string that doesn't contain [number], you might not get the behaviour you want.

I'm very satisfied with the results of adjusting the dictionary, tweaking the text and incorporating the Main Script F2 Fix. I don't think I need to make any more aggressive changes with the battle rewards text.
Huzzah!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 31, 2020, 12:36:44 am
So does the game just not like using the 16th string in a set? As said before, now that I've got a little more room, I wanted to add a unique line when you got the Gold and Copper Sword at the beginning instead of just using the two standard treasure finding strings. I figured I'd put the two at the end of Pointer #4


Here's the section from the assembly.

Code: [Select]
0x019C6B|$06:$9C5B:20 2A FA JSR $FA2A  ; display string ID specified by next byte

; code -> data
; indirect data load target
0x019C6E|$06:$9C5E:48 ; String ID #$0048: And earned [number] piece[(s)] of gold.[end-FC]

; data -> code
0x019C6F|$06:$9C5F:4C 48 95 JMP $9548  ; end TALK/ITEM routines

; find a regular item
; control flow target (from $9C09)
; call to code in a different bank ($0F:$FA2E)
0x019C72|$06:$9C62:20 2E FA JSR $FA2E  ; display string ID specified by next byte + #$0100

; code -> data
; indirect data load target
0x019C75|$06:$9C65:04 ; String ID #$0104: And there [name] discovered the [item]![end-FC]

I went to change String 48 to 4E which should be "What luck! A copper sword and [number] gold coin[(s)]![end-FC]"

And then I changed the second line 104 to "[name] gratefully pockets the lot![end-FC]" to string 4F.

When I fired up the game the first line just came out "[name] and the second line came out "They learned a new spell!" (which is weird because that second line  would be 4D.

Now hold on abw! I did catch my mistake after this. I see that for the second line, it uses a different subroutine to use a line much later in the rom, so I changed that line, $9C62,  from JSR $FA2E to JSR $FA2A.

And this is where I'm puzzled. The first line now works, but I still get "They learned a new spell!" for the second. I don't understand what the game's doing here. I did run a log and all I can see when comparing it to the assembly is that when it jumps to FA2A it doesn't jump back. Should I just NOP out the second dialog line and have the two lines together for the first?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on May 31, 2020, 09:51:19 am
And this is where I'm puzzled. The first line now works, but I still get "They learned a new spell!" for the second.
Your String #$004E = "[wait]They learned a new spell![end-FC]", so the game's doing exactly what you told it to do :P.

A bigger problem is that if you change the strings used for normal gold and item chests, those changes will affect all treasure chests, not just the Copper Sword chest, so you're also going to need to rewrite the code for displaying a string after opening a chest to use string #$004F for the Copper Sword and the normal string #$0104 for all other item chests.

What you want is something like this (untested), except there's not enough space in the original location so you'll need to JSR to some free space and then return to hook up with the rest of the existing code:
Code: [Select]
$06:$9C62:
; check to see if the item is a Copper Sword first
LDA $96    ; temp storage for item/spell/type/etc. IDs; item ID
CMP #$06    ; Item ID #$06: Copper Sword
; if it's not a Copper Sword, branch to display the normal string and execute the rest of the normal code
BNE .normal_item
; if it is a Copper Sword...
; add the item to Midenhall's inventory
LDA #$00    ; Midenhall
STA $97    ; subject hero ID $97
JSR $8D7E  ; given hero ID in $97 and item ID in $96, try to add item to first empty slot in hero's inventory; SEC if added, CLC if no empty slots
; add the gold to party gold
LDA #$32    ; at this point in the game, Midenhall is incapable of having a full inventory, so no need to check C; #$32 = 50 Gold
JSR $8D2A  ; set $8F-$90 to A-#$00
JSR $8CF5  ; add $8F-$90 to party gold, capped at $FFFF
; display your new string
JSR $FA2A  ; display string ID specified by next byte
.db $4F ; String ID #$004F: What luck! A copper sword and [number] gold coin[(s)]![wait][name] gratefully pockets the lot![end-FC]
; and finish
JMP $9548  ; end TALK/ITEM routines

.normal_item:
JSR $FA2E  ; display string ID specified by next byte + #$0100
.db $04 ; String ID #$0104: And there [name] discovered the [item]![end-FC]
$06:$9C7B:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on May 31, 2020, 11:55:20 am
Your String #$004E = "[wait]They learned a new spell![end-FC]", so the game's doing exactly what you told it to do :P.

But that’s the third to last string, wouldn’t that be 4D?  :huh:

In any case, I didn’t realize I was changing how all treasure chests work. Doesn’t seem worth it to me (just don’t want to risk borking something else at this point)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 02, 2020, 09:47:30 pm
But that’s the third to last string, wouldn’t that be 4D?  :huh:
Hmm, nope, it's definitely the second last string in its block. I don't know what else you're counting :P.

In any case, I didn’t realize I was changing how all treasure chests work. Doesn’t seem worth it to me (just don’t want to risk borking something else at this point)
The code changes aren't drastic and are pretty easy to test (open the Copper Sword chest, an item chest, and a gold chest and make sure they all have the appropriate text), but it's your call. You can definitely save it for later if/when you're feeling more adventurous!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 06, 2020, 03:55:01 pm
Hmm, nope, it's definitely the second last string in its block. I don't know what else you're counting :P.

//POINTER #4 @ $B76A - STRING #4 @ $143E6
#W16($B76A)
#INC(pointerNum, 1)
40It did not work against [name].[end-FC]

41[name] holds the power shield aloft![end-FC]

42[name] is cursed, and cannot move![end-FC]

43[name] is no longer poisoned![end-FC]

44[name] miraculously comes back to life![end-FC]

45cannot use the spell yet.[end-FC]

46[name] isn't carrying any items.[end-FC]

47[wait][name]'s level increases![end-FC]

48[line]What luck! [name] finds [number] gold coin[(s)]![end-FC]

49[FD][number] experience point[(s)] earned![FF][wait]Their strength increases by [number].[end-FC]

4A[wait]Their agility increases by [number].[end-FC]

4B[wait]Their maximum HP increases by [number].[end-FC]

4C[wait]Their maximum MP increases by [number].[end-FC]

4D[wait]They learned a new spell![end-FC]

4E[end-FC]

4F[end-FC]

???

Not trying to be smarmy, I'm genuinely confused. Speaking of this set of strings, does anyone know what "cannot use the spell yet." is used for? It's one of the only lines I haven't updated. I thought it was having spells blocked in battle or trying to use spells with a character who's dead but those are definitely different lines. I see it in the Assembly at Bank 03 $B3BD and it seems menu related.

Speaking of that Bank though, as said above I thought I'd update the code so that the Gold obtained message for after battle is ALWAYS string #8B instead of the string 48 which is also used for treasure boxes. But it's not a 1 byte fix like I thought it'd be

 
Code: [Select]
; control flow target (from $98A7)
0x0118BE|$04:$98AE:8D 25 06 STA $0625  ; party gold, high byte
0x0118C1|$04:$98B1:A5 99    LDA $99    ; store received gold to $8F-$90 so we can print it later
0x0118C3|$04:$98B3:85 8F    STA $8F   
0x0118C5|$04:$98B5:A5 9A    LDA $9A   
0x0118C7|$04:$98B7:85 90    STA $90   
0x0118C9|$04:$98B9:AD B0 61 LDA $61B0  ; flag for whether you get an item drop or not
0x0118CC|$04:$98BC:D0 0B    BNE $98C9  ; if you get an item drop, go deal with that
0x0118CE|$04:$98BE:A9 8B    LDA #$8B    ; String ID #$008B: [no voice]and earned [number] piece[(s)] of gold.[end-FC]
0x0118D0|$04:$98C0:20 EA 9C JSR $9CEA  ; set return bank $94 to #$04
; call to code in a different bank ($0F:$FA4A)
0x0118D3|$04:$98C3:20 4A FA JSR $FA4A  ; display string ID specified by A
0x0118D6|$04:$98C6:4C CE 98 JMP $98CE 

; control flow target (from $98BC)
0x0118D9|$04:$98C9:A9 48    LDA #$48    ; String ID #$0048: And earned [number] piece[(s)] of gold.[end-FC]
0x0118DB|$04:$98CB:20 CA 9C JSR $9CCA  ; for A < #$60, display string ID specified by A; for A >= #$60, display string ID specified by A + #$A0

At first I just changed $98C9 but quickly realized the subroutine after wouldn't work because A0 would be added to 8B getting me a new line, so I changed $98CB from JSR $9CCA to JSR $FA4A so that it would display string 8B without changing the value. Now I get "[name] opens the treasure chest..." and it jumps straight to "[number] gold coin[(s)] obtained." Would just making $98C9 jump back to $98BE or just removing that branch at $98BC be the way to go?

Oh btw Chicken Knife, if you're still having trouble getting space with your dictionary. Here's mine, I also added little notes to where the length values are to better keep track.

Code: [Select]
# 00100 is an intermediate end token, used to subdivide larger strings where the same function needs to be called multiple times with different values.
# E.g. in
# [name] [end-FF]threw away [name]'s [item] and gave [end-FF]the [item] to ghost of [name].[end-FC]
# the first [name] is the Prince of Midenhall's name, but the second and third [name] are the name of the dead party member whose items you are ransacking;
# similarly, the first [item] is the item you lose, but the second [item] is the item you gain.
# I have added addresses and values as comments preceeding each pair of entries to better keep track -Choppasmith

# B44B=12
/%00000=[end-FC]\n\n
/%00001=.[end-FC]\n\n
# B44C=52
/%00010=?%u2019[FD][FD][end-FC]\n\n
/%00011=[.%u2019][end-FC]\n\n
# B44D=11
%00100=[FF]
%00101=a
# B44E=11
%00110=c
%00111=o
# B44F=11
%01000=d
%01001=e
# B450=11
%01010=p
%01011=g
# B451=11
%01100=h
%01101=i
# B452=21
%01110=,
%01111=
# B453=11
%10000=l
%10001=m
# B454=11
%10010=n
%10011=b
# B455=11
%10100=T
%10101=%u2018
# B456=11
%10110=r
%10111=s
# B457=11
%11000=t
%11001=u
# B458=11
%11010=y
%11011=w
# B459=11
%11100=[switch to C0 table]
%11101=[switch to C1 table]
# B45A=11
%11110=[switch to C2 table]
%11111=[switch to C3 table]

# C0 table
# B45B=11
%1110000000=A
%1110000001=B
# B45C=21
%1110000010=Ca
%1110000011=D
# B45D=11
%1110000100=E
%1110000101=F
# B45E=11
%1110000110=G
%1110000111=H
# B45F=11
%1110001000=I
%1110001001=J
# B460=41
%1110001010=King
%1110001011=L
# B461=A1
%1110001100=Moonbrooke
%1110001101=N
# B462=14
%1110001110=O
%1110001111=he [item]
# B463=49
%1110010000=The
%1110010001= Rendarak
# B464=13
%1110010010=S
%1110010011=eth
# B465=11
%1110010100=U
%1110010101=%u201D
# B466=31
%1110010110=uff
%1110010111=C
# B467=11
%1110011000=Y
%1110011001=Z
# B468=13
%1110011010=x
%1110011011=Ver
# B469=11
%1110011100=z
%1110011101=[F9]
# B46A=11
%1110011110=%u201F
%1110011111=K

# C1 table
# B46B=12
%1110100000=v
%1110100001=qu
# B46C=31
%1110100010=%u2019[wait][line]\n
%1110100011=R
# B46D=12
%1110100100=.
%1110100101=[FD][FD]
# B46E=11
%1110100110=P
%1110100111=[line]\n
# B46F=11
%1110101000=[.%u2019]
%1110101001=!
# B470=11
%1110101010=[sun]
%1110101011=[star]
# B471=11
%1110101100=[moon]
%1110101101=W
# B472=11
%1110101110=k
%1110101111=f
# B473=11
%1110110000=?
%1110110001=j
# B474=12
%1110110010=[monster]
%1110110011=...
# B475=21
%1110110100=:
%1110110101='
# B476=11
%1110110110=-
%1110110111=%u2019
# B477=91
%1110111000= casts [spell]!
%1110111001=[letter]
# B478=11
%1110111010=[no voice]
%1110111011=[wait]
# B479=11
%1110111100=M
%1110111101=[name]
# B47A=11
%1110111110=[number]
%1110111111=[FD]

# C2 table
# B47B=13
%1111000000=&
%1111000001=est
# B47C=94
%1111000010=Midenhall
%1111000011=hou
# B47D=33
%1111000100= of
%1111000101=is
# B47E=44
%1111000110= art
%1111000111=and
# B47F=54
%1111001000=to th
%1111001001=thee
# B480=32
%1111001010=ast
%1111001011=do
# B481=37
%1111001100=hat
%1111001101= shall
# B482=32
%1111001110=was
%1111001111=!%u2019
# B483=54
%1111010000=d the
%1111010001= has
# B484=34
%1111010010=eve
%1111010011=ight
# B485=37
%1111010100=ave
%1111010101= friend
# B486=33
%1111010110=ing
%1111010111=rom
# B487=34
%1111011000=las
%1111011001=this
# B488=76
%1111011010= of the
%1111011011=Hargon
# B489=74
%1111011100=in the
%1111011101=thin
# B48A=35
%1111011110=he
%1111011111= with

# C3 table
# B48B=93
%1111100000=treasure
%1111100001=our
# B48C=83
%1111100010= Erdrick
%1111100011=ome
# B48D=83
%1111100100=wanderer
%1111100101=ell
# B48E=56
%1111100110=rince
%1111100111= great
# B48F=36
%1111101000=arr
%1111101001= 'Tis
# B490=13
%1111101010=[(s)]
%1111101011=[.%u2019][wait][line]\n
# B491=34
%1111101100=But
%1111101101=here
# B492=33
%1111101110=can
%1111101111=ove
# B493=53
%1111110000= gold
%1111110001=not
# B494=33
%1111110010=for
%1111110011=one
# B495=33
%1111110100=any
%1111110101=to
# B496=8F
%1111110110= Goddess
%1111110111=Roge Fastfinger
# B497=33
%1111111000=all
%1111111001=thy
# B498=24
%1111111010=%u2018W
%1111111011= key
# B499=34
%1111111100= it
%1111111101= tha
# B49A=54
%1111111110= thou
%1111111111= the

One thing that's really helped me is, if you haven't already, get Notepad+. Then, try searching for various pieces of phrases/words and then select Count in the search window. If you're getting under 10 you might want to update that entry (UNLESS it's one of those unique control codes the game HAS to have). Remember to use spaces before a lot of your words too!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 06, 2020, 10:12:46 pm
49[FD][number] experience point[(s)] earned![FF][wait]Their strength increases by [number].[end-FC]
That [FF] is also an end token, so your numbers for 4A-4F are all off by one. There are a few other FF end tokens scattered throughout the script, so keep those in mind when counting strings.

Speaking of this set of strings, does anyone know what "cannot use the spell yet." is used for?
I haven't gone through all the related code, so I could be wrong, but I don't think you can trigger this message, and my CDL file shows that I never did over the course of an entire playthrough. I suspect it was intended for use in some alternate reality where your casters didn't both start already knowing some in-battle spell, or possibly a leftover from Dragon Warrior, where you actually don't learn your first spell until after a few levels.

Would [...]just removing that branch at $98BC be the way to go?
Hmm, yeah, disabling the BNE at $04:$98BC should result in string #$008B always being used for gold from battle. Give it a try!

Here's mine, I also added little notes to where the length values are to better keep track.
This is untested, but I think it should save you over 1500 ($600) bytes compared to your current dictionary:
Spoiler:
Code: [Select]
/%00000=[end-FC]\n\n
/%00001=.[end-FC]\n\n
/%00010=?’[FD][FD][end-FC]\n\n
/%00011=[.’][end-FC]\n\n
# 00100 is an intermediate end token, used to subdivide larger strings where the same function needs to be called multiple times with different values.
# E.g. in
# [name] [end-FF]threw away [name]'s [item] and gave [end-FF]the [item] to ghost of [name].[end-FC]
# the first [name] is the Prince of Midenhall's name, but the second and third [name] are the name of the dead party member whose items you are ransacking;
# similarly, the first [item] is the item you lose, but the second [item] is the item you gain.
/%00100=[end-FF]\n\n
%00101=
%00110=e
%00111=t
%01000=o
%01001=a
%01010=h
%01011=s
%01100=n
%01101=r
%01110=i
%01111=l
%10000=d
%10001=u
%10010=f
%10011=m
%10100=c
%10101=y
%10110=g
%10111=w
%11000=p
%11001=,
%11010=‘
%11011=!
%11100=[switch to C0 table]
%11101=[switch to C1 table]
%11110=[switch to C2 table]
%11111=[switch to C3 table]

# C0 table
%1110000000=A
%1110000001=B
%1110000010=[ ’]
%1110000011=D
%1110000100=E
%1110000101=F
%1110000110=G
%1110000111=H
%1110001000=I
%1110001001=J
%1110001010=&
%1110001011=L
%1110001100=V
%1110001101=N
%1110001110=O
%1110001111=[item]
%1110010000=[ -59]
%1110010001=[(s)]
%1110010010=S
%1110010011=;
%1110010100=U
%1110010101=”
%1110010110= the
%1110010111=C
%1110011000=Y
%1110011001=Z
%1110011010=x
%1110011011=[wait][line]‘
%1110011100=z
%1110011101=[item-F9]
%1110011110=‟
%1110011111=K

# C1 table
%1110100000=v
%1110100001=q
%1110100010= th
%1110100011=R
%1110100100=.
%1110100101=[..].
%1110100110=P
%1110100111=b
%1110101000=T
%1110101001=[line]
%1110101010=[sun]
%1110101011=[star]
%1110101100=[moon]
%1110101101=W
%1110101110=k
%1110101111=j
%1110110000=?
%1110110001=[.’]
%1110110010=[cardinal #]
%1110110011= of
%1110110100=:
%1110110101='
%1110110110=-
%1110110111=’
%1110111000=[spell]
%1110111001=[monster(s)]
%1110111010=[no voice]
%1110111011=[wait]
%1110111100=M
%1110111101=[name]
%1110111110=[number]
%1110111111=[FD]

# C2 table
%1111000000= to
%1111000001= and
%1111000010= be
%1111000011=, friend
%1111000100=ve
%1111000101= I
%1111000110=is
%1111000111=ou
%1111001000=!’
%1111001001=The
%1111001010=Prince
%1111001011= with
%1111001100=ing
%1111001101=[..].’
%1111001110= shall
%1111001111= in
%1111010000=ight
%1111010001=Goddess
%1111010010= for
%1111010011= not
%1111010100=Erdrick
%1111010101=Hargon
%1111010110= b
%1111010111=Moonbrooke
%1111011000=her
%1111011001= from
%1111011010=at
%1111011011=place
%1111011100=ould
%1111011101=Midenhall
%1111011110= wanderer
%1111011111= a

# C3 table
%1111100000= me
%1111100001= [ ’]T
%1111100010=our
%1111100011= upon
%1111100100=come
%1111100101=ke
%1111100110=st
%1111100111= unto
%1111101000=But
%1111101001=.
%1111101010=humble
%1111101011=Th
%1111101100=ine
%1111101101=eth
%1111101110=[name]
%1111101111=ell
%1111110000=and
%1111110001='s
%1111110010= my
%1111110011= of
%1111110100=ear
%1111110101=know
%1111110110=ast
%1111110111= wh
%1111111000=est
%1111111001=Alas,
%1111111010=sure
%1111111011= such
%1111111100=ough
%1111111101=one
%1111111110= possess
%1111111111= hath
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 08, 2020, 12:06:42 am
!
This is untested, but I think it should save you over 1500 ($600) bytes compared to your current dictionary:
Spoiler:
Code: [Select]
/%00000=[end-FC]\n\n
/%00001=.[end-FC]\n\n
/%00010=?’[FD][FD][end-FC]\n\n
/%00011=[.’][end-FC]\n\n
# 00100 is an intermediate end token, used to subdivide larger strings where the same function needs to be called multiple times with different values.
# E.g. in
# [name] [end-FF]threw away [name]'s [item] and gave [end-FF]the [item] to ghost of [name].[end-FC]
# the first [name] is the Prince of Midenhall's name, but the second and third [name] are the name of the dead party member whose items you are ransacking;
# similarly, the first [item] is the item you lose, but the second [item] is the item you gain.
/%00100=[end-FF]\n\n
%00101=
%00110=e
%00111=t
%01000=o
%01001=a
%01010=h
%01011=s
%01100=n
%01101=r
%01110=i
%01111=l
%10000=d
%10001=u
%10010=f
%10011=m
%10100=c
%10101=y
%10110=g
%10111=w
%11000=p
%11001=,
%11010=‘
%11011=!
%11100=[switch to C0 table]
%11101=[switch to C1 table]
%11110=[switch to C2 table]
%11111=[switch to C3 table]

# C0 table
%1110000000=A
%1110000001=B
%1110000010=[ ’]
%1110000011=D
%1110000100=E
%1110000101=F
%1110000110=G
%1110000111=H
%1110001000=I
%1110001001=J
%1110001010=&
%1110001011=L
%1110001100=V
%1110001101=N
%1110001110=O
%1110001111=[item]
%1110010000=[ -59]
%1110010001=[(s)]
%1110010010=S
%1110010011=;
%1110010100=U
%1110010101=”
%1110010110= the
%1110010111=C
%1110011000=Y
%1110011001=Z
%1110011010=x
%1110011011=[wait][line]‘
%1110011100=z
%1110011101=[item-F9]
%1110011110=‟
%1110011111=K

# C1 table
%1110100000=v
%1110100001=q
%1110100010= th
%1110100011=R
%1110100100=.
%1110100101=[..].
%1110100110=P
%1110100111=b
%1110101000=T
%1110101001=[line]
%1110101010=[sun]
%1110101011=[star]
%1110101100=[moon]
%1110101101=W
%1110101110=k
%1110101111=j
%1110110000=?
%1110110001=[.’]
%1110110010=[cardinal #]
%1110110011= of
%1110110100=:
%1110110101='
%1110110110=-
%1110110111=’
%1110111000=[spell]
%1110111001=[monster(s)]
%1110111010=[no voice]
%1110111011=[wait]
%1110111100=M
%1110111101=[name]
%1110111110=[number]
%1110111111=[FD]

# C2 table
%1111000000= to
%1111000001= and
%1111000010= be
%1111000011=, friend
%1111000100=ve
%1111000101= I
%1111000110=is
%1111000111=ou
%1111001000=!’
%1111001001=The
%1111001010=Prince
%1111001011= with
%1111001100=ing
%1111001101=[..].’
%1111001110= shall
%1111001111= in
%1111010000=ight
%1111010001=Goddess
%1111010010= for
%1111010011= not
%1111010100=Erdrick
%1111010101=Hargon
%1111010110= b
%1111010111=Moonbrooke
%1111011000=her
%1111011001= from
%1111011010=at
%1111011011=place
%1111011100=ould
%1111011101=Midenhall
%1111011110= wanderer
%1111011111= a

# C3 table
%1111100000= me
%1111100001= [ ’]T
%1111100010=our
%1111100011= upon
%1111100100=come
%1111100101=ke
%1111100110=st
%1111100111= unto
%1111101000=But
%1111101001=.
%1111101010=humble
%1111101011=Th
%1111101100=ine
%1111101101=eth
%1111101110=[name]
%1111101111=ell
%1111110000=and
%1111110001='s
%1111110010= my
%1111110011= of
%1111110100=ear
%1111110101=know
%1111110110=ast
%1111110111= wh
%1111111000=est
%1111111001=Alas,
%1111111010=sure
%1111111011= such
%1111111100=ough
%1111111101=one
%1111111110= possess
%1111111111= hath

Well that's nice abw, but I don't think it could free up that mu-
(https://i.imgur.com/F3ZQq2B.png)

(https://media.giphy.com/media/zIwIWQx12YNEI/giphy.gif)

Okay how did you do that?  :o Seriously! I mean I know some of those changes are from putting the more used stuff on top and the lesser used stuff on bottom. I tried that a little bit but usually ended up breaking things somehow so I didn't stray too far from the original. But I mean did you run my atlas.txt through something? Entries like " b" make me raise an eyebrow and I don't even need the semicolon. I do have to wonder how that special #59 space works. I presume you added it so that the game can add spaces without changing C tables but does abcde really pick on that when it's called [ -59]?

That [FF] is also an end token, so your numbers for 4A-4F are all off by one. There are a few other FF end tokens scattered throughout the script, so keep those in mind when counting strings.

Ahhh okay that makes a lot of sense actually.

Quote
I haven't gone through all the related code, so I could be wrong, but I don't think you can trigger this message, and my CDL file shows that I never did over the course of an entire playthrough. I suspect it was intended for use in some alternate reality where your casters didn't both start already knowing some in-battle spell, or possibly a leftover from Dragon Warrior, where you actually don't learn your first spell until after a few levels.

Okay, I'd probably remove it if I didn't have so much space now. There's another line I had erased. The third Pointer 21 line "[ ‘]Follow me and do not make a peep[.’][end]" which I presume is another unused line maybe having to do with those cut items and no problems so far.

Quote
Hmm, yeah, disabling the BNE at $04:$98BC should result in string #$008B always being used for gold from battle. Give it a try!

Thanks, simply NOPing it didn't work I had to write a new routine and run it through asar

Code: [Select]
; Put this file in the same directory as asar and execute it with e.g.
;   asar -nocheck goldfix.asm targetrom.nes
; This fixes the DW2 ROM so that it uses the same post battle Gold Obtained message when an enemy drops an item instead of switching over to the gold found in treasure chest message 

norom ; stop Asar from trying to apply SNES memory mapping to this NES code
org $0118C9 ; set the ROM file insertion point
base $98B9 ; set the starting RAM address

    LDA $61B0  ; flag for whether you get an item drop or not
BNE gold  ; changes branch to always use Line 8B

gold:
    LDA #$8B    ; String ID #$008B: [no voice]and earned [number] piece[(s)] of gold.[end-FC]
JSR $9CEA  ; set return bank $94 to #$04
JSR $FA4A  ; display string ID specified by A
JMP $98CE

But it worked!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 08, 2020, 07:37:50 pm
Okay how did you do that?  :o Seriously!
Magic, clearly :P.

I mean I know some of those changes are from putting the more used stuff on top and the lesser used stuff on bottom. I tried that a little bit but usually ended up breaking things somehow so I didn't stray too far from the original. But I mean did you run my atlas.txt through something?
Basically, my process was:You could probably get similar results with ScriptCrunch if you convert your text and table file to be 1 byte = 1 character to prevent ScriptCrunch from spitting out things like "wait][end". The general idea there is to run a greedy algorithm for tokenizing the text, picking the string that will save the most space, adding it to the table file, and repeating until the table is full. That greedy algorithm is not guaranteed to produce optimal results, but it does tend to produce useful results without needing to run for a ridiculously long time, so... good enough!.

Entries like " b" make me raise an eyebrow and I don't even need the semicolon.
Ha, yeah, I should add a check for unused table entries. 1500+ free bytes should keep you going for a while, but if it starts getting tight again you could definitely kick out the semi-colon for a new table entry.

I do have to wonder how that special #59 space works. I presume you added it so that the game can add spaces without changing C tables but does abcde really pick on that when it's called [ -59]?
Me too - that's not something that appears in the original script, so I assumed that you had added it for some reason :P.

There's another line I had erased. The third Pointer 21 line "[ ‘]Follow me and do not make a peep[.’][end]" which I presume is another unused line maybe having to do with those cut items and no problems so far.
Checking the disassembly, it's used by the old man/wizard NPC on the 7th floor of the lighthouse; I think I remember testing that one out in-game, and in order to trigger it, you have to be pretty quick to TALK to him before he makes it to the stairs.

Thanks, simply NOPing it didn't work I had to write a new routine and run it through asar
Are you sure you NOP'd out the right bytes? Your ASM patch boils down to changing BNE +11 to BNE +0, which has the same effect as NOP NOP. Or, to put it another way, the logic is now "if $61B0 is not 0, go to gold, otherwise go to gold", i.e. "go to gold", which is still the same thing as NOP-ing out the BNE.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 09, 2020, 09:41:18 am
A couple things:

All this talking of NOP'ing out bytes. I assume that is assembler speak, which I have yet to have to engage in (I'm sure it's coming soon). But in case I need to NOP something, is that the equivalent of just replacing with FF or 00 or something like that in hex?

As for a more relevant matter, I finished my DQ2 script revision, which turned out to be an enormous amount of revision. While nejimakipiyo does their sweep, it's time for me to work on inserting the DQ3 script, and I have a couple questions.

When I set up the parameters that tells me how many bytes remain in each data bank, if I run over, is abcde going to tell me by how many bytes I ran over? Or is it just going to give me a fail? I'd love to know how much I'm running over so I can choose between finding some opportunities for space efficiency or looking at your compression scheme. Also, what actually happens when I run over? This would be new to me. Does it fill data up until the cut off point? Or does it have data run into the next section? Or does it simply not do a write at all? I could definitely experiment with this myself, but I'm at work right now and the curiosity is killing me. :P
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on June 09, 2020, 11:44:11 am
NOP (EA opcode) is an instruction that does nothing except wasting cpu cycles during its execution. It is used for deleting (temporary or permanently) other instructions by overwriting their length with EAs.

You can't overwrite them with 00 or FF, because 00 is an opcode for BRK instruction that causes an interrupt, and there is no such opcode as FF, you can freeze your code execution with it.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 09, 2020, 11:46:59 am
Perfect. So if I can manage to track down the DQ3 code that is applying a 125% gold and experience multiplier to monster rewards, I just EA through it.  :thumbsup:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on June 09, 2020, 12:01:46 pm
Basically yes, however you need to understand what a routine is doing exactly before start hastily deleting its instructions
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 09, 2020, 09:36:35 pm
Cyneprepou4uk's covered NOPs pretty well already, so I'll just reply to this part:

When I set up the parameters that tells me how many bytes remain in each data bank, if I run over, is abcde going to tell me by how many bytes I ran over? Or is it just going to give me a fail? I'd love to know how much I'm running over so I can choose between finding some opportunities for space efficiency or looking at your compression scheme. Also, what actually happens when I run over? This would be new to me. Does it fill data up until the cut off point? Or does it have data run into the next section? Or does it simply not do a write at all? I could definitely experiment with this myself, but I'm at work right now and the curiosity is killing me. :P
Is you set an upper limit on the insert address with #JMP(Address, MaxAddress), then yes, (recent versions of) abcde will tell you how many bytes you have to spare if your script fit into the available space or how many bytes didn't fit otherwise. If your script doesn't fit, then any data up to MaxAddress will still get inserted, but data beyond that won't be overwritten.

For DW3, if you can fit the same number of strings in each bank as the original text used, then great. There is a little bit of free space at the end of each of the first 5 banks of text, but not much, so it could be a tight fit. There is plenty of free space at the end of the 6th bank, but in order to use it you'll need to shift strings from one bank to the next and update the code for determining which bank holds each string; that code starts at $0E:$AE8F and is kind of messy. If finding and updating the right values in the original code doesn't appeal to you, you can apply the patch I made to rewrite that code which has a little table at the bottom of the ASM file for setting up the string/pointer/bank mapping that should be easy to edit; as a reminder, though, I haven't really tested that patch much, so it's possible there could be some mistakes.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 09, 2020, 11:25:35 pm
f finding and updating the right values in the original code doesn't appeal to you, you can apply the patch I made to rewrite that code which has a little table at the bottom of the ASM file for setting up the string/pointer/bank mapping that should be easy to edit; as a reminder, though, I haven't really tested that patch much, so it's possible there could be some mistakes.
I'll give your script code rewrite patch a try if (when) I determine that our script doesn't fit. I assume that this will require me to get moving with using one of assemblers we spoke about.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 14, 2020, 12:41:59 pm
So I dipped my toes into DW3 yesterday. Found myself replacing the Gadabout/Goof Off dialog first. The differences between versions are HUGE

NES:
Code: [Select]
[name] suddenly starts to flee.[end-EE]

[name] catches a whiff of the socks.[end-EE]

[name] begins to mimic the arms shopkeeper:[line]
[*']This store deals in weapons and armor[..][.'][end-EE]

[name] casts the spell, Explodet.[end-EE]

[name] speaks ill of [name][letter].[end-EE]

[name][letter] becomes enraged.[end-EE]

[name][letter] is not listening.[end-EE]

[name] is honing his body to be ready for anything.[end-EE]

[name] starts doing Jazzercise![end-EE]

[name] suddenly becomes enlightened.[end-EE]
// current address: $41A91

//POINTER #14 @ $2809C - STRING #14 @ $41A91
#W16($2809C)
[name] points [his/her] finger at [name][letter] and guffaws.[end-EE]

[name] gets tangled up in his own legs and falls down.[end-EE]

[name] pokes at the dead monster.[end-EE]

[name] remarks smugly:[line]
[*']I wouldn't fight if I were you. Even a victory would be hollow[.'][end-EE]

[name] is confused for some reason.[end-EE]

[name] lies down for a nap.[end-EE]

[name] spruces [himself/herself] up.[end-EE]

[name] is lost in thought.[end-EE]

[name] is taking a break.[end-EE]

[name] recoils![end-EE]

[name] cheers on [his/her] companions.[end-EE]

But [his/her] companions are not there.[end-EE]

But no one is listening.[end-EE]

[name] suddenly found [he/she] couldn't move a single muscle.[end-EE]

[name] beckons the heavens.[end-EE]

[name] breaks out in a smile.[end-EE]
// current address: $41C89

//POINTER #15 @ $2809E - STRING #15 @ $41C89
#W16($2809E)
[name] suddenly pinches [name].[end-EE]

[name] :[line]
[*']Hey!! What do you think you're doing?[' ][end-EE]

[name] blusters:[line]
[*']Do you realize who you are speaking to? Impertinent![' ][end-EE]

[name] gives a kind glance.[end-EE]

[name] pretends to be dead.[end-EE]

But fools no one![end-EE]

[name] soft soaps [name][letter].[end-EE]

[name] is chewing onion-flavored gum.[end-EE]

The strong smell is drifting everywhere.[end-EE]

[name] blows a kiss.[end-EE]

[name] suddenly turns around and rolls up a sleeve.[end-EE]

[ .][..]exposing a small tatoo![end-EE]

[name] is momentarily transfixed.[end-EE]

[name] sings a song.[end-EE]

[name] makes an awful pun.[end-EE]

[name] is momentarily transfixed.[end-EE]

Mobile/Switch

Code: [Select]
~<13<23<3A shuts out everything around <46him<47her<48it<64, and hunkers down to defend <46himself<47herself<48itself<64!<12<0F  ]<13<23<3A holds off on doing anything for now, and stands back to assess the situation.<12<0F  i<13<23<3A calls for backup!<12
But <46his<47her<48its<64 faithful playmates are nowhere to be seen!<12<0F  Y<13<23<3A suddenly makes a run for it!<12
But <46his<47her<48its<64 way is blocked!<12<0F  *<13<23<3A pretends to take a tumble!<12<0F  ?<46His<47Her<48Its<64 weapon catches <3B on the way down!<12<0F  M<46He<47She<48It<64 lands badly, and grazes <46his<47her<48its<64 knee!<12<0F  &<13<23<3A grins from ear to ear!<12<0F  B<13<23<3A suddenly falls flat on <46his<47her<48its<64 face!<12<0F  N<23<07: Zzz...
Would you believe it!?
<49He<4AShe<4BIt<64's fast asleep!<12<0F  C<13<23<3A picks up some stones and starts juggling with them!<12<0F  F<13<23<06: Whoopsy-daisy!
One of the stones lands on <3B's head!<12<0F  I<13<23<06: Whoopsy-daisy!
One of the stones lands on <3B's big toe!<12<0F  <<13<23<3A starts to sing and dance about like a loony!<12<0F  м13<23<3A blasts the enemy with a stinging verbal tirade!<12
<23<06: Ner-ner-na-ner-nerrr!
You smell! A-And you're rubbish!
...So THERE!<12
But <46his<47her<48its<64 words fail to ruffle any feathers...<12<0F  ><13<23<3A puts <46his<47her<48its<64 hair back in order!<12<0F  ׼13<23<3A taps <46his<47her<48its<64 feet to the rhythm of the battle!<12
Suddenly, ducking and swaying out of danger's way doesn't seem so hard!<12<0F  L<13<23<3A twirls <46his<47her<48its<64 fingers in front of <3B's face!<12<0F  5<14<23<3B's eyes start to spin round and round!<12<0F  0<14But <3B isn't fazed in the slightest...<12<0F  5<14<23<3B's eyes start to spin round and round!<12<0F  2<13<23<3A pinches <3B crudely on the behind.<12<0F  ;<23<07: Oi! What the heck do you think you're doing!?<12<0F  6<13<23<3A gets a well-deserved slap in the face.<12<0F  X<13<23<3A pulls out a mirror and starts touching up <46his<47her<48its<64 make-up.<12<0F  Ӽ13<23<3A hurls <46him<47her<48it<64self to the ground and starts bawling!<12
<23<06: Waaaah! (sob) Boo-hooo!
I'm s-so s-sad, I can't even mooove!<12
<46He<47She<48It<64's literally paralysed with sadness!<12<0F  5<13<23<3A tries making up an amazing new spell.<12<0F  <23<06: <05<1A  -<05!<12
But of course, nothing happens.<12<0F  ˼13<23<3A prays fervently to the heavens...<12
<23<06: O merciful Goddess, I beg of you—bring peace to our world!<12
...But this is neither the time nor the place.<12<0F 9<13<23<3A suddenly realises that maybe it's time to stop messing around and take life seriously.<12
<46He<47She<48It<64 gets the distinct feeling there was something very important <46he<47she<48it<64 was supposed to be doing...<12
And starts muttering away feverishly to <46himself<47herself<48itself<64...<12<0F  /<13<23<3A comes up with a hilarious joke!<12<0F  @<13<23<06: ...WHY THE LONG FACE!!!
Geddit? Hyuk hyuk hyuk!<12<0F  G<13Direct hit! <23<3B collapses on the floor in fits of laughter!<12<0F  6<13<23<3A is rolling on the floor with laughter!<12<0F  '<13<23<3A is distinctly unamused.<12<0F  D<13<23<06: ...NO, I'M A FRAYED KNOT!!!
Woohoohoooo! Boom boom!<12<0F  6<13<23<06: ...A STICK!!!
Woohoohoooo! Boom boom!<12<0F  A<13<23<06: ...HE KNEADED A POO!!!
Yuk yuk yuk! Classic, eh?<12<0F  C<13<23<06: ...NO-EYED DEER!!!
Har har! ‘No idea’! Geddit?<12<0F  T<13<23<06: ...BECAUSE HE WAS A LITTLE HORSE!!!
You know—horse, hoarse... No?<12<0F     @<13<23<06: ...BECAUSE THE SEA WEED!!!
Wacka wacka! Hooonk!<12<0F  x<13<23<06: ...NOTHING, IT JUST LET OUT A LITTLE WINE!!! You know... Grapes...wine...? Yeah!
Hur de hur de hur hur!<12<0F  ;<13<23<3A slowly and deliberately rolls a large dice.<12<0F  /It lands on a <03...
And nothing happens.<12<0F  &<13<23<3A starts singing loudly.<12<0F  :The haunting melody drifts across the battlefield...<12<0F  )<15<23<3B is completely captivated!<12<0F  )<13<23<3A is completely captivated!<12<0F  (<15But <3B isn't really listening.<12<0F  4It sounds like cats screeching in an alleyway!<12<0F  _<15<23<3B runs off as fast as <49his<4Aher<4Bits<64 legs will carry <49him<4Aher<4Bit<64!<12<0F  I<15But luckily for <3B, <49he<4Ashe<4Bit<64 isn't really listening.<12<0F  ;<13<23<3A is suddenly distracted by a smutty thought.<12<0F  D<23<06: Hur hur hur...<12
<46He<47She<48It<64 chuckles lewdly.<12<0F  G<23<06: Hyeh hyeh hyeh...<12
<46He<47She<48It<64 chuckles lewdly.<12<0F  E<13<23<06: Ahhhhhh-CHOO!!!<12
<23<3A lets out a massive sneeze!<12<0F  F<14<23<3B jumps out of <49his<4Aher<4Bits<64 skin with surprise!<12<0F  F<13<23<3A jumps out of <46his<47her<48its<64 skin with surprise!<12<0F  )<15But <3B doesn't take any notice.<12<0F  D<23<06: Ahhhhhh-TISHOO!!!<12
<23<3A lets out a massive sneeze!<12<0F  5<13<3A starts an impromptu game of ‘I Spy’.<12<0F  <23<06: I spy with my little eye, something beginning wiiith...<05! No, wait! I-I meant to say— Ach!<12
<46He<47She<48It<64 makes a complete mess of it!<12<0F  "<13<23<3A makes eyes at <3B!<12<0F  /<23<3B gets all flustered and looks away!<12<0F  5<13<23<3A looks at the ground in embarrassment!<12<0F  &But <3B doesn't take any notice.<12<0F  ˼13<3A starts telling a spooky story...<12
<23<06: It was a dark and stormy night...<12
<13That was enough to give anyone the creeps!<12<0F  <23<3B gets goosebumps!<12<0F  )<13<23<3A is shivering with fright!<12<0F  But nobody's listening.<12<0F  ڼ13<23<3A pulls a crown from somewhere and puts it on!<12
<13<23<06: Verily, I am the king of thee! HA HA HA! Kneel before me!<12
<13<46He<47She<48It<64 beckons imperiously to <3B!<12<0F  Ҽ13<23<3B shuffles nervously up to <3A and bows low!<12
<13<3A spots <46his<47her<48its<64 chance, and biffs <3B on the back of the head!<12<13<0F  )But <3B clearly isn't a monarchist!<12<0F  μ13<23<3A puts on a crown, whips out a sceptre, and adopts a thoroughly queenly air!<12
<13<23<06: Yea, I am thy queen!
HA HA HA! Kneel before me!<12
<13<46He<47She<48It<64 beckons imperiously to <3B!<12<0F  ˼13<23<3B shuffles nervously up to <3A and bows low!<12
<13<23<3A spots <46his<47her<48its<64 chance, and stamps on <3B's big toe!<12<13<0F  )But <3B clearly isn't a monarchist!<12<0F  ļ13<23<3A sneaks up behind <3B and puts <46his<47her<48its<64 hands over <49his<4Aher<4Bits<64 eyes!
<23<06: Guess whooo!<12
<13<23<07: Um...<06?<12
Oh no! <49He<4AShe<4BIt<64 got it in one!<12<0F  -<13<23<3A suddenly bursts out laughing!<12<0F  ;<13<23<06: Hohohohohoho! Hahahahahaha! HEE HEE HEE!!!<12<0F  /<13<23<3B gets weirded out and runs away!<12<0F  9<13<23<06: Wahahahaha! Woohoohoohoo! HAR HAR HAR!!!<12<0F  r<13<23<3A gives the party some stirring words of encouragement!<12
<23<06: Come on, you lot! We can do this!<12<0F  5<13<23<3A's words get the party totally pumped!<12<0F  2<13<23<3A's words totally bum everybody out!<12<0F  !Sadly, nobody is listening.<12<0F  Ӽ13<23<3A pulls out a drink <46he<47she<48it<64 has stashed up <46his<47her<48its<64 sleeve, and downs it in one!<12
<23<06: (glug glug glug) Ahhh!!!
That hit the spot! Hic!<12<0F  μ13<23<06: What'sh your—Hic!—problem, eh?
Reckon you're shpecial, do you? (burp)
Think you're—Hic!—better than me?<12
<23<3A starts haranguing <3B incoherently!<12<0F  '<13<23<3A is busy haranguing <3B.<12<0F  :<13<23<3A is busy trying to fend off a slurring <3B.<12<0F  G<13<23<06: Hic! Bleeeurgh!
<23<3A is feeling a little...poorly...<12<0F  "<13<23<3A is feeling poorly.<12<0F  R<13<23<3A points at <3B and starts bad-mouthing <49him<4Aher<4Bit<64 loudly!<12<0F  S<23<06: Yeah, yeah... That one...
Looks like a right wimp, eh?
Heh! Pathetic!<12<0F  $<14<23<3B gets really annoyed!<12<0F  $<14<23<3B gets really upset...<12<0F  )<14<23<3B wasn't taking any notice.<12<0F  Ҽ13<23<3A summons up all <46his<47her<48its<64 strength, and hurls a huge boulder straight up in the air!<12
The boulder comes hurtling down...<0F  -<13...And lands squarely on <3B's head!<12<0F  ,...And lands harmlessly on the ground.<12<0F  E<13<23<3A performs <46his<47her<48its<64 best puff-puff on <3B!<12<0F  #<23<06: (puff-puff puff-puff)<12<0F  But <3B isn't impressed!<12<0F  ;<23<3B has a huge grin on <49his<4Aher<4Bits<64 face!<12<0F  <13<23<3A is mesmerised!<12<0F  -But <3B manages to resist <3A's charms!<12<0F  V<13<23<3A tries out a special move <46he<47she<48it<64's just thought up on <3B!<12<0F  7<13<23<06: You shall be the first to feel my...
<05 <1A  <05 <1A  B<05!!!<12
...But it looks suspiciously like a normal attack.<12<0F  ^<13<23<3A starts doing something very naughty!<12
<13Everybody pretends not to notice...<12<0F  ɼ13<23<3A pulls a scrap of paper out of <46his<47her<48its<64 pocket and sets fire to it for fun!<12
<13<23<06: Owowowow!
<46He<47She<48It<64 throws the burning piece of paper in <3B's direction!<12<0F  Ӽ13<23<3A starts trying to think of fun games to play with <46his<47her<48its<64 friends.<12
...But <46he<47she<48it<64 soon remembers that the battlefield is no playground.<12<0F  ݼ13The sight of <46his<47her<48its<64 friends fighting alongside <46him<47her<48it<64 warms <3A's heart!<12
<13The warmth spreads throughout the party!<12<0F  1<14<23<3B's wounds are miraculously healed!<12<0F

Speaking of space though, am I right in that a line has to start with the quote in order to have the "speaking" sound effect? Because when I look at the format at a lot of the dialog is like this

[name] :[line]
[ ']It doesn't look especially cursed[.']

And I just think how you could save a lot of space by doing this ala more modern DQ games

[name]: It doesn't look especially cursed.

You could even edit the colon tile to be on the left side so that you wouldn't have to even use a space after.

June 14, 2020, 03:48:30 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Yep, just found with DW2, text definitely has to start with the single quote to do the sound effect, and you can definitely go back and forth between text and silence (I think that's what [wait] is for), but the space after [name] in a lot of the dialogs is still unnecessary and can definitely free up space.

EDIT: Oh wait, you don't even need a [line], it'll start right after the ` starts.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 15, 2020, 07:50:58 am
@Choppasmith

I've also found that their approach to dialogue with named speakers can be a little more space efficient.

@abw (or Choppasmith if you want to take a stab)

I have an issue making me crazy which relates to the insert script I had just set up for DQ3. The script part "seems" to be working fine (without having actually inserted our changes) and I also included the lists for spells/items/monsters. The latter list section also seemed to be working fine until I incorporated our new spell names, which increased the size of the spell list by about 30 characters. Everything seems good until the spell "Probasu" (formerly called X-Ray). The insert script has Probasu[$FF], but after running the insertion, the rom ends up with an $AD byte in the location where $FF is supposed to be written. For the life of me, I can't understand why this is happening. I could simply change 0x00AD12 to $FF (which I've done) but I end up with the end of the spell list screwed up regardless. The spell list only has one pointer, so I don't believe that could be the issue. Curiously, the spell list is getting borked only a couple bytes after where it ended in the original rom. In the past, I manually inserted the romaji Japanese spell list I was using previously (which I believe was larger than both of these lists) and it seemed fine. There are other problems with the item names, which could very well be due to a manual error, but for the life of me, I can't figure out this spell list issue, and would be very grateful if you could take a look.

Here is the insert script and the two table files I use (one for script, one for lists) https://www.dropbox.com/sh/20kwx353wplbcv4/AADvP7VMwqumHZhlwonKv928a?dl=0 (https://www.dropbox.com/sh/20kwx353wplbcv4/AADvP7VMwqumHZhlwonKv928a?dl=0)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 15, 2020, 09:07:28 am
Well, just really quick you could force it by doing

Code: [Select]
Probasu<$FF>
The only thing I can think of is I'm looking at your table and I'm not sure why you need the $ sign for A2 and FF but I don't know why that would affect anything.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 15, 2020, 09:11:20 am
Everything seems good until the spell "Probasu" (formerly called X-Ray). The insert script has Probasu[$FF], but after running the insertion, the rom ends up with an $AD byte in the location where $FF is supposed to be written. For the life of me, I can't understand why this is happening.
This
Quote
#W16($AD11)
is the culprit - the pointer write is clobbering your previously-inserted text. It's just pure luck that the low byte of the pointer happens to have the same value as the text you want ($AD1F vs. 1F=u) and happens to align with the previously-written [$FF]. I think you meant to say #W16($AA1E) instead!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 15, 2020, 11:04:07 am
Went home for lunch and tested the pointer address change. Yep! That was it. First time I've screwed up a #W16 address, so now I know it can do this kind of thing. I honestly should have suspected my address was wrong based on how far off that address was from the others.

Thanks a million, as always!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 15, 2020, 07:50:57 pm
First time I've screwed up a #W16 address, so now I know it can do this kind of thing.
Heh, there's a first time for everything, isn't there? ;) Getting everything to line up like that was pretty special, though!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 17, 2020, 02:27:00 pm
Hey abw, I wanted to try something you suggested to Chicken Knife, unique Dragonlord text, a while back and wanted to make sure I got it right.

A few minutes with a debugger says that the "A Dragonlord draws near!" text (the 0xE2'th string) comes from the 0xE2 following $03:$E595, so if you wanted different text for the Dragonlord, you'd need to change 0xE2 to whatever string you wanted to use instead. It looks like the current enemy ID is stored in RAM at $E0, so something like this should do the trick:
Code: [Select]
; $03:$E595
JSR choose_text
NOP

; free space somewhere else
choose_text:
LDA $E0
CMP #$26 ; enemy ID for Dragonlord's first form
BEQ @use_awesome_text
; otherwise use the normal text
JSR $C7CB
.byte E2 ; normal string ID
RTS
@use_awesome_text:
JSR $C7CB
.byte ?? ; whatever free string ID you want to use for your new text
RTS

I found some space for this routine at ROM 7F40, this would be RAM $3F50 and space for the string 9B, the unused 7th string in Pointer 8024. Does that sound about right?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 17, 2020, 07:29:25 pm
What happened when you tried it?

I'm assuming by $3F50 you meant $BF50 and by 9B you meant 96, but I think you'll find that ROM bank 1 is not swapped in to RAM at the point when $03:$E595 gets executed, so if you want to call code in ROM bank 1, you'll first need to add some code to swap that bank in and then swap the previous bank back when you're done. If you haven't already used them, there appear to be a few long stretches of unused $FF bytes in bank 3, so those would be the easiest places to reach since they're guaranteed to be visible.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 18, 2020, 09:15:56 am
I'm intrigued to hear how this goes. I hope to revisit at some point soon. My brain is so deeply in script editing right now, I'm not really capable of shifting gears smoothly into figuring out a whole new hacking method (assembler). But as soon as I get the DQ3 script inserted, the focus will be on hacking issues between this and DQ3.

Ah, and going back a previous comment, Choppasmith mentioned above how inefficient the script format was at times in DQ3. Stuff like:

[line][wait]
(space x3)[line]
blah blah blah blah blah balh
[line](space x3)[end]

This isn't exact, but close enough to illustrate. There are a number of these scenarios, but one example is with the early line "...and the day breaks" or something like that.

For the life of me, I can't understand why they would add all those extra spaces when they could just be [line] bytes. Usually things they did have a reason, but I'm here scratching my head. So far, I'm removing all of that.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on June 19, 2020, 12:30:34 am
What happened when you tried it?

I'm assuming by $3F50 you meant $BF50 and by 9B you meant 96, but I think you'll find that ROM bank 1 is not swapped in to RAM at the point when $03:$E595 gets executed, so if you want to call code in ROM bank 1, you'll first need to add some code to swap that bank in and then swap the previous bank back when you're done. If you haven't already used them, there appear to be a few long stretches of unused $FF bytes in bank 3, so those would be the easiest places to reach since they're guaranteed to be visible.

Have to admit, I was working this out while I was on hold over the phone and didn't get a chance to try it. I figured something was off and felt better asking, sorry. Mostly because I wanted to convert my new script over to abcde (I still had everything setup for Pointer Tables complete with manual pointer editing and I just couldn't go back to that :D) before making any more changes.

So I successfully managed to convert everything in my DW1 work over (even the Menu stuff in the DW2 example files works great and just needed a couple tweaks)

But I had a couple of abcde questions

When editing table files what does placing / before the value (usually an End Token supposed to do? I get that putting /n means the output file will make a new line (or two in the case of a proper end string token) Nevermind found the explanation in the documentation.

When doing the DW1 menu stuff, it ends at x752C however when I put #SCRIPT STOP: $752C it'll stop one byte short and my output will say #JMP($6FC0, $752B) is this intentional?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 19, 2020, 09:47:58 am
Have to admit, I was working this out while I was on hold over the phone and didn't get a chance to try it. I figured something was off and felt better asking, sorry.
No worries. I haven't tried it myself either, but it should be fairly easy as ASM changes go. I provided a general plan for the change, but I'll leave the details up to whoever actually wants to implement it :P.

(I still had everything setup for Pointer Tables complete with manual pointer editing and I just couldn't go back to that :D)
Not having to manually edit pointers is a thing of beauty indeed :D.

When doing the DW1 menu stuff, it ends at x752C however when I put #SCRIPT STOP: $752C it'll stop one byte short and my output will say #JMP($6FC0, $752B) is this intentional?
The way Cartographer works (which is not at all clear from its documentation) is that the #SCRIPT STOP address is exclusive, i.e. "extract up to but not including this address".

On the other hand, the upper limit on Atlas' #JMP command is inclusive, i.e. "insert up and including this address".

I kept both of those behaviours for abcde for the sake of backwards compatibility, but that does conflict with the goal of having a consistent interface. I'll probably end up converting abcde::Cartographer to work inclusively to match Atlas since it's much easier for people to change their extract scripts than their insert scripts.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 23, 2020, 11:11:19 am
As I am now approaching the half-way point in the process of inputting new text into DQ3, I wanted to toss out a few things to you guys that I'm thinking about beyond just the text. I have a feeling Choppasmith may want some of these fixes / improvements as well for RE-QUEST. I'm planning on working on all of these, but if anyone wants to jump in, I would be more than grateful.

NECESSARY FOR RELEASE:

TITLE SCREEN:
I believe we have to fix the nametable arrangement for the title screen because it duplicates certain letters for the Dragon Quest logo, similar to how DQ1 did. I'm also thinking about moving the III up to the upper right, filling out the space based on shrinking WARRIOR to QUEST like how I did in II. And where the III is now, I would probably write the subtitle. Would need to think about ideal font for the subtitle, and I'm definitely open to any other ideas for the title screen.

RESTORED DIFFICULTY:
Perhaps this is a little less necessary, but for me it's huge. I need to be able to locate and NOP out the code that gives the 25% bonus gold/xp added for the US version. I'll include an optional patch to revert for the grind haters, but this feels like a pretty essential part of my concept of removing localization. It should also result in the game feeling more part of a whole with the first two.

NAME RESTRICTION:
Right now the game prevents you from naming a new recruit Erdrick. I need to change that to Roto. I was a little confused when I couldn't simply find Erdrick somewhere in the rom as the disallowed name. I have some ideas on how I might find it though. Worst case scenario, I include a corny jab at the Erdrick name being not up to snuff. But I'd much rather keep things professional and include the translated text based on choosing Roto.

IMPORTANT, NOT NECESSARY FOR RELEASE

PARRY BUG:
Want to fix the bug where you can parry, then cancel, but keep the defensive bonus from the parry. Zombero included this in his hardtype patch. I reached out some time ago to ask if he could give us the code or make it available as a separate patch. I didn't get a reply, sadly. I surfed around looking for other contact details for him and couldn't find any. We may have to reinvent the wheel with this.

CROSSES / BUDDHIST SYMBOL:
Need to restore the 2 large floor crosses and a buddhist symbol that were censored in the US release. I made an attempt to do this when I was fixing the Priest / Coffin sprites but didn't get anywhere. Willing to tape another stab later but *gulp* it was scary.

Let me know guys if there's anything else that feels like it needs updating.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on June 23, 2020, 06:35:02 pm
NAME RESTRICTION:
This one is pretty easy to track down - if you watch RAM with a table file open while entering "Erdrick", you'll see the name being stored starting at $0009; from there, a read breakpoint will (after a few other hits) get you to the code for comparing the entered name against "Erdrick"... case insensitively ;).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on June 23, 2020, 11:56:39 pm
This one is pretty easy to track down - if you watch RAM with a table file open while entering "Erdrick", you'll see the name being stored starting at $0009; from there, a read breakpoint will (after a few other hits) get you to the code for comparing the entered name against "Erdrick"... case insensitively ;).
To your credit, this is probably a very nice, simple learning exercise in using breakpoints / trace logger. I'm going to attempt it soon. Let's hope the effort goes better than last time when I had to send you a video of my ineptitude.

One cool thing that happened tonight: I figured out how to swap out the relatively unnecessary himself/herself gendered opcode for a king/queen one. Now a female hero can become a queen when you return the golden crown instead of becoming... a king.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 06, 2020, 10:12:02 pm
Ok, looks like that whole idea of creating the king/queen gendered opcode was a massive waste of effort. First of all, when you return the Golden Crown and become the new king of Romalia/Romaly, even if your hero character was female, the game now has the character coded as male. But I wasn't thinking straight regardless, because even if the character kept their gender through this event, having the sprite show up as the male king with the big ol' mustache, you would still have this dissonance when the character is addressed as queen. I'm sure it would take a nice chunk of new ASM code to have the game check your gender, and, if female, create the royal character with the queen/princess sprite and appropriate gender indicator.

I do think that this would be a really cool and worthwhile validation for female hero players. Hopefully, I'll be able to revisit the idea one day when my hacking skills have improved.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on July 06, 2020, 10:28:50 pm
Ok, looks like that whole idea of creating the king/queen gendered opcode was a massive waste of effort. First of all, when you return the Golden Crown and become the new king of Romalia/Romaly, even if your hero character was female, the game now has the character coded as male. But I wasn't thinking straight regardless, because even if the character kept their gender through this event, having the sprite show up as the male king with the big ol' mustache--yet being addressed as queen--would have created a lot of cognitive dissonance. Obviously, it would take new ASM code to have the game check your gender and, if female, create the royal character with the queen/princess sprite and appropriate gender indicator.

I do think that this would be a really cool and worthwhile validation for female hero players. Hopefully, I'll be able to revisit the idea one day when my hacking skills have improved.

See, my issue is the remake script features a quite a hefty amount of unique dialog that the opcodes just won't cover, so I think I am  going to make two patches/scripts. One being a Default Male/Female option and the other being a Default Female/Non-binary Option. Since the Data Crystal has the sprite pointers, those should be easy to swap and I like people having options!  :laugh:

Since I know that's a thing now, I'm all the more inspired to do that!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 07, 2020, 06:18:52 am
See, my issue is the remake script features a quite a hefty amount of unique dialog that the opcodes just won't cover, so I think I am  going to make two patches/scripts. One being a Default Male/Female option and the other being a Default Female/Non-binary Option. Since the Data Crystal has the sprite pointers, those should be easy to swap and I like people having options!  :laugh:

Since I know that's a thing now, I'm all the more inspired to do that!
Hmmm, interesting idea to split into two versions. I don't think that would be suitable for my project, but it sounds like a good potential solution for yours. As you know, I've done some work with sprite pointers in this game. Do you think DQ3 has distinct entries in the sprite pointer table for the playable king versus the generic NPC king? If that's the case, your idea would be cool.

As for my way of handling this, in the end, I reverted back my [king/queen] changes, and I introduced a conservative improvement to the text. I don't like to add unique elements to the script unless they address a clear deficiency of the game. A previous example was having the puff puff girl in DQ2 hint to come back without the princess.

The straight translation here of saying yes to Romalia's king is: "Excellent! From this day forward, [name] will reign as the king of this castle!". But immediately after that, I'm adding the line: "Now, let's get you dressed up appropriately." After which, the game immediately transitions to your playable king character. I think that this smooths out the issue of female heroes to some extent, since it conveys that they are wearing a costume and playing a part. It becomes a little more comical and less awkward, hopefully.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 19, 2020, 08:15:36 am
Something driving me crazy in DQ3: The inventory screen supports item name lengths with 13 characters on top and 11 on the bottom, but the Vault and shop windows only support 12 on top, 10 on the bottom.

I was contemplating changing a couple items to shorter names until the issue became apparent for "Heavenly Gown of Water" (formerly Water Flying Cloth). We worked too hard on that name. It's too perfect. But having it show up in Maira/Kol as "Heavenly Gow of Water is really crap.

The original English release did have some of this, though. Sword of Destruction was chopped in Rimuldar.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on July 19, 2020, 02:49:09 pm
Something driving me crazy in DQ3: The inventory screen supports item name lengths with 13 characters on top and 11 on the bottom, but the Vault and shop windows only support 12 on top, 10 on the bottom.

I was contemplating changing a couple items to shorter names until the issue became apparent for "Heavenly Gown of Water" (formerly Water Flying Cloth). We worked too hard on that name. It's too perfect. But having it show up in Maira/Kol as "Heavenly Gow of Water is really crap.

The original English release did have some of this, though. Sword of Destruction was chopped in Rimuldar.

Am I right in assuming there's space in the window itself, it's just cutting off item name length or are you telling me there's no space in the window itself?

If it's the former, you'll have to use the debugger in FCEU to find those string length values, if it's the latter, you might be able to find the window width values and widen it (and you'll probably still need to find those values) .
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 19, 2020, 08:38:16 pm
The Vault's problem is that it indents the second line by 3 tiles instead of the 2 tiles used by other menus, so using a 2-tile indent should solve the problem there; the shop windows, however, are only wide enough (after reserving room for borders, cursor, and item price) for 12 tiles on the first line and (12 - indent) tiles on the second line. If this is the only case where you need to cram 13 letters into 12 tiles, one option would be to make the class name abbreviations use normal letters and re-purpose the the HrSrPr... tiles as squishy tiles. If you have many places where you want to use more than 12 tiles, however, widening the menus might be a better option, though it'll probably involve a bit of work.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 19, 2020, 09:00:40 pm
Thanks for the input guys.

That's true about the weird 3 character Vault indent. Looking at that rubbed me wrong regardless. I should be able to track down that data and hopefully tweak it. I assume that setting an indent value should be a single nybble or byte?

As far as squish tiles, I'm assuming that the item names in question would have to permanently make use of the squish tiles in every instance. The inconsistency using them only in those cases would be a bit bothersome. If the whole game was VWF, that's another story, but I don't plan on crossing that bridge. I could potentially cut down the incidents of this happening in shops from two to one by changing the Sword of Destruction to the Sword of Ruin. Something to contemplate.

Btw, you mentioned cannibalizing the class abbreviations, but what about the existing squish tiles located after the asterisk: BrMaBiMe. And then there is that weird cursive looking x that appeared after the "w". I already used that one for a tilde symbol for singing. Do you guys know if those are used for anything?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 20, 2020, 09:04:16 pm
That's true about the weird 3 character Vault indent. Looking at that rubbed me wrong regardless. I should be able to track down that data and hopefully tweak it. I assume that setting an indent value should be a single nybble or byte?
Setting a breakpoint on the PPU address for the first (post-indent) letter of the second line of a Vault item and working backwards from there in a trace log will get you the ROM address that controls the Vault indenting pretty quickly; the indents for shop menus are controlled separately.

Btw, you mentioned cannibalizing the class abbreviations, but what about the existing squish tiles located after the asterisk: BrMaBiMe. And then there is that weird cursive looking x that appeared after the "w". I already used that one for a tilde symbol for singing. Do you guys know if those are used for anything?
Yeah, if you only need a couple of squishy tiles, using those instead would be a better plan anyway :).
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 21, 2020, 08:18:29 pm
Setting a breakpoint on the PPU address for the first (post-indent) letter of the second line of a Vault item and working backwards from there in a trace log will get you the ROM address that controls the Vault indenting pretty quickly; the indents for shop menus are controlled separately.
Yeah, if you only need a couple of squishy tiles, using those instead would be a better plan anyway :).
Ok, I'd love to experience a breakpoint breakthrough, but I'll need some additional guidance here.

You say to write a breakpoint to the PPU address of the first letter after the triple indent. Let's use the Staff of Thunder as an example. I'm looking to write a breakpoint to "T". In FCEUX, if I go into PPU viewer, and I can't write any breakpoints, so that's not the way. Next, I go to the hex editor and select view view PPU memory. It's probably here. Except, I can't figure out where. If I do a search for the bytes that make up "Thunder", I can't find anything. If I try to search for a sequence of graphic tile bytes, that yields nothing too. No idea where to locate the T that I write a breakpoint to.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 21, 2020, 10:17:23 pm
Ah, I see. In that case, open up the Name Table Viewer and hover your mouse over that "T" in the Name Table Viewer window. Down in the properties section you'll see it has Tile ID 38 (hexadecimal), X/Y co-ordinates 25/10 (decimal, measured in tiles), and PPU address 2159 (hexadecimal; your numbers may vary depending on the PPU's current scroll position). The important part here is the PPU address; take that over to the Debugger and add a write breakpoint on that address in PPU memory. Back in the game, you'll get hits on that breakpoint as you open and close menus and that section of the screen gets redrawn. The code around where the breakpoint fires won't be terribly interesting since it's just a loop of copying stuff from RAM, but when combined with the Trace Logger, it'll stop you at exactly the right place to start backtracking from.

Spoiler:
More specifically, here:
Code: [Select]
$CAD7:BD 00 03  LDA $0300,X @ $0308 = #$38                   A:00 X:08 Y:07 S:DE P:nvUBdIzc
 $CADA:E8        INX                                          A:38 X:08 Y:07 S:DE P:nvUBdIzc
Breakpoint 0 Hit at $CADB: $2159:EP-W--
The code there is a simple loop copying data to the PPU starting from $0303; the trace log shows it writing #$77 (left border) and then four #$00 (1 space for the cursor column + 3 spaces for indent), so we'll search backwards to find where that data came from:
Code: [Select]
                              $C81C:B9 00 04  LDA $0400,Y @ $0405 = #$38                   A:00 X:08 Y:05 S:E1 P:nvUBdIzc
                              $C81F:9D 00 03  STA $0300,X @ $0308 = #$78                   A:38 X:08 Y:05 S:E1 P:nvUBdIzc
This one's another loop, copying data from $0400 to $0303, so we'll search backwards again:
Code: [Select]
                       $861E:BD FF 03  LDA $03FF,X @ $0425 = #$38                   A:12 X:26 Y:06 S:E8 P:nvUbdIzc
                       $8621:99 FF 03  STA $03FF,Y @ $0405 = #$78                   A:38 X:26 Y:06 S:E8 P:nvUbdIzc
Another copy loop, this time in reverse, but you can still see the rest of the line being copied, so keep going:
Code: [Select]
                         $870E:A6 77     LDX $0077 = #$25                             A:60 X:06 Y:00 S:E6 P:nvUBdIZC
                         $8710:E6 77     INC $0077 = #$25                             A:60 X:25 Y:00 S:E6 P:nvUBdIzC
                         $8712:B9 04 00  LDA $0004,Y @ $0004 = #$38                   A:60 X:25 Y:00 S:E6 P:nvUBdIzC
                         $8715:9D 00 04  STA $0400,X @ $0425 = #$00                   A:38 X:25 Y:00 S:E6 P:nvUBdIzC
This loop is more interesting - only the "Thunder" part gets copied, not the border or spaces. If you were trying to find out where the string came from in ROM, following $0004 would be the next step, but here we care about the position of the string, not its origin. The write offset within the buffer is controlled by X, which came from $0077, so let's follow that instead:
Code: [Select]
                        $827A:A5 77     LDA $0077 = #$1E                             A:00 X:1D Y:0C S:E7 P:nvUBdIZC
                        $827C:18        CLC                                          A:1E X:1D Y:0C S:E7 P:nvUBdIzC
                        $827D:69 07     ADC #$07                                     A:1E X:1D Y:0C S:E7 P:nvUBdIzc
                        $827F:85 77     STA $0077 = #$1E                             A:25 X:1D Y:0C S:E7 P:nvUBdIzc
$77 += 7, huh? Let's see, after the end of the first line, there's 1 tile for the right border, 1 tile for the left border, 1 tile for the cursor column, a 3-tile indent, and then 1 tile to get to the "T", which is 7 tiles. What do you think would happen if we changed that 7 to a 6? :D
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 22, 2020, 08:12:33 am
@abw, thank you for the continued information. Suffice to say I still get quite lost. Below, I'm going to paste what I noted in terms of everything I did along with all the questions I have. Hopefully this can help you help me overcome this hurdle.

$38 was the byte tile assignement

275B was my address of the black space before the T.

My Staff of Thunder was in the third position of the first screen.

On the right side of the debugger screen, I selected "Add" under the breakpoints box. For the address, there was a left and right box. I only filled out 275B in the left box. Marked "Write". Ticked off PPU Mem under Memory. Wrote "Indent" under Name.

Also running Trace Logger.

Initiates game, hits breakpoint as soon as I select "TAKE" in the VAULT menu.

Getting lists of code on the left side of the debugger app as well as with the trace logger. I'm not clear why both apps are needed when the content seems pretty similar.

I can see that the lines of code above the stop point are essentially the same between debugger info and trace logger info.

I'm confused about what a lot of the information represents. For instance, with debugger, the column that looks like "0F:CADB:8D 07 20". Not sure what that means. The STA command to the right makes sense.

Trace logger seems to display some more information. Perhaps that's the value. The first column that looks like f2393787 is consistent for hundreds of lines of code but the last digit changes a couple times. Not sure what that refers to. The next columns with A:AB X:12 Y:05 S:D7 P:NvUbdIzc would seem to show the active contents of the A/X/Y registers. But I'm not sure what the S and P refer to. Perhaps processor flags? But I'm used to seeing processor flag data represented by numbers, not letters. Middle column, we have the same info that appeared in the left column of debugger. On the right side, we see the code commands that I could probably figure out.

I assume that if I scroll up through both of these, I'll continue to see matching lines that take me back in time through the code cycle.

The notations you listed for the steps you copied above seem potentially helpful, but I think i need to get a better grasp of what I'm looking at before I can follow the logic. The documentation I've looked through for FCEUX tools tends to make a lot of assumptions about what the user already understands, and I haven't found it helpful. Hopefully the documenting of the reactions I experience while attempting to explore this stuff will help you more specifically pinpoint my knowledge gaps and what I need to grasp.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 22, 2020, 08:45:40 am
Trace logger logs code that was actually executed during logging.

0F:CADB:8D 07 20
Bank ID:CPU address:opcode + operand

f2393787 - frame counter

S - stack pointer

P - processor status, uppercase letter means flag = 1, otherwise 0
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 22, 2020, 08:56:39 am
That explanation was helpful. Thanks. I should have guessed that clever thing with the upper / lower case letters.

Trace logger logs code that was actually executed during logging.
Does the debugger do something different? Or is it just a matter of the trace logger data giving you more overall information?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 22, 2020, 09:48:23 am
The debugger is a tool for inspecting and manipulating machine instructions and their execution (from fceux help). It's a main tool.

Logger is just an addition tool. However it can save you lots of debugging time if used wisely.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 22, 2020, 05:06:26 pm
Looks like Cyneprepou4uk's got this covered; I'll just add that one of the benefits of a trace log is that it shows you how you got to a specific point, which is something the debugger is not good at (e.g. if the debugger snaps at a breakpoint, you can't be sure what the previous instruction was; maybe it was the instruction one line above the current line, maybe it was a jump/branch). Working backwards can also let you avoid lots of irrelevant breakpoint hits on addresses that are frequently used for things you aren't interested in. FCEUX's debugger is also not great at catching indirect uses; e.g. a RWX breakpoint on $80 does not fire for LDA ($80),Y.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 22, 2020, 11:01:09 pm
Thank you, guys. Tonight I got pulled into some other activities (like putting my scripts through spell check software and... erm.. discovering some things.

@abw
Since I'm going to push out a new DQ2 update anyway, I wanted to include your Text Sound Off patch, mostly to get speaker notations consistently non-indented in the prologue. Not sure why I slept on that until now, but it seems like as good a time as ever to include it.

But here's the thing I'm stuck on: the $60 byte turns off the sound and auto-indent. Great. But how to I work that byte into table file when the left column in my table file is all binary, mostly 10 digit. Do I also need to represent $60 as binary? %01100000?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 23, 2020, 09:15:26 am
Well, ask yourself this: how does DW2's text engine work? It takes the next 5 bits of input, looks that up in the currently selected dictionary page, processes any control codes in the selected dictionary entry, and then returns the resulting string. So if you want to add a new control code, what do you need to do? Edit the dictionary so that the game is able to include it and update your table file to match the game's dictionary :P.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 23, 2020, 09:22:40 am
If all the entries are based on 5 bits of input, why are so many of the entries in the table file you initially set up for me 10 bits? Very confused about that.

But regardless, it sounds like I have to make another sacrificial lamb in the dictionary. I've already done a few of those, and whichever ones I've eliminated have always seemed to result in me taking a 20-30 character hit. I'm down to the wire on free characters, so if I'm going to do this, I'm going to have to think about tweaking more of the dictionary entries in a way that creates greater efficiency and saves me a surplus of characters. Some word searching to determine which strings of text product the most hits is probably the way to go.

All a lot of work for a bit of improved indentation formatting, but I've probably done more work for less if I'm being honest with myself.  :laugh:
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 23, 2020, 08:10:52 pm
If all the entries are based on 5 bits of input, why are so many of the entries in the table file you initially set up for me 10 bits? Very confused about that.
If you wanted to, you could change the 4 switch token labels into actual switch tokens and split that combined single table of 160 entries up into its 5 separate tables of 32 5-bit entries; I figured it was just easier to work with as a single table.

But regardless, it sounds like I have to make another sacrificial lamb in the dictionary. I've already done a few of those, and whichever ones I've eliminated have always seemed to result in me taking a 20-30 character hit. I'm down to the wire on free characters, so if I'm going to do this, I'm going to have to think about tweaking more of the dictionary entries in a way that creates greater efficiency and saves me a surplus of characters. Some word searching to determine which strings of text product the most hits is probably the way to go.
As with Choppasmith's dictionary, yours can be significantly optimized. Try the following based on your 1.11 patch; it should save you somewhere around 1700 bytes, enough to fit your entire script into the first script bank:
Code: [Select]
/%00000=[end-FC]\n
/%00001=.[end-FC]\n
/%00010=?’[FD][FD][end-FC]\n
/%00011=[.’][end-FC]\n
# 00100 is an intermediate end token, used to subdivide larger strings where the same function needs to be called multiple times with different values.
# E.g. in
# [name] [end-FF]threw away [name]'s [item] and gave [end-FF]the [item] to ghost of [name].[end-FC]
# the first [name] is the Prince of Midenhall's name, but the second and third [name] are the name of the dead party member whose items you are ransacking;
# similarly, the first [item] is the item you lose, but the second [item] is the item you gain.
/%00100=[end-FF]\n
%00101=
%00110=e
%00111=o
%01000=t
%01001=a
%01010=r
%01011=n
%01100=h
%01101=s
%01110=i
%01111=l
%10000=u
%10001=d
%10010=y
%10011=‘
%10100=f
%10101=m
%10110=g
%10111=c
%11000=w
%11001=[.’]
%11010=p
%11011=.
%11100=[switch to C0 table]
%11101=[switch to C1 table]
%11110=[switch to C2 table]
%11111=[switch to C3 table]

# C0 table
%1110000000=v
%1110000001=[wait]
%1110000010=b
%1110000011=,
%1110000100=[line]
%1110000101=I
%1110000110=k
%1110000111=[name]
%1110001000=’
%1110001001=T
%1110001010='
%1110001011=!
%1110001100=[FD]
%1110001101=W
%1110001110=?
%1110001111=H
%1110010000=S
%1110010001=M
%1110010010=Y
%1110010011=L
%1110010100=G
%1110010101=A
%1110010110=P
%1110010111=R
%1110011000=C
%1110011001=D
%1110011010=B
%1110011011=K
%1110011100=[..]
%1110011101=F
%1110011110=j
%1110011111=[item]

# C1 table
%1110100000=O
%1110100001=[number]
%1110100010=:
%1110100011=E
%1110100100=x
%1110100101=N
%1110100110=q
%1110100111=[no voice]
%1110101000=z
%1110101001=[(s)]
%1110101010=-
%1110101011=/A
%1110101100=J
%1110101101=U
%1110101110=[monster(s)]
%1110101111=[item-F9]
%1110110000=[cardinal #]
%1110110001=Z
%1110110010=V
%1110110011=[sun]
%1110110100=[star]
%1110110101=[spell]
%1110110110=[moon]
%1110110111= the
%1110111000= you
%1110111001=[.’][wait][line]‘
%1110111010= of
%1110111011= have
%1110111100= b
%1110111101=!’
%1110111110= is
%1110111111= that

# C2 table
%1111000000= to
%1111000001=The
%1111000010=ve
%1111000011=,
%1111000100=ing
%1111000101=Moonbrooke
%1111000110= will
%1111000111= and
%1111001000= Hargon
%1111001001=You
%1111001010=‘Welcome
%1111001011=Laurasia
%1111001100=here
%1111001101= with
%1111001110='s
%1111001111=descendants
%1111010000=[wait][line]
%1111010001=rince
%1111010010= for
%1111010011=treasure chest
%1111010100=[name]
%1111010101=Samaltria
%1111010110=I
%1111010111=Castle
%1111011000=this
%1111011001= from
%1111011010= a
%1111011011=ther
%1111011100=ke
%1111011101= are
%1111011110=Moon Fragment
%1111011111= has

# C3 table
%1111100000=What
%1111100001= journey
%1111100010= in
%1111100011=I'
%1111100100=lease
%1111100101=oof woof
%1111100110=ter
%1111100111=n't
%1111101000=rea
%1111101001= to
%1111101010=ight
%1111101011=But
%1111101100=return
%1111101101=[number] piece[(s)]
%1111101110=Rondarkia
%1111101111=Roto
%1111110000=eautiful voice
%1111110001= of
%1111110010=This
%1111110011=ed
%1111110100=ear
%1111110101=ome
%1111110110=ll
%1111110111=not
%1111111000= was
%1111111001=[.’][wait]
%1111111010=?’
%1111111011=curse
%1111111100=companion
%1111111101= it
%1111111110=Let us meet aga
%1111111111= must
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 23, 2020, 09:20:14 pm
After having just "optimized" my dictionary, entirely pleased with myself for freeing up 50 characters, now I'm here pulling my jaw up off the floor.

You have clearly bound your soul to a demon in exchange for these powers.

It would appear that I just have to plug all the entries into my dictionary and assign all the right spacing nybbles. This is a marvelous opportunity to never have to be concerned with space again in this game. I don't have words.  :woot!:

(https://i.imgur.com/nzua0Cs.png)


So I implemented your patch that fixes indenting. I inserted the $60 byte after the line before each new speaker I want indented correctly. In all cases but one, it's working fine. For this princess line, it for some reason isn't indenting her saying the word "father!". Can't figure this out. Here's the relevant lines from my atlas file.

King:[ ‘]My dear [name], I beg you to hide yourself down below[.’][wait][line]
[ ‘]If anything should happen to me, you must not grieve[.’][60][wait][line]
Princess:[ ‘]But father![' ][60][wait][line]
King:[ ‘]I will inform the king of Laurasia of our dire situation.[wait][line]Now, you must go![' ][end]

[60] is my way of representing the $60 dictionary entry in the table file.

Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 24, 2020, 08:43:10 am
After having just "optimized" my dictionary, entirely pleased with myself for freeing up 50 characters, now I'm here pulling my jaw up off the floor.

You have clearly bound your soul to a demon in exchange for these powers.
Despite what some people might claim it stands for, CS really means Computer Sorcery :P

So I implemented your patch that fixes indenting. I inserted the $60 byte after the line before each new speaker I want indented correctly. In all cases but one, it's working fine. For this princess line, it for some reason isn't indenting her saying the word "father!". Can't figure this out.
My first guess would be that it has to do with that line of text taking up exactly 1 line of the window. It should fit without wrapping, but probably the extra [60] isn't considered whitespace and is preventing that. Try moving the [60] around a bit, taking it out, or adding a regular space before it; if none of that works, changing the length of the line by even 1 tile should also do the trick.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 24, 2020, 10:19:42 am
So I did my best to follow along with your debugger notes. I gained some helpful familiarity with the process of searching through trace logger data. Did I follow all your logic? Not even close. I'd probably need a more real-time interactive form of communication than forum posting for that, where I could ask questions and clear up my confusion on each step in your thought process. But there is research I can do on my own which can potentially help with this kind of thing.

In spite of not following all the logic, I made the change of 07 to 06 as you suggested after locating that sequence at rom address 0x042BE. It shifted the indent as you suggested. Yay! But, it's still chopping off the 11th character of "Destruction", and was probably programmed to do so so that the "n" wouldn't overwrite the right border. It would seem that there is another step involved in fixing this.

(https://i.imgur.com/1gU2zq1.png)

July 24, 2020, 10:42:11 am - (Auto Merged - Double Posts are not allowed before 7 days.)
I took your suggestion of playing around with the [60] for that princess line. Yes, it does seem that that specific line length creates a problem with your patch.

Princess:[ ‘]But father![' ][60][wait][line] was the initial format causing the problem.

I moved the byte to:

Princess:[ ‘]But father![' ][wait][line][60] and got this:

(https://i.imgur.com/KO45FOh.png)

Not any better. So then, I tried this:

Princess:[ ‘]But father![' ][wait][60][line] and got this:

(https://i.imgur.com/AmE5Jpy.png)

Probably the best result so far but it adds an extra line of spacing. I'm not exceptionally fond of inconsistent line spacing. Last, I tried:

Princess:[ ‘]But father![' ][wait][60] but it produced this result again:

(https://i.imgur.com/KO45FOh.png)

I don't love the idea of changing the "But father!" text and might prefer to live with the extra spacer line. Will have to think on it. The line length is part of the text engine, and it would probably be pretty hard to change it in this case without changing it universally. Hmmm...
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 24, 2020, 08:46:58 pm
So I did my best to follow along with your debugger notes. I gained some helpful familiarity with the process of searching through trace logger data. Did I follow all your logic? Not even close. I'd probably need a more real-time interactive form of communication than forum posting for that, where I could ask questions and clear up my confusion on each step in your thought process. But there is research I can do on my own which can potentially help with this kind of thing.
No worries - the more you use it the better you'll get!

In spite of not following all the logic, I made the change of 07 to 06 as you suggested after locating that sequence at rom address 0x042BE. It shifted the indent as you suggested. Yay! But, it's still chopping off the 11th character of "Destruction", and was probably programmed to do so so that the "n" wouldn't overwrite the right border. It would seem that there is another step involved in fixing this.
Yay! But yes, it does look like there's a maximum length being set somewhere else that would have to be updated too. The good news is that that length will be set somewhere in your trace log!

I took your suggestion of playing around with the [60] for that princess line. Yes, it does seem that that specific line length creates a problem with your patch.
[...]
I don't love the idea of changing the "But father!" text and might prefer to live with the extra spacer line. Will have to think on it. The line length is part of the text engine, and it would probably be pretty hard to change it in this case without changing it universally. Hmmm...
How about adding a space between the colon and opening quote? I see you've mostly gone with no space between them (except for the line when the princess meets her father after regaining her form), but that change would fix this one line, and if you're lucky it won't break any of the other lines. In my translation, I preserved the interlaced speech and narrative structure but put them on separate lines since there's a delay between turning the flag for the speech sound effect off and the speech sound effect stopping, so I didn't have to deal with any of this :P.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 25, 2020, 12:07:30 am
Quote
Yay! But yes, it does look like there's a maximum length being set somewhere else that would have to be updated too. The good news is that that length will be set somewhere in your trace log!
You are a sly one. I'll give it the ol' college try, but you can probably expect more questions about this.

Quote
How about adding a space between the colon and opening quote? I see you've mostly gone with no space between them (except for the line when the princess meets her father after regaining her form), but that change would fix this one line, and if you're lucky it won't break any of the other lines. In my translation, I preserved the interlaced speech and narrative structure but put them on separate lines since there's a delay between turning the flag for the speech sound effect off and the speech sound effect stopping, so I didn't have to deal with any of this :P.
Putting a line opcode right after the colon creates a very pleasant visual and solves the Princess problem.  :woot!:

Unfortunately, a new issue seems to be popping up that doesn't seem to correspond to the previous issue.

(https://i.imgur.com/asewLku.png)

Here's the text that relates to this line:

[FD]Soldier:[line][ ‘]Never mind me. I would request an audience with the king immediately[.’][wait][line]
[ ‘]I bring terrible news that must be reported![' ][60][wait][line]
Guards:[line][ ‘]We understand. Let us help you up[.’][end]

July 25, 2020, 09:04:09 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Actually, it's most likely related to the previous issue. We are probably hitting that magic number again with the final line. I'll try to rephrase, perhaps. More opportunity to do so here.

PS, if I understand this correctly, I could probably plug the [60] earlier in the line and it shouldn't cause any problems. When I get home and can play around, I'll try the Solider:[60][line]. That would seem to be a pretty safe placement method in general considering the line for the speaker is going to always be short.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 25, 2020, 10:27:22 am
You are a sly one. I'll give it the ol' college try, but you can probably expect more questions about this.
The line length control isn't too far astray from the path we were on, basically just 1 CTRL+F away.

Putting a line opcode right after the colon creates a very pleasant visual and solves the Princess problem.  :woot!:
Yay!

Unfortunately, a new issue seems to be popping up that doesn't seem to correspond to the previous issue.
It looks like the [60] and the [wait] don't play well with each other, which is another issue I never had to deal with in my text :P. Since both of your lines are fairly short, one option would be to take out the [wait] and just have e.g.
Code: [Select]
[FD]Soldier:[line]‘Never mind me. I would request an audience with the king immediately[.’][wait][line]
‘I bring terrible news that must be reported!’[line][60][line]
Guards:[line]‘We understand. Let us help you up[.’][end]
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 25, 2020, 04:38:57 pm
Quote
The line length control isn't too far astray from the path we were on, basically just 1 CTRL+F away.

The fact that Control F doesn't work in the case logger window makes me want to scream. Neither does the ability to select all and copy / paste. I attempted to save the code logger data to a file, produced a CDL file, opened it in Notepad++ and everything says NULL. Wonderful experience.

So I retreated from that and tried doing searches for the line length in the rom area around 0x0428A where the indent spacing is stored. First I searched all the 0A bytes (representing the current value of 10) before and after that address. None of those were the one. Then, I thought it might start the counting from the beginning of the line, so I started searching things like 0E / 0F / 10. Nope, nope and nope.

Quote
It looks like the [60] and the [wait] don't play well with each other, which is another issue I never had to deal with in my text :P. Since both of your lines are fairly short, one option would be to take out the [wait] and just have e.g.
I use the wait command quite liberally. A change in speaker will always be marked by a button input in my scripts, so that's pretty non-negotiable. But the good news is that I was able to do a bit of rewording for that soldier and I'm just as happy with the result. I revised the dialogue with the princess talking to her father's spirit, and that is working fine. Will probably push out an update in a bit which doesn't yet include your revised dictionary. I had enough free characters to do what needs to be done for now, but I will make it a point to revise all that before the next playthrough I do, since I will inevitably want to rewrite pieces of text and I'm sure I would enjoy all that space to work with.

I appreciate all your attention with these questions btw. I'm probably going to keep coming with them relentlessly over the next few weeks. If it becomes too much, let me know. The good thing is that there are some areas I'm actually making progress on by myself, like the nametable work needed for the title screen. Therefore, I can keep myself occupied, and it's not too bad of a start / stop / start / stop situation.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 25, 2020, 05:02:23 pm
CDL is a binary file, not a text file. It contains several flags for each byte of rom, such as code and data flags, marks code/data in debugger and highlights bytes in hex editor.

CDL is produced by code/data logger, not by trace logger. Trace logger can output to a text file (like I said before).

No, actually I said that in another thread  >:D
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 25, 2020, 11:25:34 pm
The fact that Control F doesn't work in the case logger window makes me want to scream. Neither does the ability to select all and copy / paste. I attempted to save the code logger data to a file, produced a CDL file, opened it in Notepad++ and everything says NULL. Wonderful experience.
I'm sure having the Trace Logger log to its own little window must be useful in some situations, but I always log to a file instead and then view the output in a fully-featured text editor.

So I retreated from that and tried doing searches for the line length in the rom area around 0x0428A where the indent spacing is stored. First I searched all the 0A bytes (representing the current value of 10) before and after that address. None of those were the one. Then, I thought it might start the counting from the beginning of the line, so I started searching things like 0E / 0F / 10. Nope, nope and nope.
It actually is a #$0A - the key there is to look at the end condition for the item name copy loop that's too short and find out what sets it; in this case the loop exits when $78 == 0, and $78 gets set to #$0A based on $01:$8705, which in the trace logs comes a mere 4 lines after updating the write position for the second row.

I use the wait command quite liberally. A change in speaker will always be marked by a button input in my scripts, so that's pretty non-negotiable. But the good news is that I was able to do a bit of rewording for that soldier and I'm just as happy with the result.
Fair enough - it definitely wasn't a perfect solution, but I'm glad to hear you've come up with something that works out!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 27, 2020, 07:36:30 am
Ok! I got the Trace Logger file outputting and yes, that's a much better way of utilizing the data. After tracking down that line limiting byte and changing it from 0A to 0B, I ended up realizing that the top line was also unnecessarily limited to 12 characters when it has space for 13. So I used largely the same process, adjusted the limit from 0C to 0D, and got a nice surprise afterwards:

(https://i.imgur.com/jg3VgEC.png)

But the good news is, that was an easy fix. The line two start point needed to be adjusted from 06 down to 05. And voila, a perfect VAULT window  :woot!:

(https://i.imgur.com/5rqIj9X.png)

Now, onto the next smallish thing:

I went back to your advice from weeks ago about how to change the case insensitive Erdrick name restriction to Roto. Here is what you advised.

Quote
This one is pretty easy to track down - if you watch RAM with a table file open while entering "Erdrick", you'll see the name being stored starting at $0009; from there, a read breakpoint will (after a few other hits) get you to the code for comparing the entered name against "Erdrick"... case insensitively ;).
Seeing the letters Erdrick magically appear with a table file loaded into RAM at $0009 was admittedly pretty easy (and neat!), along with setting the read breakpoint.

The part that wasn't so easy was getting 10,000 hits on that breakpoint and not being able to make heads or tails of which one was relevant.

I also have a hard time conceptualizing how the game would store this hybrid upper case / lower case data to reference, so I'm not sure what I'll be ultimately looking for.

Any help with this one would be appreciated!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 27, 2020, 08:06:34 am
Use forbit breakpoints on hit locations to disable unnecessary ones.

If the game stores letters in some format similar to ascii, where lowercase is +20, then it can check both cases by ORA 20 the entered letter and comparing result to a forbitten lowercase letter.

Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 27, 2020, 08:13:28 am
Use forbit breakpoints on hit locations to disable unnecessary ones.

If the game stores letters in some format similar to ascii, where lowercase is +20, then it can check both cases by ORA 20 the entered letter and comparing result to a forbitten letter.
I assume you mean forbid breakpoint. I'm not sure what that does, but I imagine it restricts it? Would I just check the forbid box off in the dubugger and that's it?

As for the ORA thing, in my table file 10=f and 2A=F, so that doesn't look like a difference of $20
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 27, 2020, 08:19:34 am
Yes, forbid. It prevents R/W/X breakpoints from getting hit on a specific location. You can double click on cpu address where it hits and add a corresponding checkmark.

Then probably it has to check for both cases sepatately. Maybe by using ADC / SBC 1A

One more option is to set breakpoints to another address of 0009,X range. Since code will most likely be checking name within a loop, an instruction that is gonna trigger a breakpoint for 000B will be working with 0009,X, not with 000B directly.

Actually, no, I don't think this would help much in your particular case.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 27, 2020, 05:27:21 pm
And voila, a perfect VAULT window  :woot!:
Congratulations!

If the game stores letters in some format similar to ascii, where lowercase is +20, then it can check both cases by ORA 20 the entered letter and comparing result to a forbitten lowercase letter.
Yeah, ASCII is cool that way, but DW2's character mapping does not have that property, so DW2 ends up explicitly comparing the first letter against "E" and "e", then the second letter against "R" and "r", etc.

The part that wasn't so easy was getting 10,000 hits on that breakpoint and not being able to make heads or tails of which one was relevant.
If you set your breakpoint just before hitting "END", I think the second hit is the one you'll want.

One more option is to set breakpoints to another address of 0009,X range. Since code will most likely be checking name within a loop, an instruction that is gonna trigger a breakpoint for 000B will be working with 0009,X, not with 000B directly.

Actually, no, I don't think this would help much in your particular case.
As it happens, this also works fairly well - a read breakpoint on e.g. $000A will fire a little too late to see the check on $0009, but the rest of the code is all located in the same area and is easily visible in the debugger or trace log.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 28, 2020, 06:52:04 am
Quote
f12338  A:06 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBA9:E9 01     SBC #$01
f12338  A:05 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBAB:D0 F6     BNE $CBA3
f12338  A:05 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBA3:48        PHA
f12338  A:05 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
f12338  A:04 X:00 Y:70 S:DF P:nvUbdIzC $CBA6:D0 FC     BNE $CBA4
f12338  A:04 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
f12338  A:03 X:00 Y:70 S:DF P:nvUbdIzC $CBA6:D0 FC     BNE $CBA4
f12338  A:03 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
f12338  A:02 X:00 Y:70 S:DF P:nvUbdIzC $CBA6:D0 FC     BNE $CBA4
f12338  A:02 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
f12338  A:01 X:00 Y:70 S:DF P:nvUbdIzC $CBA6:D0 FC     BNE $CBA4
f12338  A:01 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
f12338  A:00 X:00 Y:70 S:DF P:nvUbdIZC $CBA6:D0 FC     BNE $CBA4
f12338  A:00 X:00 Y:70 S:DF P:nvUbdIZC $CBA8:68        PLA
f12338  A:05 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBA9:E9 01     SBC #$01
f12338  A:04 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBAB:D0 F6     BNE $CBA3
f12338  A:04 X:00 Y:70 S:E0 P:nvUbdIzC                                $CBA3:48        PHA
f12338  A:04 X:00 Y:70 S:DF P:nvUbdIzC $CBA4:E9 01     SBC #$01
Doing my best to analyze some of these lines of code, and if I were to make a wildly uneducated guess, the letter checking may have something to do with this stuff? If I follow these addresses back to the hex editor, I'm still not seeing anything intelligible to me indicating what I need to change.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 28, 2020, 07:46:35 am
It doesn't look like name checking at all.

This is the best you could find? Seriously?

Here is what you need to do. While entering a name, set read breakpoint to 0009, and forbid every location where it triggers. Then confirm entered name, and one of the new breakpoint hits is gonna be what you are looking for.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 28, 2020, 08:15:35 am
@Cyneprepou4uk
Quote
This is the best you could find? Seriously?
I'm obviously very new and very uncomfortable with making these kinds of attempts to sort through code. If you're not going to be patient and respectful in your way of offering help, I'd rather not have it.

Furthermore, you're making a lot of assumptions about what I already understand in the way you explain things.

For instance, "forbid every location where it triggers". I have no idea what this means. "what you are looking for" - I have no idea what I'm looking for, technically speaking, so I doubt I'll recognize it.

If you aspire to be a teacher of new rom hackers, I suggest some changes to your approach.

Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 28, 2020, 08:25:35 am
You are looking for code which checks for a specific name.

Lets say your 0009 breakpoint got hit at 0F:89AB. Double click at 89AB. An "add breakpoint" window will be open, it'll already have 89AB and some condition written there, you just need to enable "forbid" checkmark and press OK.

There, now your 0009 breakpoint won't trigger at 89AB. Do the same with other hits.



Quote
If you aspire to be a teacher of new rom hackers, I suggest some changes to your approach.


I expect readers to try something on their own. For example:
Quote
You can double click on cpu address where it hits and add a corresponding checkmark.
Obviously you didn't do that. Or is my english that bad?

Also, I don't spend much time right away on explaining things in details, because most of the time people don't do anything, so it will be a waste for me.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 28, 2020, 09:21:30 am
Quote
You can double click on cpu address where it hits and add a corresponding checkmark.
I somehow overlooked that step. It certainly wasn't intentional, and I don't need to be scolded for it, or have assumptions made that I'm not trying to be independent. There are some technically complex things that I've done and am doing right now that I'm not even talking about because I grasp those things and don't need the help. That's my ultimate goal with all of this stuff.

Quote
Also, I don't spend much time right away on explaining things in details, because most of the time people don't do anything, so it will be a waste for me.
If you have any degree of familiarity with my forum activity for the last two years, it should be clear that I am committed to learning and doing. Abw's communications may also sometimes exceed my technical comprehension, but he has been consistently respectful and generous with advice and help. Some might say too generous, but I have learned things along the way in spite of (or perhaps, because of) that generosity.

If the day comes when abw starts getting tired of dealing with my limited technical capacity, he is certainly welcome to speak up, and I will respect that. But in the meantime, I prefer to wait for answers that show respect both to me and to the commitment that I've demonstrated.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 28, 2020, 10:14:53 am
Well, I'm not wiping your snots and showing respect while giving answers  >:D

Ask your questions about what you still don't understand if you want to get this thing done.

Or you can wait for abw to come here once a day, I don't really care.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 28, 2020, 10:37:57 am
Quote
Well, I'm not wiping your snots and showing respect while giving answers
At this point, I'm probably just as interested in learning about hacking from you as you are in learning about respect from me.

We'd probably be better off just staying out of each other's way from here.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on July 28, 2020, 07:57:57 pm
(removed wrong advice)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: scarlet on July 28, 2020, 10:08:57 pm
Well, I'm not wiping your snots and showing respect while giving answers  >:D

Ask your questions about what you still don't understand if you want to get this thing done.

Or you can wait for abw to come here once a day, I don't really care.

One of the greatest growth points for a software engineer is when they learn both the value of being kind while giving feedback, and how to do it. 
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on July 29, 2020, 01:52:24 am
@Chicken Knife
Found 'ERDRICK' without too much effort. Here's what I did as a cluebook:
- Turn on 'Code Data Logger'
- Enter 'ERDRICK' as name
- Put cursor on 'END'
- Turn on 'Trace Logger'
- Press enter
- 'INPUT YOUR NAME!'
- Turn off 'Trace Logger'


From the earlier clues in this thread, I know to look at $0009-000F for name. I searched for $000F since it's ERDRIC(K) and found 1 hit.

Your name check is in bank $06:Bxxx. And it's hard-coded asm.
I’m confused, is is it not at x00AA73 as mentioned on Data Crystal?
https://datacrystal.romhacking.net/wiki/Dragon_Warrior_III:ROM_map#Text
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on July 29, 2020, 07:37:56 am
(removed wrong advice)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on July 29, 2020, 09:18:07 am
Come on now, can't we all just get along here?

Chicken Knife, Cyneprepou4uk is trying to help, and freely offered assistance is not something to be tossed aside lightly. Cyneprepou4uk, Chicken Knife is making an effort to learn and grow, which is something worth encouraging, and has been making progress over a decent period of time while working on multiple fronts. I think I get where you're coming from, and I know it can be frustrating when other people have difficulty with things that come easily to you, but ask yourself whether belittling them really results in the outcome you wish to achieve. Conversely, Chicken Knife, you've got access to all the tools and information you need to figure out what an unfamiliar block of code does; spending a little more time getting familiar with the tools and absorbing the information will make you both more efficient and more effective at working with code.



As for tracking down this particular bit of code, another approach you could try is making one trace log with "Erdrick" and one trace log with some other name and then comparing the trace logs to find out where they differ; it's not an exact process since there could be unrelated differences (particularly due to timing), but if you can narrow down the range of what you log (e.g. by setting some useful breakpoints before and after the difference you're trying to detect), it can be quite useful.

I’m confused, is is it not at x00AA73 as mentioned on Data Crystal?
https://datacrystal.romhacking.net/wiki/Dragon_Warrior_III:ROM_map#Text
Yeah, that was my first guess too, but it turns out that the code for checking the player name does not rely on that string in any way, so we had to go searching for the code.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Darrman on July 29, 2020, 11:45:30 am
I had actually removed the Erdrick restriction for myself a while ago.

http://www.romhacking.net/hacks/5162/

I left some notes in the download if anyone felt like modifying the check for themselves.

I've copied them here for convenience. They're inside the spoiler.

Spoiler:
Code: [Select]
RAM 0x09 = first letter of name select, break on read here
see rhdn for table
offsets are at the start of the opcode, not necessarily where the exact number is
findings using fceux debugger
check if your name is "erdrick" and get mad if so:
letter 1:
1bc1a = compare $29; E
1bc1e = compare $0F; e
if true jump to ram $bc13 - letter 2
otherwise rts and proceed
letter 2:
increment x
load appropriate byte for current letter
compare with the listed byte below, continue on if true
this repeats for the remaining letters
1bc26 = $36; R
1bc2a = $1c; r
letter 3:
1bc32 = $28; D
1bc36 = $0e; d
letter 4:
1bc3e = $36; R
1bc42 = $1c; r
letter 5:
1bc4a = $2d; I
1bc4e = $13; i
letter 6:
1bc56 = $27; C
1bc5a = $0d; c
letter 7:
1bc62 = $2f; K
1bc66 = $15; k
if things are still true at this point,
jump to ram $bc5b
x is incremented and compared to 0x8
if it's not 8, branch to $bc61
if it is, return; hence "erdrick " is fine
load letter 8 into a, if it's zero, jump to ram $bc5b
this time x will equal 8, so it returns
by this time the game's determined you've tried to name erdrick "erdrick" and it gets annoyed and pops up a message shouting "INPUT YOUR NAME!" emphasis on "YOUR", presumably

there's probably a more elegant way to change this, but i just simply zeroed out all the comparisons
if you want to block a different name, leave any excess letters zeroed out
say you want to negate "loto" instead, then change the first four letters to correspond to that, and set the other three to zero
if you want to block an eight character name, you're out of luck without some actual modifications to the code

(Disclaimer: I know very little about ASM.)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on July 29, 2020, 12:09:45 pm
(removed wrong advice)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on July 30, 2020, 12:52:42 am
From the earlier clues in this thread, I know to look at $0009-000F for name. I searched for $000F since it's ERDRIC(K) and found 1 hit.
storall, thank you for chiming in with help! Following along with your suggestions, I get lost at this part. What are you searching in for 000F, the trace log? I get zero hits when I search that in mine.

Chicken Knife, Cyneprepou4uk is trying to help, and freely offered assistance is not something to be tossed aside lightly.
abw, the weight of that was not lost on me. I was--and am--grateful for the Cyneprepou4uk's initiative to help. I am still open to that help, but between the stress coming from this challenge and life's other significant stressors at this time, a belittling tone is something I can't just brush off and live with. That parting ways comment was made because I thought Cyneprepou4uk made it pretty clear that he is not willing to try to improve his communication. I'd be delighted if that turns out to not be the case.

As for tracking down this particular bit of code, another approach you could try is making one trace log with "Erdrick" and one trace log with some other name and then comparing the trace logs to find out where they differ; it's not an exact process since there could be unrelated differences (particularly due to timing), but if you can narrow down the range of what you log (e.g. by setting some useful breakpoints before and after the difference you're trying to detect), it can be quite useful.
So I did exactly this, and invested time in comparing the two logs side by side, starting from the bottom. The bottom 25% or so of the 140k lines seemed to match beyond the minor variances you mention. The changes in indentation for the right columns make comparison pretty simple. I'm kind of curious what causes those changes. But in any case, once I got about 25% up the log, I found this section that varies, and it seemed to potentially deal with the same RAM address that storall mentioned above. Here's the section I'm referring to with the code from the ERDRICK input first, followed by the same section of code (matching beginning and end) from an ABC name input.

Code: [Select]
(From ERDRICK input)

---------------------------
f8745   A:FF X:02 Y:04 S:D0 P:nvUbdIZc                $B722:BD 73 04  LDA $0473,X @ $0475 = #$A7
f8745   A:A7 X:02 Y:04 S:D0 P:NvUbdIzc                $B725:B0 02     BCS $B729
f8745   A:A7 X:02 Y:04 S:D0 P:NvUbdIzc                $B727:30 50     BMI $B779
f8745   A:A7 X:02 Y:04 S:D0 P:NvUbdIzc                $B779:60        RTS (from $B71F) ---------------------------
f8745   A:A7 X:02 Y:04 S:D2 P:NvUbdIzc              $B419:20 49 B4  JSR $B449
f8745   A:A7 X:02 Y:04 S:D0 P:NvUbdIzc                $B449:8E F1 06  STX $06F1 = #$00
f8745   A:A7 X:02 Y:04 S:D0 P:NvUbdIzc                $B44C:B5 F7     LDA $F7,X @ $00F9 = #$07
f8745   A:07 X:02 Y:04 S:D0 P:nvUbdIzc                $B44E:10 28     BPL $B478
f8745   A:07 X:02 Y:04 S:D0 P:nvUbdIzc                $B478:98        TYA
f8745   A:04 X:02 Y:04 S:D0 P:nvUbdIzc                $B479:48        PHA
f8745   A:04 X:02 Y:04 S:CF P:nvUbdIzc                 $B47A:B4 F6     LDY $F6,X @ $00F8 = #$44
f8745   A:04 X:02 Y:44 S:CF P:nvUbdIzc                 $B47C:B9 6B 81  LDA $816B,Y @ $81AF = #$4D
f8745   A:4D X:02 Y:44 S:CF P:nvUbdIzc                 $B47F:85 E0     STA $00E0 = #$09
f8745   A:4D X:02 Y:44 S:CF P:nvUbdIzc                 $B481:B9 6C 81  LDA $816C,Y @ $81B0 = #$84
f8745   A:84 X:02 Y:44 S:CF P:NvUbdIzc                 $B484:85 E1     STA $00E1 = #$00
f8745   A:84 X:02 Y:44 S:CF P:NvUbdIzc                 $B486:B4 F7     LDY $F7,X @ $00F9 = #$07
f8745   A:84 X:02 Y:07 S:CF P:nvUbdIzc                 $B488:B1 E0     LDA ($E0),Y @ $8454 = #$B9
f8745   A:B9 X:02 Y:07 S:CF P:NvUbdIzc                 $B48A:C9 30     CMP #$30
f8745   A:B9 X:02 Y:07 S:CF P:NvUbdIzC                 $B48C:B0 05     BCS $B493
f8745   A:B9 X:02 Y:07 S:CF P:NvUbdIzC                 $B493:F6 F7     INC $F7,X @ $00F9 = #$07
f8745   A:B9 X:02 Y:07 S:CF P:nvUbdIzC                 $B495:AA        TAX
f8745   A:B9 X:B9 Y:07 S:CF P:NvUbdIzC                 $B496:68        PLA
f8745   A:04 X:B9 Y:07 S:D0 P:nvUbdIzC                $B497:A8        TAY
f8745   A:04 X:B9 Y:04 S:D0 P:nvUbdIzC                $B498:B0 BE     BCS $B458
f8745   A:04 X:B9 Y:04 S:D0 P:nvUbdIzC                $B458:8A        TXA
f8745   A:B9 X:B9 Y:04 S:D0 P:NvUbdIzC                $B459:AE F1 06  LDX $06F1 = #$02
f8745   A:B9 X:02 Y:04 S:D0 P:nvUbdIzC                $B45C:E0 08     CPX #$08
f8745   A:B9 X:02 Y:04 S:D0 P:NvUbdIzc                $B45E:AA        TAX
f8745   A:B9 X:B9 Y:04 S:D0 P:NvUbdIzc                $B45F:B0 13     BCS $B474
f8745   A:B9 X:B9 Y:04 S:D0 P:NvUbdIzc                $B461:29 0F     AND #$0F
f8745   A:09 X:B9 Y:04 S:D0 P:nvUbdIzc                $B463:85 E1     STA $00E1 = #$84
f8745   A:09 X:B9 Y:04 S:D0 P:nvUbdIzc                $B465:AD 7F 04  LDA $047F = #$10
f8745   A:10 X:B9 Y:04 S:D0 P:nvUbdIzc                $B468:85 E0     STA $00E0 = #$4D
f8745   A:10 X:B9 Y:04 S:D0 P:nvUbdIzc                $B46A:20 54 B8  JSR $B854

(From ABC Input)

---------------------------
f10077  A:FF X:02 Y:04 S:D0 P:nvUbdIZc                $B722:BD 73 04  LDA $0473,X @ $0475 = #$A5
f10077  A:A5 X:02 Y:04 S:D0 P:NvUbdIzc                $B725:B0 02     BCS $B729
f10077  A:A5 X:02 Y:04 S:D0 P:NvUbdIzc                $B727:30 50     BMI $B779
f10077  A:A5 X:02 Y:04 S:D0 P:NvUbdIzc                $B779:60        RTS (from $B71F) ---------------------------
f10077  A:A5 X:02 Y:04 S:D2 P:NvUbdIzc              $B419:20 49 B4  JSR $B449
f10077  A:A5 X:02 Y:04 S:D0 P:NvUbdIzc                $B449:8E F1 06  STX $06F1 = #$00
f10077  A:A5 X:02 Y:04 S:D0 P:NvUbdIzc                $B44C:B5 F7     LDA $F7,X @ $00F9 = #$FE
f10077  A:FE X:02 Y:04 S:D0 P:NvUbdIzc                $B44E:10 28     BPL $B478
f10077  A:FE X:02 Y:04 S:D0 P:NvUbdIzc                $B450:A2 30     LDX #$30
f10077  A:FE X:30 Y:04 S:D0 P:nvUbdIzc                $B452:C9 FF     CMP #$FF
f10077  A:FE X:30 Y:04 S:D0 P:NvUbdIzc                $B454:F0 02     BEQ $B458
f10077  A:FE X:30 Y:04 S:D0 P:NvUbdIzc                $B456:A2 32     LDX #$32
f10077  A:FE X:32 Y:04 S:D0 P:nvUbdIzc                $B458:8A        TXA
f10077  A:32 X:32 Y:04 S:D0 P:nvUbdIzc                $B459:AE F1 06  LDX $06F1 = #$02
f10077  A:32 X:02 Y:04 S:D0 P:nvUbdIzc                $B45C:E0 08     CPX #$08
f10077  A:32 X:02 Y:04 S:D0 P:NvUbdIzc                $B45E:AA        TAX
f10077  A:32 X:32 Y:04 S:D0 P:nvUbdIzc                $B45F:B0 13     BCS $B474
f10077  A:32 X:32 Y:04 S:D0 P:nvUbdIzc                $B461:29 0F     AND #$0F
f10077  A:02 X:32 Y:04 S:D0 P:nvUbdIzc                $B463:85 E1     STA $00E1 = #$00
f10077  A:02 X:32 Y:04 S:D0 P:nvUbdIzc                $B465:AD 7F 04  LDA $047F = #$90
f10077  A:90 X:32 Y:04 S:D0 P:NvUbdIzc                $B468:85 E0     STA $00E0 = #$02
f10077  A:90 X:32 Y:04 S:D0 P:NvUbdIzc                $B46A:20 54 B8  JSR $B854
Is this an example of what I'm looking for? Hopefully I'm not a million miles away this time. My temptation would be to find that code in the rom and start playing around with it. Any other suggestions for what I can meaningfully do next other than just randomly playing around with the data in that section of the ram/rom? Random experimentation has served me well so far, but I'd like to learn the more efficient methods.

Conversely, Chicken Knife, you've got access to all the tools and information you need to figure out what an unfamiliar block of code does; spending a little more time getting familiar with the tools and absorbing the information will make you both more efficient and more effective at working with code.
Always looking for more of this stuff. I've found some youtube videos infinitely helpful in the past. The combination of hearing an explanation and seeing things done visually has worked wonders for me. I haven't found much in that format (or any other format, tbh) for Trace Logger activity specifically. I'm curious if you or others have any suggestions that would help me learn to look at the flow of code in the trace log and glean a sense of what it pertains to. I can read through the individual operations, looking up the ones I'm foggy on, but I seem to have an almost impossible time seeing the forest through the trees. I'm not sure what would help me with that, and I'm very much open to suggestions.

I had actually removed the Erdrick restriction for myself a while ago.

http://www.romhacking.net/hacks/5162/

I left some notes in the download if anyone felt like modifying the check for themselves.

I've copied them here for convenience. They're inside the spoiler.
Darrman, I thank you for your eagerness to help. As storall says, I do want to go through the steps of finding this, arduous as they may be, so I am opting not to look closely at what you shared for now. I figure that a relatively small item to fix like this provides a better learning opportunity than some of the more complex things I want to mess with soon after, so I want to stick to the processes that others have recommended.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 30, 2020, 06:13:24 am
This code that you posted doesn't look like name checking either. Code you are looking for has to load/compare values from 0009-000F. At least post code that does it.

Searching for 000F in log is a good approach. You couldn't find it because your log probably wasn't correct, but I can't tell what it is exactly. Try searching for other addresses from the range.

Log comparsion is also a good approach, but logs should be as equal as possible to make it easier for you. Write Erdrick and move cursor to End or something, pause emulator and make a savestate. Then manually change the last character in ram to a different byte and save to another savestate while still paused. Don't unpause, disable breakpoints, load save, launch log, hold confirm button, press frame advance hotkey several times for tracer to do his stuff. Save log, and do the same with another savestate, then compare 2 logs. Search for where instructions begin to differ.

You can mix it up with code/data logger. Clear it and run it before hitting End, hold turbo hotkey to speed up, wait until it stops finding new data, pause cdlogger but don't close it, and enable "only log new code" checkmark in tracer. Log will be much lighter.

And you still have my way of doing things.
Quote
While entering a name, set read breakpoint to 0009, and forbid every location where it triggers. Then confirm entered name, and one of the new breakpoint hits is gonna be what you are looking for.
Post screenshots from debugger of these new hits, and I can tell which one is correct.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on July 30, 2020, 09:08:10 am
(removed wrong advice)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on July 31, 2020, 05:39:57 am
I tried to find this code myself, and the very first hit of 000F breakpoint when I clicked End hits the spot. So I don't know what all the fuss is about.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on July 31, 2020, 08:33:28 am
(low-quality post; content removed)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 01, 2020, 12:06:08 am
Guys, sorry I can take a couple days to get back. Full time job, full time dad, other obligations, etc. With something I find really unfamiliar and challenging like this, I need at least a couple hours to totally focus on what I'm doing, along with being in the right mental state. It's not like script and graphics stuff that I can work on in much smaller chunks of time or in a less than ideal condition.

But I have some great news to report.

Quote
Log comparsion is also a good approach, but logs should be as equal as possible to make it easier for you. Write Erdrick and move cursor to End or something, pause emulator and make a savestate. Then manually change the last character in ram to a different byte and save to another savestate while still paused. Don't unpause, disable breakpoints, load save, launch log, hold confirm button, press frame advance hotkey several times for tracer to do his stuff. Save log, and do the same with another savestate, then compare 2 logs. Search for where instructions begin to differ.
This advice from Cyneprepou4uk was extremely helpful. Thank you! I was able to use it to create logs that exactly matched other than the points of divergence. And voila, I found the code:

Code: [Select]
f15769  A:B7 X:00 Y:70 S:EC P:NvUBdIzC                    $BB26:20 FB BB  JSR $BBFB
f15769  A:B7 X:00 Y:70 S:EA P:NvUBdIzC                      $BBFB:A2 00     LDX #$00
f15769  A:B7 X:00 Y:70 S:EA P:nvUBdIZC                      $BBFD:B5 09     LDA $09,X @ $0009 = #$29
f15769  A:29 X:00 Y:70 S:EA P:nvUBdIzC                      $BBFF:C9 00     CMP #$00
f15769  A:29 X:00 Y:70 S:EA P:nvUBdIzC                      $BC01:D0 07     BNE $BC0A
f15769  A:29 X:00 Y:70 S:EA P:nvUBdIzC                      $BC0A:C9 29     CMP #$29
f15769  A:29 X:00 Y:70 S:EA P:nvUBdIZC                      $BC0C:F0 05     BEQ $BC13
f15769  A:29 X:00 Y:70 S:EA P:nvUBdIZC                      $BC13:E8        INX
f15769  A:29 X:01 Y:70 S:EA P:nvUBdIzC                      $BC14:B5 09     LDA $09,X @ $000A = #$36
f15769  A:36 X:01 Y:70 S:EA P:nvUBdIzC                      $BC16:C9 36     CMP #$36
f15769  A:36 X:01 Y:70 S:EA P:nvUBdIZC                      $BC18:F0 05     BEQ $BC1F
f15769  A:36 X:01 Y:70 S:EA P:nvUBdIZC                      $BC1F:E8        INX
f15769  A:36 X:02 Y:70 S:EA P:nvUBdIzC                      $BC20:B5 09     LDA $09,X @ $000B = #$28
f15769  A:28 X:02 Y:70 S:EA P:nvUBdIzC                      $BC22:C9 28     CMP #$28
f15769  A:28 X:02 Y:70 S:EA P:nvUBdIZC                      $BC24:F0 05     BEQ $BC2B
f15769  A:28 X:02 Y:70 S:EA P:nvUBdIZC                      $BC2B:E8        INX
f15769  A:28 X:03 Y:70 S:EA P:nvUBdIzC                      $BC2C:B5 09     LDA $09,X @ $000C = #$36
f15769  A:36 X:03 Y:70 S:EA P:nvUBdIzC                      $BC2E:C9 36     CMP #$36
f15769  A:36 X:03 Y:70 S:EA P:nvUBdIZC                      $BC30:F0 05     BEQ $BC37
f15769  A:36 X:03 Y:70 S:EA P:nvUBdIZC                      $BC37:E8        INX
f15769  A:36 X:04 Y:70 S:EA P:nvUBdIzC                      $BC38:B5 09     LDA $09,X @ $000D = #$2D
f15769  A:2D X:04 Y:70 S:EA P:nvUBdIzC                      $BC3A:C9 2D     CMP #$2D
f15769  A:2D X:04 Y:70 S:EA P:nvUBdIZC                      $BC3C:F0 05     BEQ $BC43
f15769  A:2D X:04 Y:70 S:EA P:nvUBdIZC                      $BC43:E8        INX
f15769  A:2D X:05 Y:70 S:EA P:nvUBdIzC                      $BC44:B5 09     LDA $09,X @ $000E = #$27
f15769  A:27 X:05 Y:70 S:EA P:nvUBdIzC                      $BC46:C9 27     CMP #$27
f15769  A:27 X:05 Y:70 S:EA P:nvUBdIZC                      $BC48:F0 05     BEQ $BC4F
f15769  A:27 X:05 Y:70 S:EA P:nvUBdIZC                      $BC4F:E8        INX
Breakpoint 0 Hit at $BC50: $000F:ECR---
This time I don't have to ask if this is the right stuff because I used it to replace the ERDRICK/erdrick comparison with ROTO/roto[00][00][00].

And it works, hallelujah!

But the best part wasn't the result, it was the feeling as if scales had fallen from my eyes when I analyzed the flow of code and actually understood what it was doing with the CMP and BEQ commands.

I'm sure i'll be drowning in confusion a thousand times over with this stuff as time goes on, but that epiphany feeling was huge. I really appreciate everyone's support through this process of discovery.

Quote
While entering a name, set read breakpoint to 0009, and forbid every location where it triggers. Then confirm entered name, and one of the new breakpoint hits is gonna be what you are looking for.
Cyneprepou4uk, I'm still very foggy on the forbid concept. I don't really understand what I would have plugged in as forbid breakpoints according to your method. What exactly is being forbidden? You say to forbid every location where it triggers? I really don't understand that at all, and a longer explanation would be appreciated so that I can use this technique in the future.

Quote
Which is why I'm not understanding what part of the process is there some miscommunication. Thinking we must be overlooking some basic part of the debugging procedure that Chicken Knife is getting tripped up on (and we take for granted).
And to answer this question, storall, the biggest problem for me was simply being confronted by appx 150,000 lines of almost completely unfamiliar code in trace logs with only the vaguest idea of what I was looking for. The comparison process where all the timing stuff matches was really helpful, but after finding what I wanted (essentially right before and after the first breakpoint trigger) the location of it seemed kind of obvious. It was a million miles away from obvious before I found it, so what can I say? Like most of the other things I've learned so far in romhacking, before you understand it, it seems impossible. And after you understand it, it seems kind of easy and you can't believe you found it so difficult.

Anyway, I think I want to take a look at the next thing: disabling the code that causes you to earn an extra 25% gold and experience from defeating monsters in the English version. To approach this, I imagine I would initiate the trace log recording exactly after defeating enemies and earning the reward, but more specificity there would probably help. I could probably set up matching trace logs between the Japanese and English versions for comparison purposes, although I wouldn't have the luxury of doing the save state thing for a perfect syncing of trace logs. Next, I'm not sure what the code would look like that does this, but I imagine some kind of arithmetic is involved. Any advice or tips would be helpful. If everyone remains feeling generous, I'd love a similar kind of support that helps me along with the investigative process without handing me the answer.

Thank you all again!
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 01, 2020, 04:17:53 am
Quote
The part that wasn't so easy was getting 10,000 hits on that breakpoint and not being able to make heads or tails of which one was relevant.

I assumed that you got a bunch of unrelevant hits during name input, so forbidding them would disable those hits while still having read breakpoint enabled, which would reveal a proper hit after clicking End since code for checking name must be in a different location.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 01, 2020, 09:09:08 am
I assumed that you got a bunch of unrelevant hits during name input, so forbidding them would disable those hits while still having read breakpoint enabled, which would reveal a proper hit after clicking End since code for checking name must be in a different location.
Two questions.

What bytes would I potentially key in for the forbids? Is it the code address in ram that's doing the reading resulting in the bad hit?

Also, I assume that the only way I would know they are bad hits is if I am able to sift through the code and come to that conclusion. So forbid entries are only valuable if I am able to conclusively determine that. It's just a way of skipping past the stuff that you know is wrong in order to more quickly arrive at the right one, correct?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 01, 2020, 10:12:30 am
I feel like a bad educator; one more chance.

(low-quality post; content removed)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 01, 2020, 10:35:35 am
I feel like a bad educator; one more chance.

---------------

How to make 150% exp

1. Find ram address (wiki, cheats, search)
2. Save game before killing monster
3. Put 'Write' breakpoint on addr
4. Play game. Trigger.
5. Add code (lda - lsr - ... - sta)


You likely know this already and this portion will wipe in few days.

----------------

How to make forbid breakpoint

1. Enter DW3 name screen
2. Add breakpoint 1 ($09 - read)
3. Trigger.
4. $06:BA39 = no. Discard.
5. Edit breakpoint 1 (forbid = yes, condition: K==#6&&P==$BA39)
6. Repeat until debugger quiet

----------------

If post self-rated low quality, will wipe later.

----------------

Yes.
storall, don't sweat imperfection! Any help is good help. It's very hard for me to perfectly convey and for you guys to perfectly understand every nuance of what I grasp and what I don't grasp at any given point. I think this is more of a throw it to the wall and see what sticks situation.

For the gold/xp calculation, i'm not looking to increase the reward to 150%. I'm looking to remove the 25% boost already present in the English localization of the game that was not present in the Japanese version. If you look up monster gold and xp values in the game, they reflect the Japanese values, but the game is applying an algorithm to increase them. For my delocalized project, I'll include an optional patch to revert the earning rates back to that of the standard English versions, but I want the base patch to have the Japanese earning rates and therefore be a little grindier. Since it seems like I'll be removing code here, your last step wouldn't seem to apply: 5. Add code (lda - lsr - ... - sta). But if it did apply, I would assume that there may not be space for adding code. That would require me to make use of an assembler, no? If I'm removing code, I could potentially replace the removed code with NOP instructions, right?

And thank you for the forbid steps. I'll have to play with that and see if I can get it working.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 01, 2020, 10:51:01 am
Two questions.

What bytes would I potentially key in for the forbids? Is it the code address in ram that's doing the reading resulting in the bad hit?

Also, I assume that the only way I would know they are bad hits is if I am able to sift through the code and come to that conclusion. So forbid entries are only valuable if I am able to conclusively determine that. It's just a way of skipping past the stuff that you know is wrong in order to more quickly arrive at the right one, correct?

Not sure I understand the first question. Rephrase it.



Yes, usually you need to look at the code to decide that. But sometimes you need to be guided by logic. Some ingame checks, like name checking for example, is very unlikely executed every single frame, it has to do so only after pressing End. Which means that all other breakpoint hits that you could encounter before pressing End are unrelevant by default.

Forbidding doesn't always work. In worst cases you don't encounter new hits after forbidding everything when you perform some action in the game. Which means that one of those forbidden locations was actually correct. Then you need to unforbid them one by one and test them by changing code, byte in ram, etc.



Quote
5. Edit breakpoint 1 (forbid = yes
Forbid checkmark disables RWX condition, so creating such a breakpoint is useless. Not to mention that forbid only works for code execution location, and not for reading/writing.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 01, 2020, 11:19:14 am
Quote
Forbid checkmark disables RWX condition, so creating such a breakpoint is useless. Not to mention that forbid only works for code execution location, and not for reading/writing.

Right, I'm being a moron. I'll redo the guide.


How to make forbid breakpoint

1. Enter DW3 name screen

2. Add breakpoint ($09 - read)
3. Trigger.
4. $06:BA39 = no I don't want this. discard.
5. Edit breakpoint
- forbid = yes
- address = BA39
- condition = K==#6
6. Add new breakpoint ($09 - read)

x. Repeat steps 2-6 as needed.

-------------------

Quote
For the gold/xp calculation, i'm not looking to increase the reward to 150%. I'm looking to remove the 25% boost already present in the English localization of the game that was not present in the Japanese version.

It was my sad, indirect attempt to to be smart. Knowing that the steps to remove the 125% gain are nearly the same procedure, I was hoping that maybe you'd go through the steps anyway, see how they're similar, and figure out the correct nop(s) to reverse the 125% math to 100%.

But again, another teaching failure.

-------------------

Quote
What bytes would I potentially key in for the forbids? Is it the code address in ram that's doing the reading resulting in the bad hit?

I think he means "how do I prevent debugger from breakpoint at this spot again in future?"

Clearly I shouldn't be explaining anything in future.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 01, 2020, 11:38:42 am
4 clicks for 1 forbid breakpoint
https://i.imgur.com/tQokfqt.gif
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 01, 2020, 11:45:58 am
Quote
How to make 150% exp

1. Find ram address (wiki, cheats, search)
2. Save game before killing monster
3. Put 'Write' breakpoint on addr
4. Play game. Trigger.
5. Add code (lda - lsr - ... - sta)
I just read that wrong, my bad. It's a good alternate case that could help me figure out how to remove the 25%

Quote
I think he means "how do I prevent debugger from breakpoint at this spot again in future?"
Yes, that is the goal, but I was really asking about what the input on the screen looks like. There are two sections, a left box allowing for two bytes and a right box allowing for two bytes. I haven't used the right box yet. Am I filling that one now?

Quote
But again, another teaching failure.
It feels like you are very inclined to torment yourself over the smallest things that no one else is bothered by. I'm definitely impressed by your hacking knowledge, and it is helpful. I don't want to see you beat yourself up over some unrealistic standard of perfect teaching. Trust me, even if I had the most perfect teacher in the world, I would still not get it at times. I've already demonstrated that a ton of times, but I'm not gonna let that torment me.


Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 01, 2020, 12:32:21 pm
The part I dislike about giving bad advice is that it creates more confusion, which wastes everyone's time, and turns me into a grumpy cat trying to undo that mistake. Repeat enough times and it becomes an annoying something I want fixed before I get old.


Part of this problem here is that I'm the one just lazy enough to not post good pictures of what I'm doing. Which would help a lot.

--------------------

Quote
There are two sections, a left box allowing for two bytes and a right box allowing for two bytes. I haven't used the right box yet. Am I filling that one now?

If we are not talking about the 'Add Breakpoint' box, then ignore this next part.

Because it's just 1 value, I still use the left box only. If we had to block a range of addresses, then we use the right side.

Let's say I want to forbid $03:8000-9FFF because I hate that stopping on that code.
- Left box = 8000
- Right box = 9FFF
- Forbid = yes
- Condition = K==#3


If it's some other debugger feature, could you upload a picture or what step you're getting held on?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 02, 2020, 02:29:59 pm
4 clicks for 1 forbid breakpoint
https://i.imgur.com/tQokfqt.gif
This animation was great. I didn't know I could right click the lines of code on the left hand side.

Let's say I want to forbid $03:8000-9FFF because I hate that stopping on that code.
- Left box = 8000
- Right box = 9FFF
- Forbid = yes
- Condition = K==#3
So the right box is a range. That should have been intuitive to me.

Quote
1. Find ram address (wiki, cheats, search)
2. Save game before killing monster
3. Put 'Write' breakpoint on addr
4. Play game. Trigger.
5. Add code (lda - lsr - ... - sta)
I'm trying to work on tracking down the gold or xp values so I can write my breakpoint. According to the data crystal ROM map, I know exactly how all the attributes of a monster including XP and gold are stored. I was expecting to be able to take the sequence of bytes stored in those addresses, search in RAM while in battle, and find the tables there arranged the same way. Sadly, the game doesn't seem to work that way. I can't figure this out, and the RAM map doesn't have any of this. Any tips on how I can figure out where to put my RAM breakpoints?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 02, 2020, 02:47:57 pm
You sure there is nothing at datacrystal about gold and exp addresses for dw3 in ram map? Because I can clearly see it is written here


Quote
I didn't know I could right click the lines of code on the left hand side.

So you say you didn't know, huh?

Quote
You can double click on cpu address where it hits and add a corresponding checkmark.

Quote
Lets say your 0009 breakpoint got hit at 0F:89AB. Double click at 89AB. An "add breakpoint" window will be open, it'll already have 89AB and some condition written there, you just need to enable "forbid" checkmark and press OK.

Obviously you didn't do that for a second time. Or is my english that bad?  >:D
Should I bother to keep explaining anything in the future?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 02, 2020, 04:12:44 pm
You sure there is nothing at datacrystal about gold and exp addresses for dw3 in ram map? Because I can clearly see it is written here
Total experience and gold values for the party are written there, not the experience and gold values for monsters that I was looking for. I was thinking that the algorithm that increases the monster reward values would fire off right after the monster values get read, but perhaps I could assign a write breakpoint to the character experience / gold address and backtrack.

Quote
Obviously you didn't do that for a second time. Or is my english that bad?  >:D
Should I bother to keep explaining anything in the future?
There goes your shitty tone again. Improve it, and I'll find hanging on your every word a great deal easier.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 02, 2020, 04:24:19 pm
Yeah, that's me who have to improve his attitude, coz I'm the one who needs help with hacks  >:D

Quote
Should I bother to keep explaining anything in the future?
I've got my answer.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 02, 2020, 05:04:35 pm
I've got my answer.
You helping here is up to you. I actually did read what you said, and it wasn’t clear to me that you were talking about the left panel. When I’m very foggy on something or overwhelmed with a new and complex program, I need things really spelled out.

But if you are going to stick around here, the expectation is that respectfulness is demonstrated no matter what. Even if you have things to teach and I have things to learn. Even if I’m slow with something. Even if I didn’t read something correctly. Most people understand that belittling language is never acceptable. Other people here have also pointed it out, and you recognizing how you come across at times and learning how to address the same things in a better way would be a big opportunity for your development. Therefore, if you do stick around, I will continue to help you recognize those opportunities.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 02, 2020, 05:24:30 pm
Chicken Knife's new problem is that he doesn't know the procedure of how to convert ROM address to CPU address.


Here's a really quick basic guide. Let's collect our data.

https://datacrystal.romhacking.net/wiki/Dragon_Warrior_III:ROM_map
- Slime EXP, 0x0032E4 = Experience (0-255) = $04

https://datacrystal.romhacking.net/wiki/Dragon_Warrior_III
- Mapper name: MMC1

https://wiki.nesdev.com/w/index.php/MMC1
- CPU $8000-$BFFF: 16 KB PRG ROM bank, either switchable or fixed to the first bank
- CPU $C000-$FFFF: 16 KB PRG ROM bank, either fixed to the last bank or switchable


1. $32E4 file - $10 header = $32d4
- MMC1 says we have $4000 banksize. $32d4 / $4000 = bank 0.
- $32d4 % $4000 = $32d4 offset

2. Our data is hiding at $8000-BFFF or $C000-FFFF
- 8000+32d4 = b2d4
- c000+32d4 = f2d4

3. Add 'Read' breakpoints
- I'll assume you know this by now
- Don't use K==#0 though; that only correctly works when using PC execute breakpoint

4. Note that you'll have to track down the real spot where it gives bonus points.
   It's not as straightforward as I thought and will take a thorough look at the trace log.

5. It might be worthwhile doing this same procedure for Japan also and compare the logs.


edit: Read breakpoint tip

Since we know slime exp value is $04
- Address = $B2D4
- Read = yes
- Condition: $B2D4==#04

Then it won't bp on non-correct values.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 02, 2020, 06:07:37 pm
Quote
Most people understand that belittling language is never acceptable

I wasn't belittling you, I was pointing out that you don't try those things on practice, meaning that I was wasting my time. Because if you did, you would understand what I was talking about. But wasting time is my own fault coz I'm the one who decides to post.

But if you actually did try to see those things in debugger and couldn't find it, then you are a slowpoke who needs to get more experience with debugging and understanding basic nes stuff before going into mega hardcore hacking like changing name check and gold. And this is how my belittling looks like  >:D

Either way I'm done here. Oh, and refresh your memory
http://catb.org/~esr/faqs/smart-questions.html#answers
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 02, 2020, 08:06:49 pm
Chicken Knife - a short diary in case you need another hint.


Encountered 1 Slime outside the castle.
- Saved state before slaying it.
- Report says 6 exp and 3 gold.

Load state and put breakpoint on Slime exp (04).
- On break, turned on trace logger.
- Noticed it had a rts and stepped out.
- It had a 24-bit write to range (-redacted-).
- Checked the RAM wiki https://datacrystal.romhacking.net/wiki/Dragon_Warrior_III:RAM_map but no match.
- Looked interesting so I put a 'Write' breakpoint on (-redacted-)
- Remember that it had a $04

Let the game continue.
- A breakpoint on (-redacted-).
- What's this? A $06 is being stored there. And it's 24-bit again.
- Again another rts so I floated out.
- Now I turned off the trace logger.
- A new area of code.

Time to think!
- So it had $04 and became $06.
- Interesting weird piece of asm but it looks like our bonus math.
- To test, I left-clicked the address I wanted to nop out.

  More specifically, it's that vertical blank column on the left side of address.
  Hover your mouse there and it says on bottom:
    leftclick = inline assembler
    rightclick = hexeditor

- Opened the 'Inline Assembler'. Entered the nop replacement (nop + enter).
  When it looked good, I hit 'apply.' Close box.
  - note: it's temporary and not permanent to rom.

Reload state.
- Now says I gained 4 exp and 3 gold.
- To be honest, I didn't believe it and checked the info stats afterward.
- 4 exp and 53 gold.

Well that's 1 done. Time to bake in asm fix.


edit: And likely I'll need to show you a picture. But that'd give away the answer so have to wait until you find the area.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 03, 2020, 09:46:42 am
@Storall, your posts regarding the steps you took with this process are clear and helpful! I really appreciate you taking the time to spell things out like this. There are a handful of points I'd like to ask for clarification on. I'd like to understand your process outline more completely before I perform the steps myself.

Here are the points to clarify:

Quote
Chicken Knife's new problem is that he doesn't know the procedure of how to convert ROM address to CPU address.
I've actually done a lot of converting ROM to RAM address (which I believe is the same as CPU address since CPU only interacts with RAM other than bank loading / switching) But I'm glad you took the time to discuss this, because it brings up an interesting point:

Quote
- CPU $8000-$BFFF: 16 KB PRG ROM bank, either switchable or fixed to the first bank
- CPU $C000-$FFFF: 16 KB PRG ROM bank, either fixed to the last bank or switchable
All the times I've had to calculate RAM address in my work on DQ1/DQ2/DQ3, I've only ever had to use the $8000-BFFF address range, never the $C000-$FFFF range. I'm glad to be reminded that data could also be stored in the $C000-$FFFF range, because I've become so unaccustomed to never dealing with that area. I've mostly dealt with these addresses for the script, and the script seems to never be stored there curiously.

Quote
2. Our data is hiding at $8000-BFFF or $C000-FFFF
- 8000+32d4 = b2d4
- c000+32d4 = f2d4
It seems like I had the right idea to search the RAM for the sequential bytes that store monster xp&gold, but where I probably failed was that this data wasn't loaded there yet, even though I was in battle when I checked. I'm guessing that the code executes a bankswitch command at some point just before it actually needs that monster reward data, probably because the rest of the time, the code is pulling from the bank that stores miscellaneous battle text. Therefore when I checked for those bytes, it wasn't loaded yet. But after I set these breakpoints, once I get the hit, if I then go check the RAM data, I should find the bytes there.

Quote
- Don't use K==#0 though; that only correctly works when using PC execute breakpoint
You said this in reference to setting the read breakpoint. I'm not sure what K==#0 means and would enjoy some further explanation here.

Quote
It might be worthwhile doing this same procedure for Japan also and compare the logs.
I was planning to do this.  :laugh: One of my tech savvy friends suggested that I could use a text editor compare function that would allow the program itself to compare the two sets of text. That sounds great, but I would probably not be able to achieve perfectly synced timing between the two different versions. I'll do it myself manually, and hopefully I will be able to differentiate between the stuff directly resulting from timing differences.

Quote
- Condition: $B2D4==#04
This sounds like a great tip. Thank you! I'll play with setting the condition.

Now I have some questions regarding your diary:

Quote
- Noticed it had a rts and stepped out.
I know that RTS is a return from subroutine. Two question, why did you react to that, and what does "stepped out" mean? When I get breakpoint hits, I typically only hit the "run" button to have the game go past the break. I see there are other options involving "stepping" but I don't really understand what those mean.

Quote
- Again another rts so I floated out.
Not sure what floated out means.

Quote
- Now I turned off the trace logger.
- A new area of code.

Time to think!
- So it had $04 and became $06.
- Interesting weird piece of asm but it looks like our bonus math.
- To test, I left-clicked the address I wanted to nop out.

  More specifically, it's that vertical blank column on the left side of address.
  Hover your mouse there and it says on bottom:
    leftclick = inline assembler
    rightclick = hexeditor

- Opened the 'Inline Assembler'. Entered the nop replacement (nop + enter).
  When it looked good, I hit 'apply.' Close box.
  - note: it's temporary and not permanent to rom.
I get a little lost here unfortunately. So you start off by analyzing the trace log you created for this second section of code that deals with writing the inflated slime exp. When you say you left clicked the address you wanted to NOP out, you are saying that you left clicked that CPU address on the left side of the debugger screen? If so, I didn't realize that I could rewrite code from that screen directly. Vertical blank column in the debugger? I probably need to be home and working with this to potentially see what you are referring to. It sounds like FCEUX actually has an assembler function. Very cool! It sounds like you just replaced existing bytes in the code with the NOP operations, which didn't require any expansion of the code. That sounds easy enough.

Ok, that's it for questions, and hopefully I'll be able to figure out what you covered in the last paragraph just by playing around. I'm pretty excited to try all this now.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 03, 2020, 10:29:09 am
Quote
You said this in reference to setting the read breakpoint. I'm not sure what K==#0 means and would enjoy some further explanation here.

Let's say I want to place execute breakpoint at $07:C041.
- Address: C041.
- Execute: yes.
- Condition: K==#07. Meaning stop only at PC Bank 07.


In case of DW3, Slime EXP was at $00:B2D4 or $00:F2D4.
- Address: B2D4.
- Read: yes.

- Condition: K==#00. === If we do this though, it will only trigger when PC is bank 00. Which seems to be never during my debugging trial. It will not trigger when reading from $00:B2D4.
- Condition: $B2D4=#04. === This will trigger when reading from $B2D4 and when $B2D4 = 04 (slime exp value).


Quote
I'll do it myself manually, and hopefully I will be able to differentiate between the stuff directly resulting from timing differences.

I should do this also because I want to see what really got added to USA.


Quote
I know that RTS is a return from subroutine. Two question, why did you react to that, and what does "stepped out" mean? When I get breakpoint hits, I typically only hit the "run" button to have the game go past the break. I see there are other options involving "stepping" but I don't really understand what those mean.

I saw a short routine, meaning we came from somewhere else. So I clicked Step Over because I wanted to see in the registers what was happening. When I got out (rts), I saw an interesting clue from the asm code; I could tell what that meant and it looked important to investigate.


Quote
Not sure what floated out means.

"Floated out" = I clicked Step until I reached the rts and "jumped" somewhere else.


Quote
So you start off by analyzing the trace log you created for this second section of code that deals with writing the inflated slime exp.

Correct. Once I saw the $06 being written, I figured it was safe to stop. I read the asm code at the stop point and thought .. hmm .. interesting, it's 24-bit value.

Took a picture of my Castlevania 2 debugging session. The highlighted red box is where to click the mouse.
(https://github.com/storall/Bucket/raw/master/FCEUX/fceux_assembler.PNG) (https://github.com/storall/Bucket/raw/master/FCEUX/fceux_assembler2.PNG)

I'll explain more later.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on August 03, 2020, 05:19:23 pm
Out of curiosity, where did you get that 25% number for extra gold and experience from? The English version appears to be adding different percentages for gold and experience, and neither of them is 25%.

- Condition: K==#00. === If we do this though, it will only trigger when PC is bank 00. Which seems to be never during my debugging trial. It will not trigger when reading from $00:B2D4.
One extra point here: if you know your data is in bank 0, you might like to set a T==#00 condition on a read breakpoint; the Debugger page of FCEUX's help file explains what T and K mean in the context of breakpoint conditions.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 03, 2020, 05:36:03 pm
Quote from: abw
One extra point here: if you know your data is in bank 0, you might like to set a T==#00 condition on a read breakpoint; the Debugger page of FCEUX's help file explains what T and K mean in the context of breakpoint conditions.

Thank you! I completely missed that helpful bullet point.

Quote from: manual
Break only when accessing a data from bank 2 (the condiition is relevant when using with Read/Write-type breakpoints):

T==#2


I got lazy and read the abbreviated online wiki manual, which doesn't cover that one.
http://wiki.nesdev.com/w/index.php/FCEUX_debugger
(This page was last modified on 8 September 2012, at 07:27)


Quote from: abw
Out of curiosity, where did you get that 25% number for extra gold and experience from? The English version appears to be adding different percentages for gold and experience, and neither of them is 25%.

I wondered the same thing. :lol:

August 03, 2020, 06:47:50 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
I hacked Slime to have base 256 exp. Got 342 after battle. Seems like 133%.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 03, 2020, 11:46:43 pm
@storall,
This is a heavy duty process and will clearly take me multiple days to sort out. Most of my time tonight was spent fiddling around with the debugger, which is something I've barely done up until now. I'm finally understanding all the step commands, how to use them to move through the code, understanding how everything I'm seeing matches up to the RAM storage, etc. I'm hoping that investing this time getting a feel for the system and looking up opcodes will improve recognition. At this point, I don't think I need more tips. I need more time to debug, log, document, learn and process all this. I'm clearly getting the sense that dealing with this code will be more complex than the ERDRICK comparison routine, and I want to be ready.

Quote
Out of curiosity, where did you get that 25% number for extra gold and experience from? The English version appears to be adding different percentages for gold and experience, and neither of them is 25%.
It would seem that "The Cutting Room Floor" site has finally let me down. It has otherwise proven itself to be quite reliable. https://tcrf.net/Dragon_Warrior_III_(NES) (https://tcrf.net/Dragon_Warrior_III_(NES))
"EXP and gold drops were increased by 25% in the North American version."

About FCEUX help, I have the latest version of FCEUX, I click the help menu, I select a topic, I click display, and nothing happens. That's been driving me crazy for a while. I've also found that HTML help site, but it really doesn't have much at all. I would love to figure out how to access the thorough HELP material. Pretty friggin' sad when you can't even figure out how to access the HELP documentation.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: storall on August 04, 2020, 12:09:26 am
Quote
About FCEUX help, I have the latest version of FCEUX, I click the help menu, I select a topic, I click display, and nothing happens. That's been driving me crazy for a while. I've also found that HTML help site, but it really doesn't have much at all. I would love to figure out how to access the thorough HELP material. Pretty friggin' sad when you can't even figure out how to access the HELP documentation.

https://github.com/TASVideos/fceux
https://ci.appveyor.com/project/zeromus/fceux
https://ci.appveyor.com/project/zeromus/fceux/builds/34463273
https://ci.appveyor.com/project/zeromus/fceux/build/job/4kdrl5nrxt0duixe/artifacts
- download zip
- open file: fceux.chm


Quote
This is a heavy duty process and will clearly take me multiple days to sort out. Most of my time tonight was spent fiddling around with the debugger, which is something I've barely done up until now. I'm finally understanding all the step commands, how to use them to move through the code, understanding how everything I'm seeing matches up to the RAM storage, etc. I'm hoping that investing this time getting a feel for the system and looking up opcodes will improve recognition. At this point, I don't think I need more tips. I need more time to debug, log, document, learn and process all this. I'm clearly getting the sense that dealing with this code will be more complex than the ERDRICK comparison routine, and I want to be ready.

Very understandable! I think you are progressing. This problem is more complicated than ERDRICK.

Getting that read breakpoint to work for EXP is your major goal. Then I think the rest will slowly fall into place.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 04, 2020, 05:31:37 am
Quote
That's been driving me crazy for a while

Unblock fceux.chm in file properties.

If you're looking for detailed debugger documentation, I've got most of it on my site.
https://iromhacker.ru/nes/ru/fceux/debug/debugger/1/index.html
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 05, 2020, 12:11:32 am
I created savestates between the English and Japanese versions, both with only the hero killing 1 slime. I figured out the different RAM address of the Japanese version for the read breakpoint of the 04 value, and I created two nearly identical log files. Other than a very brief divergence that occurred right after the break, the below is where the English version really goes off into its own territory. I'm looking closely at it 1. because of the divergence, and 2. because I see 04 and then 06 getting loaded into the X register.

Code: [Select]
f37361  A:01 X:00 Y:01 S:CC P:nVUBdIZc                    $B4EB:B5 F7     LDA $F7,X @ $00F7 = #$04
f37361  A:04 X:00 Y:01 S:CC P:nVUBdIzc                    $B4ED:C9 FF     CMP #$FF
f37361  A:04 X:00 Y:01 S:CC P:nVUBdIzc                    $B4EF:F0 0E     BEQ $B4FF
f37361  A:04 X:00 Y:01 S:CC P:nVUBdIzc                    $B4F1:A9 FE     LDA #$FE
f37361  A:FE X:00 Y:01 S:CC P:NVUBdIzc                    $B4F3:95 F7     STA $F7,X @ $00F7 = #$04
f37361  A:FE X:00 Y:01 S:CC P:NVUBdIzc                    $B4F5:20 07 B7  JSR $B707
f37361  A:FE X:00 Y:01 S:CA P:NVUBdIzc                      $B707:E0 06     CPX #$06
f37361  A:FE X:00 Y:01 S:CA P:NVUBdIzc                      $B709:B0 12     BCS $B71D
f37361  A:FE X:00 Y:01 S:CA P:NVUBdIzc                      $B70B:AD F3 06  LDA $06F3 = #$FF
f37361  A:FF X:00 Y:01 S:CA P:NVUBdIzc                      $B70E:C9 FF     CMP #$FF
f37361  A:FF X:00 Y:01 S:CA P:nVUBdIZC                      $B710:F0 0B     BEQ $B71D
f37361  A:FF X:00 Y:01 S:CA P:nVUBdIZC                      $B71D:18        CLC
f37361  A:FF X:00 Y:01 S:CA P:nVUBdIZc                      $B71E:60        RTS (from $B707) ---------------------------
f37361  A:FF X:00 Y:01 S:CC P:nVUBdIZc                    $B4F8:90 05     BCC $B4FF
f37361  A:FF X:00 Y:01 S:CC P:nVUBdIZc                    $B4FF:D6 E2     DEC $E2,X @ $00E2 = #$03
f37361  A:FF X:00 Y:01 S:CC P:nVUBdIzc                    $B501:D0 DF     BNE $B4E2
(1 lines skipped)
f37361  A:FF X:00 Y:01 S:CE P:nVUBdIzc                  $B3B2:A2 02     LDX #$02
f37361  A:FF X:02 Y:01 S:CE P:nVUBdIzc                  $B3B4:20 DE B4  JSR $B4DE
(23 lines skipped)
f37361  A:FF X:02 Y:01 S:CE P:nVUBdIzc                  $B3B7:A2 04     LDX #$04
f37361  A:FF X:04 Y:01 S:CE P:nVUBdIzc                  $B3B9:20 DE B4  JSR $B4DE
(23 lines skipped)
f37361  A:FF X:04 Y:01 S:CE P:nVUBdIzc                  $B3BC:A2 06     LDX #$06
f37361  A:FF X:06 Y:01 S:CE P:nVUBdIzc                  $B3BE:88        DEY
f37361  A:FF X:06 Y:00 S:CE P:nVUBdIZc                  $B3BF:20 DE B4  JSR $B4DE
(7 lines skipped)
f37361  A:00 X:06 Y:00 S:CE P:nVUBdIzc                  $B3C2:AD 7C 04  LDA $047C = #$BE
f37361  A:BE X:06 Y:00 S:CE P:NVUBdIzc                  $B3C5:C9 6A     CMP #$6A
f37361  A:BE X:06 Y:00 S:CE P:nVUBdIzC                  $B3C7:90 DE     BCC $B3A7
f37361  A:BE X:06 Y:00 S:CE P:nVUBdIzC                  $B3C9:A2 06     LDX #$06
f37361  A:BE X:06 Y:00 S:CE P:nVUBdIzC                  $B3CB:A1 D6     LDA ($D6,X) @ $AF5B = #$E1
f37361  A:E1 X:06 Y:00 S:CE P:NVUBdIzC                  $B3CD:49 FC     EOR #$FC
f37361  A:1D X:06 Y:00 S:CE P:nVUBdIzC                  $B3CF:F0 0E     BEQ $B3DF
f37361  A:1D X:06 Y:00 S:CE P:nVUBdIzC                  $B3D1:CA        DEX
f37361  A:1D X:05 Y:00 S:CE P:nVUBdIzC                  $B3D2:CA        DEX
f37361  A:1D X:04 Y:00 S:CE P:nVUBdIzC                  $B3D3:10 F6     BPL $B3CB
f37361  A:1D X:04 Y:00 S:CE P:nVUBdIzC                  $B3CB:A1 D6     LDA ($D6,X) @ $AF0D = #$FA
(5 lines skipped)
f37361  A:06 X:02 Y:00 S:CE P:nVUBdIzC                  $B3CB:A1 D6     LDA ($D6,X) @ $AE6A = #$FA
(5 lines skipped)
f37361  A:06 X:00 Y:00 S:CE P:nVUBdIZC                  $B3CB:A1 D6     LDA ($D6,X) @ $ADC0 = #$30
(5 lines skipped)
f37361  A:CC X:FE Y:00 S:CE P:NVUBdIzC                  $B3D5:A2 06     LDX #$06
f37361  A:CC X:06 Y:00 S:CE P:nVUBdIzC                  $B3D7:B5 E2     LDA $E2,X @ $00E8 = #$02
f37361  A:02 X:06 Y:00 S:CE P:nVUBdIzC                  $B3D9:D0 04     BNE $B3DF
f37361  A:02 X:06 Y:00 S:CE P:nVUBdIzC                  $B3DF:C9 00     CMP #$00
f37361  A:02 X:06 Y:00 S:CE P:nVUBdIzC                  $B3E1:F0 07     BEQ $B3EA
f37361  A:02 X:06 Y:00 S:CE P:nVUBdIzC                  $B3E3:A9 DF     LDA #$DF
f37361  A:DF X:06 Y:00 S:CE P:NVUBdIzC                  $B3E5:2D 7F 04  AND $047F = #$D0
f37361  A:D0 X:06 Y:00 S:CE P:NVUBdIzC                  $B3E8:B0 05     BCS $B3EF
f37361  A:D0 X:06 Y:00 S:CE P:NVUBdIzC                  $B3EF:8D 7F 04  STA $047F = #$D0
f37361  A:D0 X:06 Y:00 S:CE P:NVUBdIzC                  $B3F2:A2 00     LDX #$00
f37361  A:D0 X:00 Y:00 S:CE P:nVUBdIZC                  $B3F4:A0 00     LDY #$00
f37361  A:D0 X:00 Y:00 S:CE P:nVUBdIZC                  $B3F6:20 1F B7  JSR $B71F
f37361  A:D0 X:00 Y:00 S:CC P:nVUBdIZC                    $B71F:20 07 B7  JSR $B707
(7 lines skipped)
f37361  A:FF X:00 Y:00 S:CC P:nVUBdIZc                    $B722:BD 73 04  LDA $0473,X @ $0473 = #$B0
f37361  A:B0 X:00 Y:00 S:CC P:NVUBdIzc                    $B725:B0 02     BCS $B729
f37361  A:B0 X:00 Y:00 S:CC P:NVUBdIzc                    $B727:30 50     BMI $B779
f37361  A:B0 X:00 Y:00 S:CC P:NVUBdIzc                    $B779:60        RTS (from $B71F) ---------------------------

There is nothing as intuitive for me here so far as what I found with the compare operations for the ERDRICK name, but I was already warned that this would be the case. There's also a decent chance I am not even close here.

Quote
- What's this? A $06 is being stored there. And it's 24-bit again.
I've tried to follow this clue and determine what a 24 bit range looks like. As I look through the code, I can't seem to find any operations with longer than a 16 bit range. Would an operation with a 24 bit operand look like four bytes together? That's what I've looked for.

I still feel like I'm not particularly close to solving this, but I have spent another several hours studying operations and learning about bitwise functions like AND, OR, etc. Hopefully I'm getting something out of spending time like this.

Also, a question about the inline assembler. Is there any real difference between inserting the NOP instructions there or just finding the corresponding bytes in a hex editor and just replacing them with EA? I'm curious.

Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 05, 2020, 05:01:53 am
24-bit means some game value (up to 16,7 million) is stored in 3 ram addresses, usually neighboring.

No difference between NOP and EA at all. But you can't undo inline assembler
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Euyira on August 05, 2020, 08:39:50 am
Quote from: Chicken Knife
2. because I see 04 and then 06 getting loaded into the X register.

I did not do exercise but from carefully reading thread you might be off.


Quote from: storall
- It had a 24-bit write to range (-redacted-).
      ..
- A breakpoint on (-redacted-).
- What's this? A $06 is being stored there. And it's 24-bit again.

@storall saw $04 write to RAM xx+0, xx+1, xx+2. And then $06 write to RAM xx+0, xx+1, xx+2. Posted log shows no $04 or $06 writes.


Quote from: Chicken Knife
1. because of the divergence

Did you accidentally skip past the answer? What did log look like at breakpoint when EXP was read?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 05, 2020, 01:37:56 pm
Ok, I assume that a write command would be an STA, a STY or a STX, followed by a memory address. I would want to see the $04 or the $06 in one of the registers prior to that store command, and then see the store command execute writing it to a 3 byte (24 bit) memory space. This concept confuses me because I don't see why the game would need a 3 byte space to store a one byte value.

**EDIT Thinking through this more carefully, I realize that the game would definitely need a wider space for XP storage since there are creatures that provide 5 digit experience values.

But in any case, I was looking for something like STA $16 BA 24 as an example of the formatting. Did not see this in my logs. But I will take another more careful look tonight.

Quote
RAM xx+0, xx+1, xx+2.
I'm pretty confused by this. What does the +0 / +1 / +2 mean? I think seeing a hypothetical example of what I'm looking for would be helpful.

Quote
Did you accidentally skip past the answer? What did log look like at breakpoint when EXP was read?
There was a small variance between the English and Japanese logs just a handful of lines after the breakpoint for the first read of $04. I'll look at it again, but I didn't see any evidence of a 3 byte (24 bit) write command.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 05, 2020, 03:30:37 pm
How many instructions does debugger execute between hits of read breakpoint for enemy exp and write breakpoint for your exp? Number is below flags in brackets
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Euyira on August 05, 2020, 06:46:06 pm
By time this message is approved by moderator, Cyneprepou4uk has already provided the answers.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 05, 2020, 07:23:52 pm
How many instructions does debugger execute between hits of read breakpoint for enemy exp and write breakpoint for your exp? Number is below flags in brackets
English version:  +3902477 instructions
Japanese version: +3902646 instructions

Trace Logger seems to be skipping lines interestingly. It wasn't doing this when I was working on the ERDRICK check, but if it's filtering out timing stuff, that's fine by me.
English trace log has 3809 lines
Japanese trace log has 3907 lines

It's interesting that the Japanese operations are greater in quantity. I would have expected it to be the other way based on the routine introduced for increasing the values.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 05, 2020, 07:36:43 pm
That's a lot, I was hoping these hits will happen during the same frame. Ok, never mind.

Tracer skips lines if you have "log only new code" checkmark enabled.



Find out which one of 3 exp adresses triggers last (probably it has to be address with highest exp digits) when you gain exp, and post several dozens of log lines before that last trigger happens.

Also post some log from code which reads enemy exp addresses.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 05, 2020, 08:30:06 pm
Maybe it's easier if I just link to the complete English & Japanese trace logs.

https://www.dropbox.com/sh/20kwx353wplbcv4/AADvP7VMwqumHZhlwonKv928a?dl=0

They both begin with reading 04 experience from the Slime data and end at the write operation to the first byte of character experience.

I did another scan through the English log and all the operations I saw were either 1, 2 or 3 bytes total. I didn't see anything with a 1 byte operation and a 3 byte operand.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 05, 2020, 09:08:35 pm
NES doesn't have instructions with 3 byte operands. And even if it had, it wouldn't make much difference in your case, because you can load/write only 1 address at a time, not 3 at once.

Exp is stored at 0744-0746. 3 addresses (24 bits). Initially you have 000000 exp. When you kill a slime, you gain 0004 exp by default. So 000000 + 0004 = 000004. If for example you currently had 00FFFF exp, your total would be 00FFFF + 0004 = 010003 exp. Note that game stores exp in little-endian, so it would actually look like 03 00 01.

Lets look at the last lines of jap log. Loop copies 0744-0746 (current exp) into 0004-0006 (temp addresses).
Code: [Select]
f19031  A:80 X:00 Y:34 S:E0 P:NvUBdizc                                $956A:A0 00     LDY #$00
f19031  A:80 X:00 Y:00 S:E0 P:nvUBdiZc                                $956C:BD 44 07  LDA $0744,X @ $0744 = #$FE
f19031  A:FE X:00 Y:00 S:E0 P:NvUBdizc                                $956F:99 04 00  STA $0004,Y @ $0004 = #$80
f19031  A:FE X:00 Y:00 S:E0 P:NvUBdizc                                $9572:E8        INX
f19031  A:FE X:01 Y:00 S:E0 P:nvUBdizc                                $9573:C8        INY
f19031  A:FE X:01 Y:01 S:E0 P:nvUBdizc                                $9574:C0 03     CPY #$03
f19031  A:FE X:01 Y:01 S:E0 P:NvUBdizc                                $9576:D0 F4     BNE $956C

Then 00CF-00D1 (your gained exp) is added to 0004-0006
Code: [Select]
f19031  A:09 X:03 Y:03 S:E2 P:nvUBdiZC                              $9585:18        CLC
f19031  A:09 X:03 Y:03 S:E2 P:nvUBdiZc                              $9586:A5 04     LDA $0004 = #$FE
f19031  A:FE X:03 Y:03 S:E2 P:NvUBdizc                              $9588:65 CF     ADC $00CF = #$04
f19031  A:02 X:03 Y:03 S:E2 P:nvUBdizC                              $958A:85 04     STA $0004 = #$FE
f19031  A:02 X:03 Y:03 S:E2 P:nvUBdizC                              $958C:A5 05     LDA $0005 = #$B3
f19031  A:B3 X:03 Y:03 S:E2 P:NvUBdizC                              $958E:65 D0     ADC $00D0 = #$00
f19031  A:B4 X:03 Y:03 S:E2 P:NvUBdizc                              $9590:85 05     STA $0005 = #$B3
f19031  A:B4 X:03 Y:03 S:E2 P:NvUBdizc                              $9592:A5 06     LDA $0006 = #$09
f19031  A:09 X:03 Y:03 S:E2 P:nvUBdizc                              $9594:65 D1     ADC $00D1 = #$00
f19031  A:09 X:03 Y:03 S:E2 P:nvUBdizc                              $9596:85 06     STA $0006 = #$09

At 9598 it checks for overflow, but there wasn't any. And finally code writes total exp from 0004-0006 back into 0744-0746.
Code: [Select]
f97711  A:22 X:00 Y:03 S:E2 P:nvUBdIzc                              $95DE:A0 00     LDY #$00
f97711  A:22 X:00 Y:00 S:E2 P:nvUBdIZc                              $95E0:B9 04 00  LDA $0004,Y @ $0004 = #$3E
You didn't log enough here, I expected you to find the last trigger. But it looks basically the same as 956A, so no big deal.



The difference between both version is gained exp
Code: [Select]
eng
$95A9:65 CF     ADC $00CF = #$06

jap
$9588:65 CF     ADC $00CF = #$04

So you need to trace back in the log where value at 00CF is coming from.

Here is an answer for how to disable additional exp if you get tired of this task.
Spoiler:

f97678  A:01 X:5D Y:00 S:EA P:nvUBdIzC                      $8A98:20 CB 8C  JSR $8CCB
f97678  A:01 X:5D Y:00 S:E8 P:nvUBdIzC                        $8CCB:75 00     ADC $00,X @ $005D = #$04
f97678  A:06 X:5D Y:00 S:E8 P:nvUBdIzc                        $8CCD:95 00     STA $00,X @ $005D = #$04
f97678  A:06 X:5D Y:00 S:E8 P:nvUBdIzc                        $8CCF:98        TYA
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CD0:75 01     ADC $01,X @ $005E = #$00
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CD2:95 01     STA $01,X @ $005E = #$00
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CD4:A9 00     LDA #$00
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CD6:75 02     ADC $02,X @ $005F = #$00
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CD8:95 02     STA $02,X @ $005F = #$00
f97678  A:00 X:5D Y:00 S:E8 P:nvUBdIZc                        $8CDA:60        RTS (from $8CCB)

NOP out that JSR $8CCB to disable additional exp
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 06, 2020, 12:08:15 am
@Cyneprepou4uk
Your basic descriptions of those sections of code were helpful. I spent hours reasoning through each step in them to gain familiarity with how these things work, and it was very interesting.

By searching backwards in the log, I followed the trail of gained experience from the CF memory location to the 5D location, where I saw the value there be changed from $04 to $06. At that point, I knew that that was the area where I needed to disable something with EA, and I was looking closely at the operation that added the 1 in the accumulator along with the carry flag to the 04 in 5D to get 06. But based on the other operations attached to that, I felt like disabling just that one line of code would make a mess of things. I was thinking of disabling a whole bunch of lines, but I remembered storall mentioning that he disabled just one. At that point, I looked at your spoiler and realized that yes, disabling the jump into that whole subroutine was the correct way. The code would just pass right over it without anything getting mucked up.

This was a painful but very good exercise. The most important thing I learned was the value of following the trail of data moving from memory location to memory location.

Now, I'm willing to bet that a nearly identical routine exists for increasing the gold. Tomorrow evening, I'm going to follow a very similar set of steps and work to disable that one myself.

Thanks for the support with this.

August 06, 2020, 03:19:18 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Woke up in the middle of the night feeling the need to take a stab at uncovering the gold increase routine, so I did. I had some success following the trail, but I got a bit lost at a point and would like some help.

Here's a link for a new log file that cuts off very slightly after the write to your gold.

https://www.dropbox.com/s/t6xmn6qklagoqx2/log%20before%20and%20after%20slime%20gold%20write%20EDITED.txt?dl=0

My new gold value being written down at the bottom near the break was 55 and that was coming from the RAM address $04. Searching backwards, that 55 value came from 07BC (52 - existing gold) & $CE (3 acquired gold)
Searching backwards, the 3 acquired gold seemed to come from $60 (address 8C0C).
Searching backwards, the 3 in $60 seems to come from $04 again, where it was a value of 02, only changed by the addition of a carry flag. Here's that bit of code that puzzles me:

Code: [Select]
f97657  A:02 X:60 Y:00 S:E8 P:nvUBdIzc                        $C0B5:60        RTS (from $C07F) ---------------------------
f97657  A:02 X:60 Y:00 S:EA P:nvUBdIzc                      $8BF6:C9 01     CMP #$01
f97657  A:02 X:60 Y:00 S:EA P:nvUBdIzC                      $8BF8:A5 04     LDA $0004 = #$02
f97657  A:02 X:60 Y:00 S:EA P:nvUBdIzC                      $8BFA:65 60     ADC $0060 = #$00
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8BFC:85 60     STA $0060 = #$00
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8BFE:A5 05     LDA $0005 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C00:65 61     ADC $0061 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C02:85 61     STA $0061 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C04:90 06     BCC $8C0C
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C0C:A5 60     LDA $0060 = #$03
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C0E:8D 3F 06  STA $063F = #$04
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C11:85 CE     STA $00CE = #$03
I find this pretty odd, because the number got adjusted from the Japanese value of 02 to the English version value of 03 without the kind of complex subroutine that adjusted the experience. It makes me feel like I lost the trail or there is something I'm missing.



August 06, 2020, 04:02:16 am - (Auto Merged - Double Posts are not allowed before 7 days.)
I did some work to make sure that the English version isn't just adjusting gold values by one. After making several comparisons, it would seem that the English gold values are being adjusted to 120% of the Japanese values. So there is definitely a routine doing this that has so far evaded me.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 06, 2020, 06:56:35 am
You have found code correctly, but it is not the most convenient location to edit. Here is the easiest way in my opinion

(https://i.imgur.com/MGLahIN.png)

I replced 00CE-00CF (gained gold with addition) with 0004-0005 (default gained gold). It seems like 0004-0005 keep default gold the whole time.
Code: [Select]
f97657  A:FF X:4A Y:00 S:EA P:nvUBdIZC                      $8BE7:A5 60     LDA $0060 = #$02
f97657  A:02 X:4A Y:00 S:EA P:nvUBdIzC                      $8BE9:85 04     STA $0004 = #$00
f97657  A:02 X:4A Y:00 S:EA P:nvUBdIzC                      $8BEB:A5 61     LDA $0061 = #$00
f97657  A:00 X:4A Y:00 S:EA P:nvUBdIZC                      $8BED:85 05     STA $0005 = #$00

However I didn't change 00D0 to 0006, because 00D0 is always forced to store 00
Code: [Select]
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C1E:A9 00     LDA #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C20:8D 41 06  STA $0641 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C23:85 D0     STA $00D0 = #$00

On the other hand, 0006 might still keep some garbage value, presumably from exp, so it's save to keep 00D0.

August 06, 2020, 07:19:53 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Actually, no. I forgot that this code I've changed only affects ram gold value, but the screen still displays +3 gold gained.

August 06, 2020, 07:26:45 am - (Auto Merged - Double Posts are not allowed before 7 days.)
(https://i.imgur.com/HJsbNLL.png)

Here is a better way. CMP 01 is for affecting C flag, but I've deleted additions and now store 0004-0005 directly at 0060-0061 (gold for displaying and copying into 00CE-00CF)
Code: [Select]
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C0C:A5 60     LDA $0060 = #$03
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C0E:8D 3F 06  STA $063F = #$04
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C11:85 CE     STA $00CE = #$03
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C13:05 61     ORA $0061 = #$00
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C15:F0 58     BEQ $8C6F
f97657  A:03 X:60 Y:00 S:EA P:nvUBdIzc                      $8C17:A5 61     LDA $0061 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C19:8D 40 06  STA $0640 = #$00
f97657  A:00 X:60 Y:00 S:EA P:nvUBdIZc                      $8C1C:85 CF     STA $00CF = #$04

, so there is no need for it. Instead I replace it with CLC, which forces C = 0, which results in BCC to always branch and skip overflow correction.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 06, 2020, 08:05:34 am
This fix took some finesse I see, but there's a problem. I'm testing if the new values come out correctly compared to my Japanese guidebook.

For instance, Al-mi'raj, or Spiked Hare in the original localization gave 10 gold per in the English version. Japanese version is supposed to give 8 gold per. I just killed four of them and got 38 pieces of gold. Original English would have been 40, Japanese would have been 32.

It seems like the new code subtracted 2 from one of them (which is correct) but perhaps didn't extend that benefit to the other 3? 38 doesn't divide by four after all.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 06, 2020, 08:15:54 am
Game doesn't add to each monster separately, it gets a sum of all monsters and works with it.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 06, 2020, 08:31:24 am
I just did a direct comparison of the Japanese version and our patch for the English version.

Near Romalia / Romaly, I killed 4 grey cloaked Magicians in the Japanese version and got 13 exp, 40 gold.

Then, I killed four of those Magicians in the patched English version and got 13 exp, 48 gold.

The new gold calculation is definitely not sufficiently emulating the way the Japanese game handles it.

FYI, heading to work so I won't be able to do anything more with this until tonight.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Cyneprepou4uk on August 06, 2020, 08:35:02 am
40 and 48, sound like you didn't apply the patch, still +20%.

I've tested it on 2 ravens and 5 slimes, works for me. 2 ravens = 4 gold instead of 5, 5 slimes = 10 gold instead of 12. Didn't compare to jap thought.

August 06, 2020, 07:11:12 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Quote
RAM xx+0, xx+1, xx+2.
I'm pretty confused by this.

Since no one else explained it. In assemblers such as ca65 you can do stuff like
Code: [Select]
ram_exp = $0744    ; creating a label

LDA #$00
STA ram_exp        ; 0744, ram_exp + 0 also works
STA ram_exp + 1    ; 0745
STA ram_exp + 2    ; 0746

So it was just a way to tell you about 3 nearby addresses with exp.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 07, 2020, 12:29:19 am
@Cyneprepou4uk
Apologies for giving you that bad info regarding the gold code not working. The reason it wasn't working is because I missed a couple of the byte swaps. I didn't realize how many there were because I looked at it quickly. I shouldn't have even touched that this morning with such limited time. Anyway, I got it all sorted out a few hours ago.

After that, I decided to address the next thing on my list, the Parry / Cancel bug (causes character to retain double defense from parry even after cancelling action). Knowing that Zombero managed to fix this bug for his Hardtype hack, I figured I'd take a look at his code.

I did a couple of trace logs to compare and I tracked down the subroutine he incorporated surprisingly quickly. It's a routine that already seems to exist at $4842 but he copied it over to some blank space later in the rom. I plugged that small fix into my rom, and it works perfectly.

I had actually sent Zombero a PM over a year ago requesting permission to incorporate the parry fix patch and never heard back. I sent him an email tonight requesting permission again. I'm a little unclear on whether or not it's acceptable to use part of someone's work and provide credit if you can't get through to them to obtain permission. I feel like I've seen this covered in the rules at some point, but I can't seem to find it now.

**EDIT I sent the admin team an email describing the scenario and asking how things like this should be handled.

If using Zombero's parry fix is ultimately kosher, that should solve everything remaining on my list except for one more big one: restoring censored Japanese nametables in three locations: the white cross in the big temple in Lanceal, the  white cross in the shrine of Necrogond and finally the Buddhist symbol behind the altar at the Temple of Dharma.

I played around for hours with the data for these maps several months ago, and I simply couldn't crack the format of how the engine draws the maps. I was unable to just swap in the Japanese instructions because the space for them is smaller in the English rom. Now that I have a little skill with debugging / trace logging, I can hopefully get further with this. Perhaps even part of the drawing routine could be jumped over to another section of code if the space isn't enough. abw mentioned the idea of writing the code to be more efficient, but that would appear to be quite beyond me right now. How would you guys go about approaching this?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 15, 2020, 11:07:24 pm
@ Cyneprepou4uk
A bug turned up and I've confirmed that it's a direct result of your code changes that remove the extra gold. While the battle gold acquisition is working fine, now when you go to sell an item at the shop, you end up getting a massive amount of money. Try selling a medical herb. The shop keeper will tell you the correct price he will buy it for, but then you get 33000+ gold as a result of the sale.

In other matters, the admin team messaged me back that having fixed the Parry bug via referencing Zombero's fix shouldn't be an issue, primarily since he copied an existing routine and simply made a jump to it and a return.

Also, I became aware of a DQ3 bug where you learn Snowstorm/Mafrosto at 26 and Icespears/Frostdain at 32, when it was supposed to happen in reverse. Based on menu placement and spell damage, I thought that fixing would be a significant improvement. I spent the last week doing my own disassembly work on the somewhat complex routine structure for spell learning. Today I was able to locate the bytes that needed switching. Submitted as a separate hack. I thought that players of the standard game would appreciate this bug fixed.

Didn't even start working on decensoring the nametables until tonight, and barely got anywhere. But I should be able to make some progress based on having a larger tool box.



August 16, 2020, 02:24:21 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
I started from scratch trying to fix the gold issue without looking at your work. It seems that a smaller scale fix does the job, without making a mess of anything else. I just targeted the two instructions that add the $60 / $61 values, replaced the first with a CLC and EA, and the second with an ADC #$00.

ROM address $0x04C0A should have $18 $EA written
ROM address $0x04C10 should have $69 $00 written

I've tested on both low and high gold generating monsters, and I've also bought and sold things. Everything seems in order.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on August 28, 2020, 07:11:11 pm
The other problem we all have is that I missed a detail in how DW2's text engine handles transitioning from the first text bank to the second text bank - it actually requires a copy of the first byte of the second text bank to be placed after the last byte of the first bank. In the original game, this means that $05:$BFD7 (0x017FE7) has to have the same byte value as $02:$B7B2 (0x00B7C2); Choppasmith's version will require $05:$BFD7 to be a copy of $0C:$8000 instead.

The bad news is that abcde can't currently handle this for you, so you'll have to copy your second bank's first script byte to 0x017FE7 on your own in the meantime.
I finally got around to doing something about this - the latest version of abcde (v0.0.9) now has enough power to handle copying a byte from one address to another (total rocket science going on here, I know :P) if you supply the right insertion commands anywhere after the end of the main script, like so:
Code: [Select]
// due to the way the game's bank bridging code works, the first byte of the second script bank needs to be copied to the byte after the last byte of the first script bank in order to ensure consistency between banks
#VAR(copy, CALCVAR)
#READ(copy, $B7C2)
#JMP($17FE7)
#PRINT(copy, 8)
Basically that just does what you'd expect - creates a variable to hold a value, reads a byte from ROM into that variable, jumps to the address you need to the value to be copied to, then inserts the value there.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on August 28, 2020, 09:04:21 pm
I finally got around to doing something about this - the latest version of abcde (v0.0.9) now has enough power to handle copying a byte from one address to another (total rocket science going on here, I know :P)
Glad this is a feature now! I'm sure the need will come up again at some point for us.

And since you've shown up here, you know that I have to pick your brain a bit, right? As you can see above, this thread went from cacophonous to deadly silent over the last few weeks.

So! After solving everything on my wish list but maps, it sort of became an absolute requirement for me to solve the maps, hell or high water. I'm progressing with my disassembly/documentation process, but I worry that it will take me something like 6 months at the rate it feels like it's going. The structure of what's going on here seems to be a lot more complex than the above issues that I figured out.

I've been working on the Necrogond Shrine first and foremost (because small) and we know the nametable data is 1AB4E-1AB82 ROM, AB3E-AB72 RAM. I've ran a trace log that breaks on every read on that RAM range and captures all the code forward until the map is drawn. The values move through a hell of a complex structure of loop routines, and I'm trying to map that all out so that I can understand and manipulate the data, still operating on your idea that if I understand what's going on, I might be able to increase map complexity in the same data space via greater efficiency. And if that can't be done, I then look to the idea of having the code do a bank switch (something I haven't figured out yet) and read that map data from another bank that actually has free space. I might need to move the attribute table as well, I imagine. Does that plan seem prudent? If you have any ideas that could save me weeks or months, do tell. I know you solved something similar with the maps in DQ2, and I'm very curious how equivalent the map drawing routines are between the two games. I was trying to figure out which thread it was on that we discussed that over a year ago, but alas.

If you wanted to take a glace at the trace log I refer to: https://www.dropbox.com/s/ck4n9qxr034wh8b/log%20for%20entering%20necrogond%20READ%20HITS%20FROM%20MAP%20DATA.log?dl=0
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on August 29, 2020, 09:54:09 pm
I know you solved something similar with the maps in DQ2, and I'm very curious how equivalent the map drawing routines are between the two games. I was trying to figure out which thread it was on that we discussed that over a year ago, but alas.
I think you're looking for this thread: http://www.romhacking.net/forum/index.php?topic=26112.msg378684#msg378684. After taking ROM 0x1AB4E-0x1AB82 and plugging it into my DW2 map building visualizer, I get something that looks very much like the Necrogond Shrine (same layout, but the 2 games use different graphics per tile ID, so e.g. tile ID $14 is a treasure chest in DW2 but a star in DW3), so without looking at DW3's code, I'd say the map building routines are likely to be virtually identical between the two games. http://datacrystal.romhacking.net/wiki/Dragon_Warrior_II::ROM_map/ASM_bank_02 has a fair bit of commentary on DW2's map building code, so assuming the code actually is as similar as I expect, that commentary should be quite helpful for DW3 too.

I'm progressing with my disassembly/documentation process, but I worry that it will take me something like 6 months at the rate it feels like it's going. The structure of what's going on here seems to be a lot more complex than the above issues that I figured out.
Yup, the map building routine is definitely "special" ;). I think it took me a couple of multi-hour sessions to work through it enough to understand what was going on, and then several more sessions to document it.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 06, 2020, 10:43:48 am
@abw

I'm continuing to have an extremely hard time grasping the structure of the map drawing, even with the DQ2 disassembly. It's hard for me to even know how to ask for specific help on this, but here's a list of questions that I hope will help clarify.


VOCABULARY

Some terminology / conceptuals I could use clarifaction on:

Control flow target: google would indicate that the control flow is the main program sequence and the targets are the subroutines that get called per the control flow. Is that the right idea?

Map buffer: this is a function of the PPU I would assume?

Map data handler: not finding much in my research for this terminology

"map stack": is this different than the normal stack register?

index to top of "map stack": not sure what indexing means

popping the bottom of the "map stack": also not clear on meaning

process next control code: is this referring to the next step in the main flow of the program?

flag for whether xxxx handler wrote tile IDs: I would assume that flag means write a yes or no indication?

read the next text token and interpolate any variable control codes: not clear on this concept of interpolating.


FORMATTING

A question about how your disassembly is formatted:

Example:
0x00AE5B|$02:$AE4B:B0 03      BCS $AE50     ; read 2 bits of map data: if #$00 or #$01, rotate in that direction and draw the current tile ID; if #$02, push to "map stack" then read 1 bit of map data, rotate in that direction, and draw current tile ID; if #$03, read 1 bit of map data and if set, pop from "map stack", else loop to 0b10 handler to start drawing at a new co-ordinate

Your description here seems to describe a routine, but the notes seems to correspond to a single instruction to branch if carry is set. Are you describing the function of the routine that gets branched to if the criteria is met? I imagine this must be the case.


CONCEPTS

Here are some high level questions about what is going on.

Is it correct to say that *ALL* all of the drawing instructions are ultimately found in the cluster of map data, and that the code / routines involved in the map drawing go through the same structure of processes for every map? Therefore, as long as I understand what purpose each byte in the map data serves, I should be able enact changes? This was my hope, but when I read the disassembly, I have a hard time determining exactly which bytes of map data are getting read from and how it all translates in to the routine structure.

Am I correct in my suspicion that the material in this disassembly most relevant to my map drawing concerns is located about 2/3 of the way down the file?

Ok, that's all I have for now, but I suspect there will be additional rounds of questions coming.

Yup, the map building routine is definitely "special" ;). I think it took me a couple of multi-hour sessions to work through it enough to understand what was going on, and then several more sessions to document it.
Why again am I even attempting something that even the likes of you finds difficult?  :P
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 07, 2020, 07:44:53 pm
Rapid Fire Answer Round!

Control flow target: google would indicate that the control flow is the main program sequence and the targets are the subroutines that get called per the control flow. Is that the right idea?
Yup, that's exactly it means.

Map buffer: this is a function of the PPU I would assume?
Nope, that's just the area of cartridge RAM starting at $7800 that the game uses to hold the map data while it's being constructed.

Map data handler: not finding much in my research for this terminology
This just refers to the code for handling map data.

"map stack": is this different than the normal stack register?
Yup. As I said earlier in the linked thread, the map building routine manages its own stack in cartridge RAM via software, and this is completely separate from the CPU's hardware stack that gets used for PHA/PLA/JSR/RTS/etc. operations.

index to top of "map stack": not sure what indexing means
https://en.wikipedia.org/wiki/Array_index

popping the bottom of the "map stack": also not clear on meaning
https://en.wikipedia.org/wiki/Stack_(abstract_data_type)

process next control code: is this referring to the next step in the main flow of the program?
Probably yes, depending on how you choose to break up the flow of a program into steps. Usually it means the program is finished its current (sub-)task and is moving on to the next one.

flag for whether xxxx handler wrote tile IDs: I would assume that flag means write a yes or no indication?
Yup.

read the next text token and interpolate any variable control codes: not clear on this concept of interpolating.
https://en.wikipedia.org/wiki/String_interpolation

Your description here seems to describe a routine, but the notes seems to correspond to a single instruction to branch if carry is set. Are you describing the function of the routine that gets branched to if the criteria is met? I imagine this must be the case.
Yup. Usually the interesting thing about branches and subroutine calls is what code they end up executing, so that's the information my comments tend to provide, though if there's something strange going on like branching based on incorrect logic, that'll be noted somewhere too.

Is it correct to say that *ALL* all of the drawing instructions are ultimately found in the cluster of map data, and that the code / routines involved in the map drawing go through the same structure of processes for every map? Therefore, as long as I understand what purpose each byte in the map data serves, I should be able enact changes? This was my hope, but when I read the disassembly, I have a hard time determining exactly which bytes of map data are getting read from and how it all translates in to the routine structure.
There is some code that runs earlier and reads a separate block of what I've referred to as map header data from $02:$8018, but aside from providing the pointer to the map data, it's not really relevant for the tricky part of map construction. The world map data is handled separately, but all the other maps go through this routine. Also, keep in mind that the map building instructions have many different bit lengths, and almost none of them are 8 bits long.

Am I correct in my suspicion that the material in this disassembly most relevant to my map drawing concerns is located about 2/3 of the way down the file?
As I said earlier in the linked thread, $02:$AB89 is the entry point for the map building routine.

Why again am I even attempting something that even the likes of you finds difficult?  :P
Because it's good practice :D. There is something to be said for the old adage that whatever does not kill you makes you stronger; overcoming challenges is one of the ways in which we grow.


Apparently there already is a Dragon Quest III Map Viewer (https://www.romhacking.net/utilities/64/), though for me it crashes immediately after loading a ROM with what looks like a Shift-JIS-encoded error message; does that program help any?

I've put some time into adding various bells and whistles to my DW2 map building visualizer and added a bunch of DW3 map data; I've labelled the first few maps and added some DW3 tile images, but the majority of the maps are still unlabelled, I haven't gone looking for the separate map header data (assuming it exists), and the tilesets are pretty messed up (the complete town tileset includes more than 32 different tiles, so there's logic somewhere for deciding which tiles get loaded into VRAM and thus what image a given tile ID will end up producing). Even as a WIP, though, it's still a bit fun and should be educational. Here's a link! (https://drive.google.com/open?id=1rsVoTiWovICAdQ49r-v1noRjVOSzpf6A)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: erinnk on September 08, 2020, 05:12:49 pm
I'm continuing to have an extremely hard time grasping the structure of the map drawing, even with the DQ2 disassembly. It's hard for me to even know how to ask for specific help on this, but here's a list of questions that I hope will help clarify.
...

I'll attempt to reach out to you to help however I can.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 09, 2020, 09:59:16 pm
@abw

The Rapid Fire Answer Round was very helpful, thank you!

But the real reason I'm writing at this moment is that I simply can't hold back my happiness with your map visualizer software. It's brilliantly intuitive, and the power of being able to step through the bit based code and watch the map build is filling me with absolute joy. I actually see the light at the end of the tunnel now because of this thing. You, sir, have saved the day--yet again. I feel pretty confident that after playing around with this enough, I'll be able to bend the map drawing to my will and determine if there actually is a way to increase efficiency and add the crosses. I'm still a bit skeptical on that point because I know that your DQ2 map work resulted in either lesser or equal overall detail. But I will give this my all because the alternative is rather frightening.

Regarding the other DQ3 map builder software, I had the same experience as you. Weird error message and crash. I doubt I would find even a fraction of the value there that I find in your piece of work regardless.

And one question: the tile ID's. Am I correct to assume that these 5 bit tile ID numbers match up to a separate attribute table that stores tiles selected for each specific background? Therefore, if I needed to swap out an available tile, I would just do so in the attribute table (which would probably incorporate a way to target a much wider range of addresses?

Oh, btw, you really should publish this map visualizer at some point. People would value this.

I'll attempt to reach out to you to help however I can.
Thank you so much for dropping in! You have already been a huge help to me, particularly with me actually gaining a grasp of a lot of the ins and outs of 6502. For those that don't know erinnk, she has some incredible history with past DQ related projects, various other feats of technical wizardry and is an all around wonderful person to boot. Welcome!

September 09, 2020, 10:22:12 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
@abw,

Also: I'm studying efficiency right now. But if I find an opportunity to rewrite some of this, I wanted to ask your advice about the best way for me to rewrite this in bit. I really haven't had to do that yet, and I'm kind of scratching my head thinking about it. I don't think I can just insert this in bit form via a hex editor. Maybe online there are some tools I can find where I can expand the byte sequence into a bit sequence and then compress it back into a byte sequence when I'm finished editing?

**NOTE erinnk already helped me find a tool for converting strings from bit to byte / byte to bit.

And also: looking at the DQ3 map options, am I right to assume that the Lanceal and Dharma temple maps already have their data saved here, and I just have to figure out which map ID they are saved under and note that?

And... if I may be so bold, the one thing jumping out to me that I'd fix with the visualizer is this: when I use the "Do next step" option, and it pastes the next command on the bottom of the screen, would it be possible to have the application auto scroll down to the new command that pasted? I end up constantly moving my mouse up and down between hitting the button and then scrolling down on the list of operations so I can see what executed. This is a really small issue but I just wanted to bring it up. I should really be shot for complaining about software that you designed for your own private use and were generous enough to share with me. :P
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: erinnk on September 09, 2020, 10:12:53 pm
You're so nice. Happy to do whatever I can 😊
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 11, 2020, 05:05:22 am
@abw

After studying the bit efficiency of the Necogrond Shrine Map Data, I don't see an opportunity to optimize it. Furthermore, I'm calculating that I would need space for 39 extra bits to draw the white cross. You could also take a look if you haven't already, but I'll be shocked if you come up with something vastly different. That brings us back to square one. My suspicion is that we need to explore shifting some of data to another ROM bank, making the necessary adjustments required to read it there. For instance, the ROM bank starting at $74010 seems totally empty. If we needed to copy over large sections of code and data, that would seem to be the place for it. Or better yet, what about copying over the entire Japanese ROM bank starting at $18010 and just updating the pointers that call to the map drawing routines?
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 12, 2020, 11:38:49 pm
I simply can't hold back my happiness with your map visualizer software. It's brilliantly intuitive, and the power of being able to step through the bit based code and watch the map build is filling me with absolute joy.
It is rather fascinating to watch the maps being put together, isn't it? I'm glad you're enjoying it!

And one question: the tile ID's. Am I correct to assume that these 5 bit tile ID numbers match up to a separate attribute table that stores tiles selected for each specific background? Therefore, if I needed to swap out an available tile, I would just do so in the attribute table (which would probably incorporate a way to target a much wider range of addresses?
They'll need to match up with something else, definitely. I didn't go through all of the code related to maps, but the tiles are 16x16px, so the tile ID values will have to map to a set of 4 nametable values for the individual 8x8px PPU tiles (this might be implemented as a simple value * 4 with 2 ASLs) and a palette index (this probably involves the map ID somehow since I think water and lava use the same tile ID but with different palettes). Somewhere there will also be data about which tiles can be walked upon etc.

For DW3, keep in mind that not all of the PPU tiles are loaded into VRAM at the same time, so if you want to use a tile that isn't already present, you'll need to figure out what controls which tiles are available and work with or alter that logic.

Also, the size of a tile ID depends on the highest tile ID the map uses; most of them are 5 bits, but if, for example, a map doesn't use any tile ID over 07, it can get away with using 3-bit tile IDs.

Oh, btw, you really should publish this map visualizer at some point. People would value this.
Yeah, eventually. It still has a ways to go before it's ready for the limelight, though I did put some more time into it over the past few days and have updated the original link with a newer version. One particular update of note is that the previous version had accidentally sorted the DW3 maps by the ROM address of the start of each map's data instead of by the address of the pointer, so the ID values were all wrong, and I've corrected that in the newer version.

And... if I may be so bold, the one thing jumping out to me that I'd fix with the visualizer is this: when I use the "Do next step" option, and it pastes the next command on the bottom of the screen, would it be possible to have the application auto scroll down to the new command that pasted?
Ha, this was actually working earlier (it's something I wanted too :P), but I inadvertently broke it while making the layout prettier, so I've fixed this in the newer version, and made it optional too.

And also: looking at the DQ3 map options, am I right to assume that the Lanceal and Dharma temple maps already have their data saved here, and I just have to figure out which map ID they are saved under and note that?
Yup, it looks like everything except the 2 world maps are covered, including map #$81, which I feel like I've seen before but haven't been able to locate in-game. It's stored adjacent to the Rimuldar 2F map and visually lines up well with the two inaccessible staircases in the north part of Rimuldar; possibly an unused map?

After studying the bit efficiency of the Necogrond Shrine Map Data, I don't see an opportunity to optimize it.
There is some room for optimization, but finding an extra 39 bits (or 33 since the map data has 6 trailing bits you can use without needing an extra byte) could be tricky. Rectangles can cover large areas at a fixed cost, but the original instructions often prefer drawing long straight lines one tile at a time, and that's often less efficient. For instance, the 3 rows of 5 stars and statues are drawn as lines and cost 27 bits each (including the cost of switching tile IDs), but single 1x5 rectangles would achieve the same effect at a cost of 25 bits each, so there's an extra 3*2=6 bits saved. You can save a few more bits by drawing the walls and then the floor tiles as rectangles instead of drawing the floors first and then tracing around them with wall tiles, but that's still not enough space.

Ideally I'd like to have some sort of map editor where you can draw whatever map you want and then it would automatically generate a minimal set of building instructions, but we're not there yet, alas.

Moving the maps to a different bank is certainly an option, but you'll have to adjust the logic for determining which bank to load to read the map data from. An easier approach for the bank 7 maps (which includes Dhama Temple) would be to use some of the $200+ bytes of apparently free space starting around $07:$BDB8.

Are the DQ3 maps stored in the same format as DW3? I seem to recall DQ2 and DW2 had different ways of storing and building their maps.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 13, 2020, 08:30:52 am
though I did put some more time into it over the past few days and have updated the original link with a newer version.
Yay! Excited to play around with the new version.

For instance, the 3 rows of 5 stars and statues are drawn as lines and cost 27 bits each (including the cost of switching tile IDs), but single 1x5 rectangles would achieve the same effect at a cost of 25 bits each
This is brilliant. My brain did not conceive rectangles with 1 width or length as a possibility.

Moving the maps to a different bank is certainly an option, but you'll have to adjust the logic for determining which bank to load to read the map data from. An easier approach for the bank 7 maps (which includes Dhama Temple) would be to use some of the $200+ bytes of apparently free space starting around $07:$BDB8.
I've had blinders on looking exclusively at the Necrogond Shrine issue, so it's delightful to now see that there is plenty of space for expansion in the next ROM bank. I have a few things to ask about now.

1. Moving the Dharma map data should just be an update to a pointer in the index, I assume.

2. There should be space there also for Necrogond (and presumably Lanceal), but that involves a bank switch on where they are read--adjusting the logic as you say. In my disassembly efforts so far, I haven't dealt with any bank switching yet. I'd assume that the bank numbers for each set of map data are stored somewhere in an organized manner, no?

3. As far as adjusting the logic, is that limited to adjusting just the bank read data and the map data pointer? Or would there be more to the story?

Are the DQ3 maps stored in the same format as DW3? I seem to recall DQ2 and DW2 had different ways of storing and building their maps.
I haven't determined that, and never thought it would be different. How bizarre of them to change such a thing.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on September 27, 2020, 11:50:34 pm
FYI, I updated the map visualizer link with a new version that includes a few more upgrades, most notably adding the DW3 tilesets so that DW3 maps now display mostly correctly (I didn't bother with palette swaps of the same tileset like Aliahan vs. Tantegel). I also took a peek at DW4 and found that it too uses the same basic map building process as DW2 and DW3, though I haven't loaded anything from DW4 yet, so there's some extra fun to be had there.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on September 28, 2020, 01:08:34 pm
Sounds great! I'll be using it again soon. I took a break with the background stuff for a bit to wrap up title screen. I also started another play just to make sure none of the bug fixes created any unintended effects, but ended up committed to another entire play-through for further text improvements. Just came across what appears to be a bug in the original game that's kind of interesting. There's an encounter in Baramos's castle with a Stray Metal (Metal Babble) on the right and a few Hologhost on the left. In only that encounter, for some bizarre reason, the Stray Metal will take normal damage from my Priest (who happens to be in the second party slot). I don't believe anything I did would have caused this. I'll have to do some debugging to figure out why the 0 or 1 damage metal slime routine isn't triggering with only that character in that specific encounter.

As far as backgrounds, when I return to that to wrap things up, I'm guessing it would be easier to just make more space for an expanded Necrogrond Shrine map by taking a map or two around it and making those more space efficient via your 1 square wide blob idea. I'll adjust data locations afterwards, track down the map data pointers, and make the necessary adjustments. It will take a bit of time but with the help of your DQ2 disassembly, I see that all being workable.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 06, 2020, 03:11:05 pm
Thought I'd crosspost this from my thread, but user Seb has discovered there's an unseen NPC Post Malroth at Midenhall that gives you a blank window. I checked the original and it's there too.

(https://i.imgur.com/nE0u6XV.png)

So I did a trace log and looked up the ASM documentation

Code: [Select]
$80B7:F0 0A     BEQ $80C3
A:03 X:18 Y:00 S:FD P:nvUBdIzc   $80B9:20 34 D3  JSR $D334
A:03 X:18 Y:00 S:FB P:nvUBdIzc     $D334:20 5C F7  JSR $F75C
A:03 X:18 Y:00 S:F9 P:nvUBdIzc       $F75C:48        PHA
A:03 X:18 Y:00 S:F8 P:nvUBdIzc        $F75D:A9 00     LDA #$00
A:00 X:18 Y:00 S:F8 P:nvUBdIZc        $F75F:F0 21     BEQ $F782
A:00 X:18 Y:00 S:F8 P:nvUBdIZc        $F782:20 D5 C3  JSR $C3D5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $C3D5:4C BB FF  JMP $FFBB
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFBB:8D F6 05  STA $05F6 = #$06
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFBE:86 43     STX $0043 = #$18
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC0:78        SEI
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC1:8D FF FF  STA $FFFF = #$C5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC4:4A        LSR
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC5:8D FF FF  STA $FFFF = #$C5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC8:4A        LSR
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFC9:8D FF FF  STA $FFFF = #$C5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFCC:4A        LSR
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFCD:8D FF FF  STA $FFFF = #$C5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFD0:4A        LSR
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFD1:8D FF FF  STA $FFFF = #$C5
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFD4:EA        NOP
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFD5:EA        NOP
A:00 X:18 Y:00 S:F6 P:nvUBdIZc          $FFD6:60        RTS (from $C3D5) ---------------------------
A:00 X:18 Y:00 S:F8 P:nvUBdIZc        $F785:68        PLA
A:03 X:18 Y:00 S:F9 P:nvUBdIzc       $F786:60        RTS (from $F75C) ---------------------------

Am I reading this right that this NPC is trying to read from string ID 148, which without looking, I imagine is probably blank and unused?

October 06, 2020, 03:25:36 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Also, abw, I THINK this might be a bug with your menu hack


Another thing occurs when buying items. After you select which character will hold the item, the merchant's dialogue won't refer to them, but instead to the one that comes before them in the name list (or loop back to the last one in the case of the first character).
(https://i.imgur.com/1CjfPO8.png) (https://i.imgur.com/z1HDMXG.png) (https://i.imgur.com/S3b4aeM.png)



At least I can't see anything wrong with my script that would cause this.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 07, 2020, 07:31:20 pm
Thought I'd crosspost this from my thread, but user Seb has discovered there's an unseen NPC Post Malroth at Midenhall that gives you a blank window. I checked the original and it's there too.

Am I reading this right that this NPC is trying to read from string ID 148, which without looking, I imagine is probably blank and unused?
It's an empty string, but clearly not unused :P. I'm guessing the devs stuck an NPC there to block you from reaching the Evil Clown in the basement, but it's basically the same amount of work to add a check for Malroth being dead when generating Midenhall B1 as to add a check for Malroth being dead when generating Midenhall 1F, so I dunno.

Also, abw, I THINK this might be a bug with your menu hack
[...]
At least I can't see anything wrong with my script that would cause this.
Nope. You can easily confirm it by trying just my patch. This is happening because you've added a [name] control code to the item shop string (‘With our most humble compliments, good [name]!’) that wasn't present in the original string (‘I thank thee kindly.’) but didn't update the dialogue code to populate the [name] buffer for that string, so you end up getting whatever string happened to be left over in $6119 from the last time it got used.

This should be an easy change to make, though - basically you just want to take $06:$8438 and move it a couple of lines up to just after $06:$8431 so that it executes regardless of the branch at $06:$8436.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 11, 2020, 10:46:33 pm
@abw

The thing I've been stuck on with the DQ3 map stuff is regarding the pointers to the map data. Per your DQ2 bank 2 disassembly, there is a nicely organized map header list that includes the relevant pointers to each set of map data. And it's where one would expect it, right at the top of the ROM bank with the map data below.

You'd assume this would be the same with DQ3, but alas, no such luck. It's very possible I'm overlooking something obvious, but I can't find anything like that header list in the relevant DQ3 ROM banks. And I need it in order to move map data around. I've even looked through trace logs where the map data is accessed but the pointing is just not making sense to me.

October 12, 2020, 02:33:27 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Nevermind, I found them. Top of the second map data bank.

*EDIT

Finished the maps at long last! I was in the middle of working on efficiency improvements, and then I noticed the unused Rimuldar upstairs map that you had labeled in the map viewer. And it just so happened to be in the crowded first bank where I desperately needed space. So after moving around appx 30 maps, voila! Everything is uncensored. And I technically didn't need to learn any of the bitwise map instructions, but I'm glad I did. It was really quite cool.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Dracula X on October 12, 2020, 06:34:22 pm
Is it possible to add this feature?

Dragon Warrior 2 & 3
The player can tell who to buy these weapons, armor, and shield for each character like they did in
Dragon Warrior IV so the player doesn't have to spend all that time to earn more gold by making
a mistake by buying the same thing again and it will not work for one of your party members.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 13, 2020, 09:47:24 pm
You'd assume this would be the same with DQ3, but alas, no such luck.
The core map building instruction set appears to be identical between Dragon Warrior II, III, and IV but yes, the supporting code and data do differ a bit between DW2 and the later games. Some of the differences include the exterior tile ID being moved from the map header data to 5 of the 6 bits of data in the third byte of map data that are unused in DW2 (and the exterior background is a pattern, not a solid tile), and the coding for the final wall conversion step is much more convoluted.

So after moving around appx 30 maps, voila! Everything is uncensored. And I technically didn't need to learn any of the bitwise map instructions, but I'm glad I did. It was really quite cool.
Congratulations! If you were able to revert DW3's maps to DQ3's but didn't end up needing to know the actual building instructions, then I'm guessing you actually were able to import the maps from DQ3 successfully, which would mean DQ3 and DW3 do use essentially the same storage system, unlike DQ2 vs. DW2?

The player can tell who to buy these weapons, armor, and shield for each character like they did in
Dragon Warrior IV so the player doesn't have to spend all that time to earn more gold by making
a mistake by buying the same thing again and it will not work for one of your party members.
I'm not quite sure what you mean here - the weapon/armour shop dialogue in both Dragon Warrior II and III already warns you if the character you've selected to carry the item is unable to equip it and then gives you the option of cancelling your purchase, just like it does in Dragon Warrior IV.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 13, 2020, 10:08:40 pm
Congratulations! If you were able to revert DW3's maps to DQ3's but didn't end up needing to know the actual building instructions, then I'm guessing you actually were able to import the maps from DQ3 successfully, which would mean DQ3 and DW3 do use essentially the same storage system, unlike DQ2 vs. DW2?
Your inference is correct. For all three of the maps I uncensored, yes--I was able to plug in the Japanese map data and it was perfectly compatible.

I'm really glad for the existence of those unused rooms. It took me too long to realize that saving a couple bits here and there via improved efficiency never quite results in shrinking the byte footprint of the map data after you convert it.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Dracula X on October 13, 2020, 11:22:21 pm
Quote
I'm not quite sure what you mean here - the weapon/armor shop dialogue in both Dragon Warrior II and III already warns you if the character you've selected to carry the item is unable to equip it and then gives you the option of cancelling your purchase, just like it does in Dragon Warrior IV.

If there's an E right next to a party member then that person can equip that weapon, armor, shield. If not, then that person cannot equip that weapon, armor, shield.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 14, 2020, 10:50:30 pm
Your inference is correct. For all three of the maps I uncensored, yes--I was able to plug in the Japanese map data and it was perfectly compatible.
Nice, that does make life a fair bit easier then. Watching the building process can be a good way of spotting potential areas for improvement, but it's still not the easiest thing in the world to optimize.

In other news, I've updated the visualizer link with a new version that adds in the DW4 maps.

If there's an E right next to a party member then that person can equip that weapon, armor, shield. If not, then that person cannot equip that weapon, armor, shield.
Ah, okay. The DW2 disassembly should be complete enough to make that relatively easy. You'd need to expand the width of the hero selection menu windows and add probably 3 new menu control codes for displaying E or not depending on whether the corresponding hero can equip the selected item. Expanding the menu windows would require understanding the menu format (which is documented in the disassembly and elsewhere) and consuming more ROM space and shifting all the other menus around and updating their pointers, but there is plenty of free space available in that area, so it's not too bad. The routine for determining equipability is also documented in the disassembly, so you'd just need to have your new menu control code handler call that and then add an E or a space to the menu string buffer based on the result.

DW3 would take a lot more work since I don't believe anybody has made any of the required knowledge public, so you'd have to figure out where everything is and how it works first, and I can tell you right now that DW3's menu system is much more complex than DW2's. Given the customizable nature of your party in DW3, you might also want to consider showing which reserve members can equip an item, or which classes can equip an item.

October 18, 2020, 09:57:38 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Update: I actually implemented this for DW2 and included it as part of my Menu Upgrades (http://www.romhacking.net/hacks/4753/) hack. It wasn't too hard, except that DW2's fixed bank is over 99.5% full and I forgot about the weapon shop's version of the hero selection menu being shared with 5 other uses, so I ended up adding new menu data just for the weapon shop instead of code to detect which case the menu was being used for.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 20, 2020, 02:37:43 am
I just saw abw's update on 10/18, and it certainly deserves a bump. Very cool you were able to implement that! Looking over your DQ2 menu upgrade patch, it pains me to not use this by default in our Delocalized version. The reason is because it would set a precedent for displaying entire character names that DQ3 and DQ4 can't follow through with. I think it's important for the player experience to always get a feeling of progression with each iteration of the series.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 20, 2020, 10:55:40 pm
Well, it's not that they can't, it would just take a lot of work :P. Your point about progression is certainly valid, though; I think DQ8 on the PS2 was the first official English version to use more than 4 characters when displaying hero names, and that is a loooong way in the future relative to when the NES games were released.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 20, 2020, 11:15:18 pm
I for one will definitely try to add that DQ2 Menu update, thanks abw. Hopefully I get some time this week.

I like to think of my hacks as an alternate universe where the games were localized like they are now from the get go. When I get to DQ3 SNES, I even want to edit the map with the Switch/mobile edits for extra authenticity (lucky for me, there IS a DQ3/DQ6 map Editor out there, the Japanese DQ hacking scene is really something). At the same time, I don't mind adding QoL fixes especially in the case of DQ2 since fans will tell you it should be the LAST version of DQ2 to play. At the end of the day people just want the modern scripts in the old versions.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 21, 2020, 09:52:32 pm
You wouldn't happen to have a link to that, would you? A quick check for various likely-sounding search phrases with Google doesn't turn up anything that looks interesting within the first few pages of results.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Choppasmith on October 23, 2020, 01:26:58 am
You wouldn't happen to have a link to that, would you? A quick check for various likely-sounding search phrases with Google doesn't turn up anything that looks interesting within the first few pages of results.

Sure :)
https://w.atwiki.jp/dq_binary/pages/31.html

If you use some kind of webpage translator the site should be more obvious but basically the list starts with hacks and then goes to developer tools underneath that. They have some RAM and ROM values for games on the left side, but it's very incomplete and mostly for the SNES games. They do have config files for BNE2, sort of a multi-game data viewer/editor that uses said config files for rom hacking. There's somewhat of a English explanation and how-to here but I haven't tried it myself:

https://www.southcape.org/2014/12/22/using-bne2-for-rom-analysis/

Oh and abw, I'm really sorry, I'm trying to update my DW2 rom with your latest Menu Upgrades patch (via asar). I must be forgetting something (it's been a while) that's different in my ROM compared to an unchanged ROM but I'm getting a glitch when I try to buy any weapon/armor in a shop (It just skips the party menu and goes straight to the "(Cannock) Can not equip this are you sure?" message and the graphics glitch out,

October 23, 2020, 08:41:18 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Also, abw, I was hoping to ask if you know how to edit the Redraw Menu text to fix a blink-and-you'll-miss-it glitch when cycling through menus (Sorry to be a pain but I figured maybe you had to touch this up a little bit when doing your Latin translation)

(https://i.imgur.com/UTvJbBJ.png)

The format is baffling to me

Code: [Select]

AN 
D[top border-77] 
[top border-77][top border-77] 
[top border-77][top-right border] [right border]
Why do you need multiple lines for one line of the window? What are the spaces for?

I tried to simply edit it according to where the letters of the new Command window now line up but that didn't work. ND seems to work a little better than AN but I still get extra lines.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: abw on October 24, 2020, 09:47:14 pm
https://w.atwiki.jp/dq_binary/pages/31.html
Thanks! Alas, there's not a lot of information on that page, and all the links I tried are giving me 503 errors, so I can't even try it any of it out for myself :(. Assuming they actually do have a (non-Overworld) map editor, I'm curious to see how well it works.

Oh and abw, I'm really sorry, I'm trying to update my DW2 rom with your latest Menu Upgrades patch (via asar). I must be forgetting something (it's been a while) that's different in my ROM compared to an unchanged ROM but I'm getting a glitch when I try to buy any weapon/armor in a shop (It just skips the party menu and goes straight to the "(Cannock) Can not equip this are you sure?" message and the graphics glitch out,
Probably what you're missing are the 2 new menus and their pointers. Basically I just took the 2 BUY/SELL target menus (from pointers #18 and #42), copied them to new menus (creating pointers #75 and #76, which meant shifting the entire block of menu data down by 4 bytes), updated them to include a space and the new optional E control code ($F0-$F2 depending on the hero), and adjusted their size/position to fit the new text.

Why do you need multiple lines for one line of the window? What are the spaces for?
Because it's not one line of the window, it's two lines divided up to match PPU attribute boundaries so that the game can apply the right palette when clearing and drawing the overlapping tiles (of course, the palette doesn't change between the parts of the COMMAND and EQUIP menus that overlap, but it's all part of the same system that handles rolling the EQUIP menu up and down over the map background which almost always does use a different palette, so the overlap section still has to obey the same rules). A tiny bit of experimentation will show you that that "AN  " is the "AN" of the top line and then the 2 spaces on the second line directly under the "AN". The rest of the data works the same way, e.g. "SP  " covers the "SP" on one line and the "  " directly below it.

After updating that section of data, you'll want to test getting into a battle, because despite being completely separate conceptually, the game actually uses one of the strings of 4 consecutive spaces from that block of COMMAND menu replacement text as one of the black backgrounds in battle :P.

And yes, DW2's menu clearing/redrawing is indeed a pain.
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Retrolife on October 26, 2020, 05:24:04 am
Next year is 30th anniversary of DW III so a new hack is in order one that brings out the best of the game in every aspect(gameplay,storyline,npcs,graphics)
Title: Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
Post by: Chicken Knife on October 28, 2020, 04:29:16 pm
Guess I was a few months too early on our DQ3 NES restoration / retranslation hack.  :P

I intend to eventually work on the SFC version, but even if I started it immediately, (which I don't plan to) it would definitely not get finished in 2021.