Extended Text Mode

Bucket Mouse

Active member
Joe said something about "eventually" making it possible to string together text boxes. As it is text boxes are limited to 256 characters, which makes 11 to 12 lines of text per box -- enough in most cases, but sometimes you need more.

I didn't think I'd be tinkering with this so soon, but it turns out a scene fairly early on in my game needs a lot more text. So I'm attempting to patch together an Extended Text Mode on my own.

At first I thought I'd need to write a separate sequence for it, but I think it should be possible to get what I want by slightly modifying the value of one variable in DrawNPCText.asm. In order to figure that out, I had to understand exactly what's going on in DrawNPCText itself. I've studied it hard, but there's something crucial I can't seem to find. Here's the whole thing dissected:

Code:
DrawTextBox:

	LDA gameHandler
	AND #%00100000
	BEQ dodrawTextBox
	JMP dontDrawTextBox
If the conditions are right, draw a text box. Unless there's already a text box onscreen, in which case skip the next part of the code.

Code:
dodrawTextBox:


   ; HideSprites
   
;;; this means that npc text is off right now
;;; so create the box and disable object updates.
    DrawBox #BOX_1_ORIGIN_X,#BOX_1_ORIGIN_Y,#BOX_1_WIDTH, #BOX_1_HEIGHT, #BOX_1_ATT_WIDTH, #BOX_1_ATT_HEIGHT, #$00, #$00, #$00
 
    
    LDA #BOX_1_ORIGIN_X
    ASL
    CLC
    ADC #$01
    STA temp
    
    LDA #BOX_1_ORIGIN_Y
    ASL
    CLC
    ADC #$01
    STA temp1
A box is drawn to the specifications set in NESMaker. Then a little math is calculated to set the dimensions of the text itself as slightly smaller.

"HideSprites" appears to be dummied out with a semicolon, yet it works. I don't understand that part.

Code:
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
	LDY stringTemp
	LDA screenText,y
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
	STA stringGroupOffset

	
    DrawText temp, temp1
    LDA gameHandler
    ORA #%00100000
    STA gameHandler
This next part must be important for a border to be marked around it. The text is loaded into A while something called "stringTemp" is loaded into Y, then they're combined. The text is drawn at the dimensions calculated by DrawBox, then the game reads the controller again (I think....I'm not quite sure what "gameHandler" does exactly).

Code:
 dontDrawTextBox:
	LDA writingText
	BEQ canPressBeBecauseNotWritingText
	JMP dontTurnOffTextBox ;; can't press b to advance or close because still writing text
canPressBeBecauseNotWritingText:
	LDA gamepad
	AND #%00000010 ;; is b button pressed when there is a textbox on the screen?
	BNE  turnOffTextBox
	JMP dontTurnOffTextBox
A routine runs that prevents you from skipping the text or closing the box prematurely. If you wanted skippable text, here's where you'd modify it.

The program reads the gamepad inputs. If the binary for the B button is coming through, the program branches to "Turn Off Text Box."
Otherwise it jumps to "dontTurnOffTextBox" -- a routine that simply leads to an RTS.

Code:
turnOffTextBox:
	LDA stringEnd
	BEQ dontLoadANewTextString
  DrawBox #BOX_1_ORIGIN_X,#BOX_1_ORIGIN_Y,#BOX_1_WIDTH, #BOX_1_HEIGHT, #BOX_1_ATT_WIDTH, #BOX_1_ATT_HEIGHT, #$00, #$01, #$00
	;LDA stringGroupPointer
	;ASL
	;ASL
	;CLC
	;ADC stringTemp

	;STA stringGroupOffset
	
	LDY stringTemp
	LDA screenText,y
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	STA stringGroupOffset
	
	
	LDA #BOX_1_ORIGIN_X
    ASL
    CLC
    ADC #$01
    STA temp
    
    LDA #BOX_1_ORIGIN_Y
    ASL
    CLC
    ADC #$01
    STA temp1
	
	ContinueText temp, temp1
	RTS
"turnOffTextBox" is a misleading name because it doesn't exactly turn off the box. Instead it loads a value called "stringEnd" and determines if it matches the correct value. If it doesn't yet, the program moves on to the next part, which "erases" the onscreen text by drawing a new box over it. There's some dummied-out code here; not sure what it's for. Pre-release, a video came out on Facebook that showed colored text screens, but that feature had to be drawn in like everything else and the box took far longer...so it was cut. It doesn't look like this dummied code is what that does, though.

