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

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

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
Re: General NES Hacking Questions
« Reply #40 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

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #41 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

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
Re: General NES Hacking Questions
« Reply #42 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?
« Last Edit: December 31, 2018, 08:36:07 am by Chicken Knife »

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #43 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.

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
Re: General NES Hacking Questions
« Reply #44 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.

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #45 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 thread; you might find that helpful if you haven't read it already.

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
Re: General NES Hacking Questions
« Reply #46 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.
« Last Edit: January 06, 2019, 11:05:10 pm by Chicken Knife »

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #47 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.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #48 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:



So far so good?


But then I get some scrambled text:



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



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



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.



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?
« Last Edit: February 06, 2019, 09:37:51 pm by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #49 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 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.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #50 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 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?

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #51 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.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #52 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!

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #53 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, 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.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #54 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.

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #55 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.

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #56 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?
« Last Edit: March 10, 2019, 01:58:06 pm by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #57 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 ;).

Choppasmith

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Re: General NES Hacking Questions
« Reply #58 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.
« Last Edit: March 10, 2019, 03:49:16 pm by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 305
    • View Profile
Re: General NES Hacking Questions
« Reply #59 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".