User:Kmeisthax/Findings/2011/6/10/The Wordwrap Plan
The plan for wordwrapped text
The main script routine lives at 2C100 (ROM B:4100) and is implemented as a state machine that gets called by the main game loop once per frame. The most important state for us is State 1 (WRAM C9C9 == 01) because it performs all of the main script interpreter duties - it loads control codes, draws text, and everything else.
A word wrap routine has to be called every space to check and see if the current word will fit on the current line. For the sake of clarity I will define "word" as a stream of non-space, non-control, valid ASCII characters. Spaces, newlines (E2, or now just explicit newline), and terminators (E1) are considered word deliminators and cause the word wrap logic to be triggered when hit.
Status bytes we're interested in include:
WRAM_VWF_LetterShift C7C2 WRAM_MainScript_TilesDrawn C9CB WRAM_MainScript_NumNewlines C9CE
We also need to allocate a new byte of state in WRAM.
WRAM_WordWrap_LettersLeft ????
This byte will be 0 when it's time to activate the WordWrap routine, and it's counted down after each letter draw (control codes don't count, except for E1 and E2 which sets it 0).
The main WordWrap routine must scan the script string for a suitable string delimiter. Again, we're using space \0, terminate \xE1, and force newline \xE2 as delimiters. If we start on a delimiter, then we just assume that delimiter is a single word. In practice, since WordWrap will be called in the normal text handler, the only delimiter we have to worry about starting on is space.
Then it has to determine the word size in pixels, which is done just by accumulating on the letter length table at ROM B:7B00. Finally we have to calculate how much space we have left, which is done by looking at LetterShift and TilesDrawn.
Formally, the condition for words fitting in the current line of text is...
wordsize <= TilesDrawn * 8 + LetterShift
When a word will not fit, we should immediatly jump to the newline routine as if we encountered a newline. If we were called when the main script pointer is sitting on a character, we should move the main script pointer back first so that the letter will be picked up 'next time'.
Otherwise, we set the LettersLeft counter and continue, and the main script continues drawing characters.