This is mostly the same as before except "DrawText" is now "ContinueText." The code then RTSes itself away, where I assume, it continues to loop back here until stringEnd equals...I have no idea what it's supposed to equal because nothing tells me. More on this in a bit.

Code:
dontLoadANewTextString:
	
	HideBox #BOX_1_ORIGIN_X,#BOX_1_ORIGIN_Y,#BOX_1_WIDTH, #BOX_1_HEIGHT, #BOX_1_ATT_WIDTH, #BOX_1_ATT_HEIGHT
	LDA gameHandler
	AND #%11011111
	STA gameHandler
	ShowSprites
	LDA #$00
	STA textBoxFlag
	STA updateHUD_offset
dontTurnOffTextBox:
    rts
dontLoadANewTextString launches HideBox, the routine that undraws the text box and restores all that was there before.

From everything I've gathered here, Extended Text Mode should be rather simple. The variable that appears to control the time at which the game stops loading text is STRINGEND.....but I can't find anyplace in the code where the value of it is defined. You'd think it would be here somewhere, but it isn't. Extended Text Mode would temporarily load a new value into STRINGEND that would push things past the current text entry into the next one on the list. The number you establish on that particular screen determines the amount of text you can get in one window.

I feel like I'm really close. Where is STRINGEND?
 

hairycarrot

New member
This post is very valuable to me. Did you ever find stingend?

I am trying to make the text stay on the screen after I dismiss the box. The most success I've had so far is if I comment out 4 lines as shown below, I can get my player back, but it will not move. If I push a movement button it will change facing. If I push jump, it will start jump animation and never end. If I push left or right after that, it will change facing direction in the jump animation.

Code:
dontLoadANewTextString:
	
	;HideBox #BOX_1_ORIGIN_X,#BOX_1_ORIGIN_Y,#BOX_1_WIDTH, #BOX_1_HEIGHT, #BOX_1_ATT_WIDTH, #BOX_1_ATT_HEIGHT ;commenting this line make text load each time it is dismissed
	;LDA gameHandler
	;AND #%11011111
	;STA gameHandler
	ShowSprites ;need for player
	LDA #$00 ;need for player
	STA textBoxFlag
	STA updateHUD_offset

I think if your question gets answered, it will lead me to an answer to what I'm doing.
 

Bucket Mouse

Active member
Yeah, I found Stringend occurs in three more ASM files. SystemVariables.asm (which establishes the memory size for it as one byte), Macros.asm (in a macro for drawing a text box), and HandleHudData (which is for HUD text). Macros has the answer. As far as I can tell, DrawText calls the macro every time, and Stringend has a value of zero, like I figured.

The answer must be in here, but I haven't focused on it lately.

Code:
MACRO DrawText arg0, arg1
	;; arg0 = x (in tiles)
	;; arg1 = y (in tiles)

	LDA #$00
	STA stringEnd;; sets more or whatever else might be needed at the end of the text string

	LDA #$00
	STA hudTileCounter
	STA updateHUD_offset
	LDA #$01
	STA writingText

	
	LDA arg0
	STA tileX
	LDA arg1
	STA tileY 
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	JSR coordinatesToNametableValue
	;; establishes updateNT_pos and updateNT_pos+1
	;;; FIRST, IF this has been tripped, blank all of the values
	


	ENDM
As for keeping the text onscreen, you're on the right track by disabling HideBox. I don't think you want to dummy out gameHandler though; you need that. Like it says, it handles the game.

You know what helps a lot? Entering the variable names into the search box when you're in the Routines folder. Every instance of that variable will turn up and by tracking down their paths, you can find out how they work pretty quickly. If that sounds obvious, I'm sorry, but it wasn't immediate to me.
 

hairycarrot

New member
Well I've commented out so many different lines and I haven't found anything that helps. I was able to find one that would only load the first letter in the text box and then freeze the game.

All further attempts at modification have had no result. I was really expecting that more changes would break the game, but I didn't even do that.

I've been trying to follow the different references to other pieces of code, and I can't find what actually turns off the sprites.
Hidesprites is commented out.
There's an argument in the draw box that disables sprites, but that didn't make any change when I tried variations on it.

Did you make any more progress?
 
Top Bottom