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

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

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #180 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



Thank you SO much abw, you're awesome!  :thumbsup: Please know, I'm immeasurably grateful!

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 370
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #181 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?

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #182 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.

« Last Edit: May 22, 2020, 12:26:28 am by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #183 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.

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 370
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #184 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.
« Last Edit: May 22, 2020, 09:52:05 am by Chicken Knife »

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #185 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.

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 370
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #186 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?

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #187 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.

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #188 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, 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 if you do so).

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #189 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, 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 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:
« Last Edit: May 27, 2020, 11:04:45 pm by Choppasmith »

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 370
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #190 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.

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #191 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!

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #192 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?

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #193 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:

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #194 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)

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #195 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!

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #196 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!

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #197 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

Choppasmith

  • Full Member
  • ***
  • Posts: 178
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #198 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-




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!

abw

  • Sr. Member
  • ****
  • Posts: 470
    • View Profile
Re: Dragon Warrior 1, 2 & 3 Hacking Discussion
« Reply #199 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:
  • re-extracted the text from your patched version (dumped your dictionary, converted it to a table file, used the table to dump the script)
  • generated a frequency table for all the table entries that represent a single script byte (you could do this in many ways, though I actually used abcde)
  • made a new table file, populating the 23 available 5-bit table entries with the 23 most frequent script bytes and filling in the rest of the single script bytes
  • ran the text + partial table through a variant of ScriptCrunch I made that's designed to work with abcde
  • filled in the rest of the table entries based on the results
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.