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

Author Topic: Dragon Warrior 2 Disassembly  (Read 4290 times)

Choppasmith

  • Full Member
  • ***
  • Posts: 126
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #20 on: July 16, 2019, 02:43:45 pm »
Oh I see now. It loads the amount of groups into memory and does string 0 (# Monster,) first and then when it reaches the last monster (or if there's just one) does "And Monster appeared"

I was comparing how it's handled in the Mobile version which is basically

Single Enemy: A(n) (monster) appears
Single/First Group: Some (monsters) appear
Second group: And a/some (monster/s)
Third group: AND a/some (monster/s)

I was wondering how close I could get it to that, even skipping the all caps AND and changing the number words (over One) to "Some", but the code there looks packed and I don't think there's a way to do it without it looking off or wonky.
« Last Edit: July 16, 2019, 02:59:54 pm by Choppasmith »

abw

  • Sr. Member
  • ****
  • Posts: 275
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #21 on: July 16, 2019, 08:07:45 pm »
Oh I see now. It loads the amount of groups into memory and does string 0 (# Monster,) first and then when it reaches the last monster (or if there's just one) does "And Monster appeared"
Not quite - if there's only 1 group, there's no "And".

I was comparing how it's handled in the Mobile version which is basically

Single Enemy: A(n) (monster) appears
Single/First Group: Some (monsters) appear
Second group: And a/some (monster/s)
Third group: AND a/some (monster/s)

I was wondering how close I could get it to that, even skipping the all caps AND and changing the number words (over One) to "Some", but the code there looks packed and I don't think there's a way to do it without it looking off or wonky.
Hmm, let's see...
  • "One" vs. "Some": this is easy, you can just change the text for each of "Two" through "Eight" to say "Some" instead.
  • "A" vs. "An": the code for printing the cardinal number starts at $02:$BEF0, there's a chunk of empty space after its data, and the monster name has already been loaded into $6119 by the time the code for printing the cardinal number runs, so you've got options there. You could actually combine both of these changes into some code like this (completely untested; adjust the vowel checks based on your monster names if necessary):
Code: [Select]
table dw2.tbl,rtl

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 "Some[end-FA]" ; or spell it out as $36,$18,$16,$0E,$FA if you don't want to bother with a table
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
  • "appear" vs. "appears": well, there's a reason DW2 used "appeared" :P. But hey, didn't we fix that [(s)] control code earlier? This sounds like the perfect place to put that to good use ;D. On the other hand, the original battle text is almost exclusively written in past tense, so introducing a present tense here might seem odd :-\.
  • Having different text for each group: strings #$55 and #$56 are empty and probably unused, so if you initialized $A8 to #$52 and let the code keep incrementing $A8 for every group added to battle like it already is, you could replace
Code: [Select]
0x011530|$04:$9520:A6 A8    LDX $A8    ; total # of non-empty groups processed
0x011532|$04:$9522:CA      DEX       
0x011533|$04:$9523:D0 04    BNE $9529  ; branch if we processed more than one non-empty group
0x011535|$04:$9525:A9 54    LDA #$54    ; String ID #$0054: [cardinal #] [monster(s)][line]appeared.[end-FC]
0x011537|$04:$9527:D0 06    BNE $952F 
; control flow target (from $9523)
0x011539|$04:$9529:A9 53    LDA #$53    ; String ID #$0053: And [cardinal #] [monster(s)][line]appeared.[end-FC]
0x01153B|$04:$952B:D0 02    BNE $952F 
    with
Code: [Select]
LDA $A8
BNE $952F
    which gives you 9 bytes to play with; that's probably enough. This way, you'd still have string #$01 for battles with a single group, and then for multi-group battles you'd get string #$53 for group #1, #$54 for group #2, #$55 for group #3, and #$56 for group #4. Update the text of those strings as desired.
So yes, it will take a little bit of work, but nothing too drastic, and I think that lets you match the mobile version perfectly (except for whatever you do with the text for group #4 ["AND THEN, as if that wasn't enough, a/some (monster/s)"]).

Choppasmith

  • Full Member
  • ***
  • Posts: 126
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #22 on: August 05, 2019, 02:03:27 am »
Sorry for the wait. In the middle of summer my computer room/office can become UNBEARABLE stuffy making it harder to find time for this stuff. There's a lot to unpack here, but lets look at this Monster appearing rewrite you graciously offered.

LDA $A8 ; total # of non-empty groups processed
BNE $952F ; LDA=Text String code?


Am I right in assuming that because we changed the first line from LDX to LDA it's just a mater of adding lines until it's done counting? Like this

LDA #$53 ; [monster] appears
LDA #$54 ; And [monster]
LDA #$55 ; AND [monster]
LDA #$55 ; AND [monster]

Note There's nothing unique in the mobile script for a 4th group, I would assume (if it's even possible) it just uses "AND [monster]" again

I'm not supposed to add a branch for each and every string am I because otherwise it'd be impossible to keep it under 9 bytes.

Quote
On the other hand, the original battle text is almost exclusively written in past tense, so introducing a present tense here might seem odd :-\.

I've noticed this in my rewrite. Modern DQ seems to go for present tense and my script is updated accordingly.

abw

  • Sr. Member
  • ****
  • Posts: 275
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #23 on: August 05, 2019, 11:55:58 am »
Sorry for the wait. In the middle of summer my computer room/office can become UNBEARABLE stuffy making it harder to find time for this stuff.
Eww :P. That's probably not too good for your computer either!

There's a lot to unpack here, but lets look at this Monster appearing rewrite you graciously offered.
I think you missed the part about initializing $A8 to #$52 and letting the existing code continue to increment $A8 for every non-empty group; if you do that, then for multi-group battles, $A8 should have the value you want at the time you want it, so you can just use it as the string ID directly. No need for CMP, LDA, or a large number of branches. I'd start by making a little ASM file that reproduces the existing code from $04:$94FC - $04:$9547, and then start editing by changing
Code: [Select]
LDA #$00
STA $A8    ; initialize total # of non-empty groups processed
STA $A7    ; initialize total # of empty groups processed
to
Code: [Select]
LDA #$52
STA $A8    ; initialize string ID for # of non-empty groups processed
LDA #$00
STA $A7    ; initialize total # of empty groups processed

I've noticed this in my rewrite. Modern DQ seems to go for present tense and my script is updated accordingly.
Ah, alright, in that case, no worries!

Chicken Knife

  • Sr. Member
  • ****
  • Posts: 269
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #24 on: August 05, 2019, 02:33:53 pm »
@abw,

I was quickly reading through your disassembly and looking for the section that handles how character sprites are displayed. I have nothing left to do with DW2 but I figure if I can learn how it all works based on your disassembly of 2, it would probably work almost the same for 1 and 3 where I do have work to do. It's possible you didn't spend time detailing that since it was of minimal relevance, and that's fine.

abw

  • Sr. Member
  • ****
  • Posts: 275
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #25 on: August 05, 2019, 03:32:48 pm »
At this point it's not really a question of relevance, just that there's a lot of code to go through and I haven't wandered into much of the code for displaying sprites. If you want to start digging into it, I can give you a few places to start from, like where the per-map pointers to their data are ($02:$A539), where that data gets stored (starting at $053C), and where their graphics are ($00:$A043). Scripted motion (e.g. everything in the prologue) happens at $0F:$CCF1, and the data for the movements starts at $07:$8010. Monster graphic/palette pointers start at $04:$90FC.

As for how close DW2's sprite handling will be to DW1 or DW3, well, who knows? Games can be crazy :P.

Choppasmith

  • Full Member
  • ***
  • Posts: 126
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #26 on: August 10, 2019, 06:33:45 pm »
Eww :P. That's probably not too good for your computer either!
I think you missed the part about initializing $A8 to #$52 and letting the existing code continue to increment $A8 for every non-empty group; if you do that, then for multi-group battles, $A8 should have the value you want at the time you want it, so you can just use it as the string ID directly. No need for CMP, LDA, or a large number of branches. I'd start by making a little ASM file that reproduces the existing code from $04:$94FC - $04:$9547, and then start editing by changing
Code: [Select]
LDA #$00
STA $A8    ; initialize total # of non-empty groups processed
STA $A7    ; initialize total # of empty groups processed
to
Code: [Select]
LDA #$52
STA $A8    ; initialize string ID for # of non-empty groups processed
LDA #$00
STA $A7    ; initialize total # of empty groups processed
Ah, alright, in that case, no worries!

So I'm a little stumped. Does that mean, if I had something like this:

Code: [Select]
LDA #$52   
STA $A8
LDA #$00   
STA $A7   
; control flow target (from $9538)
index:
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   
BEQ $9532 
INC $A8   
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
DEC $60D8 
BNE first 
LDA $A8           
BNE flow 

flow:
JSR $9CCA

first:
LDA $53 ;"[cardinal #] [monster(s)] appear!"

This would just repeat until all the monsters/groups are counted?

Now I know the "first:" should have something that would just load A, but I'm not quite sure of the right code. A being the right string which starts at 52 (so that 1 enemy group loads string 53, 2 loads 54 and so on.

abw

  • Sr. Member
  • ****
  • Posts: 275
    • View Profile
Re: Dragon Warrior 2 Disassembly
« Reply #27 on: August 11, 2019, 11:52:28 am »
The original code cares about 2 things when deciding which per-group string to use: 1) whether the group being printed is the last non-empty group or not, and 2) if the current group is the last non-empty group, whether there was more than one non-empty group or not. If the current group isn't the last non-empty group, it uses string ID #$0001, otherwise it uses #$0053 if there are multiple non-empty groups or #$0054 if there's only 1 non-empty group.

For 1), if you search the code for $60D8, you'll see that it gets initialized to #$00 ($04:$94E7), gets incremented for every non-empty group ($04:$94F4), after which point it tells you the total number of non-empty groups, and then decremented every time a non-empty group gets processed ($04:$951B), so at that point it tells you how many non-empty groups are remaining, and thus whether the group being printed is the last non-empty group or not.

2) works similarly but in reverse: $A8 gets initialized to #$00 ($04:$94FE) and then incremented every time a non-empty group gets processed ($04:$950D), so it tells you which non-empty group is currently being processed and thus whether there was more than one non-empty group or not.

But in your case, you want to change that logic around to care about 1) whether there is more than one non-empty group or not, and 2) if there is more than one non-empty group, which non-empty group is currently being processed.

For 1), you can just take out the DEC $60D8 and then $60D8 will tell you whether there is more than one non-empty group or not.

For 2), $A8 already tells you this.

Does that help any?

Spoiler:
If you're still stuck, here's the version I whipped together:
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: