My text system is a little complicated, I wasn't exactly trying to submit a good bug report, but rather to see if anyone had experienced anything like this (based on symptoms) or if anyone had ideas. Luckily, the non-breaking space worked like a charm.
I suppose there are two issues:
1. Leading spaces are always trimmed
2. Tab character is not always handled correctly (whether actual Tab or Chr(9)
This second case has some more details:
I tried Chr(11) VT vertical tab, Chr(12) FF form feed, and a couple others that I can't remember. Interestingly, they all behaved like Tabs, they made a few spaces. And they all SOMETIMES were replaced with "n"s. I could exit my channel and restart it 10 times, and get 8 times correct indentations and 2 times the "n"s, it was totally inconsistent and unreliable.
Here is the Function I was working on:
FUNCTION longTexts(title AS STRING) AS STRING ' trig by initBook(1) ' Chr(0) null, Chr(9) Tab, Chr(10) LF, Chr(13) CR, Chr(32) sp, Chr(34) dbl quotes, Chr(11) VT, Chr(12) FF, Chr(160) nbsp
' TB = "" + Chr(9)
TB = Chr(9)
' TB = "" + Chr(32) + Chr(32) + Chr(32) ' This doesn't work, no spaces or "tab" appears
' TB = "" + Chr(0) + Chr(32) + Chr(32) + Chr(32) + "" ' This doesn't work either
' PH = "" + Chr(10) + Chr(10) + Chr(9)
' PH = Chr(10) + Chr(10) + Chr(11) + Chr(32) + Chr(32) + Chr(32) + Chr(0) ' Vertical Tab works! But just as prone to "n" bug ' BUT, this retained the spaces after...
' PH = Chr(10) + Chr(10) + Chr(11) ' Just a regular Tab size, prone to "n" bug
' PH = "" + Chr(10) + Chr(10) + Chr(32) + Chr(32) + Chr(32)
' PH = "" + Chr(10) + Chr(10) + Chr(0) + Chr(32) + Chr(32) + Chr(32) + ""
' PH = Chr(10) + Chr(10) + Chr(12) + Chr(32) + Chr(32) + Chr(32) + Chr(12) ' Form Feed works, interesting... ' Nope, Form Feed seems prone to "n" bug too
' but at least between the "n"s are the spaces, maybe there is some other blank character I can stick spaces inbetween
' PH = Chr(10) + Chr(10) + Chr(12) ' Nope, Form Feed seems prone to "n" bug too
PH = Chr(10) + Chr(10) + Chr(160) + Chr(32) + Chr(32) + Chr(32) + Chr(160) ' Wow, Chr(160) nbsp works, thanks to TheEndless
' PH = Chr(10) + Chr(10) + " " + Chr(32) + Chr(32) + Chr(32) + Chr(0)
texts = {
intro: TB + "This is the story of Elendia's Esteem, the highest grace and favor ever bestowed upon a human, only granted once in all the ages known to the recorders." + PH + "In the Kingdom of Evermore, many gods and goddesses compete to influence the lives of the people, to gain their loyalty and worship, and to guide the events of the heavens in their own favor. Elendia is one such diety, a member of the Prime Synod, the ancient council of the gods formed by common consent of those oldest of beings, long ago in a time of chaos and disorder." + PH + "With her rivals Thanor, Kyrindia, and Loxus, Elendia agreed to divide the world into four kingdoms, and she named her domain Evermore, after the longing in her heart to lead the people toward eternal growth and divine progression, never to end, becoming greater evermore." + PH + "In time, peace and order coalesced upon the world, to the satifaction of the Prime Synod, and it was into this order that the Untried emerged. They are the lesser gods, unversed and untested, powerful but limited. They never knew a world of chaos, and their followers come and go. The Untried dain to compete with their elder deities, and cause their mischief as they can." + PH + "The oldest manuscripts of the recorders, copies of copies, tell us the tale of prince Albrecht. He was the youngest son of the king, and unlauded, so he desired to prove his valor." + PH + "In search of a task he might accomplish, he sought out the wisdom of oracles of his day, whom we would now call sages, but from the record it appears they harbored a stronger connection to the heavens than that." + PH + "Albrecht was instructed not to perform some great feat of strength or dexterity, but rather was told to lift others, to become a guidestone in the lives of the many, to better the position of the common man." + PH + "Time passed, and Albrecht pondered how he might fulfill the quest. This feat was like no other he had heard of, yet it rang true in his heart." + PH + "One day, while fasting and meditating atop the highest tower of the kingdom, the Skyward Hand (remnants of its foundation are still visible to this day in Hightowne), he beheld in vision the people of the kingdom. He saw them taking up arms against a dark and shadowy foe, layered in ranks upon the hillsides below them, his people formed all about the top." + PH + "From the earliest shades of dawn to the faintest light of dusk, his people cast down the devils from the hill top, again and again. An endless onslaught, repelled, returning, repelled again." + PH + "As he watched the fighters clash, he saw that the black shapes of the enemy seemed to match the outlines of their brighter counterparts. Indeed, upon close inspection, he believed it was in fact true that each man fought an exact copy of himself, only without light or visage." + PH + "In an instant Albrecht knew the meaning, that each man fought against his baser half, his low instincts, the parts of him that would drag him down and see him mired in self-indulgence. Leaning forward in his trance, he focused his mind forward to the end of the battle. He saw his people begin to prevail, their light shining forth ever more brightly, their dark foes diminishing day by day through the struggle." + PH + "Then, an unexpected thing occurred. Where each shadow fell, a tree sprung up. In his vision, time passed in a strange manner - the trees grew praeternaturally fast, while the men and devils fought impossibly slow. It was such that limbs of men and trees moved at the same speed; struggle matched growth." + PH + "Albrecht witnessed many individuals felling some of the trees and carving out new weapons and shields from the wood. They built homes and lives from it. The whole foundation of their society began to grow by it, and as this occurred, fewer and fewer dark shapes emerged from the valleys below." + PH + "After eons of fighting, living, conquering, his people prevailed. Darkness retreated, leaving a shining city on a hill in its wake. Tall forests of strong trees covered the land, teeming with life and sustenance, while men labored and took joy in their work. Women and children crafted and played and loved, and all were whole and happy." + PH + "The vision faded away, and the young prince Albrecht felt his own form wavering. He was weak and drained, and could not stand. Servants bore him to his room, where he was attended for three days while he regained his strength."
}
RETURN texts[title]
END FUNCTION
After that the big string goes to get split up in to many small lines and positioned on the page according as they fit, divided into multiple pages that can be flipped with right/left. It's my in-game book system.
longTexts() is called by initBook()
FUNCTION initBook(bk) ' trig by interactCheck(1), noted by objctInfo(1) "book", trig ind by useItem(1)
'? "initBook() running"
m.cAA.mainMenu.Lv = -1 ' Turn off main menus ' This would happen if reading a bk fom inven
title = textDatabase(bk.dscr, 1) ' Get the book's title from the text database
text = longTexts(title) ' Get the actual book long-text
dbook = m.drAA.book
dbook.book = TRUE
w = 7*64 + 16
lines = splitBlockText(text, w, m.drAA.font)
pages = []
WHILE lines.Count() > 11 ' Take out first 11 lines and put them into a "page"
page = []
IF lines[ 0] = "" THEN lines.Shift() ' Take out any blank line at the top ' This could possibly reduce lines.Count to exactly 11 (if it was 12)
FOR i = 1 TO 11
page.Push(lines.Shift())
END FOR
pages.Push(page)
END WHILE
IF lines.Count() > 0 THEN pages.Push(lines) ' At this point there should be <= 11 lines left for the last page, and there could be 0 if a blank line was removed from previous page top
dbook.pages = pages
dbook.pg = 0
dbook.pgs = pages.Count() -1
setBookPages()
initBookSprites(dbook)
'SOUND ' play "open book" sound
dbook.theBook = bk ' Store bk so exitBook() can check for any .linkTo deact
IF bk.linkTo <> INVALID THEN doLink("on", bk, y, x, rm) ' If book has a linkTo, do it ' Send trig as "on" (act)
END FUNCTION
And here is splitBlockText() that RokuMarkn gave to me (I've never fully understood it - maybe this is stripping out leading spaces?)
FUNCTION splitBlockText(text AS STRING, width AS INTEGER, font AS OBJECT) AS OBJECT ' trig by prepText(1), drawConvo(1), initBook(1) ' From RokuMarkn, updated to handle New Lines w/ Chr(10)
' Ascii 10 is New Line or Line Feed. Enter into strings like: "Hello."+Chr(10)+"Goodbye." ' Don't use "/n" because both / and n are delims, so all n's cause split!
'timer = createObject("roTimespan") ' For measuring performance
splitTextLines = []
linePos = 0
WHILE TRUE
WHILE text.Mid(linePos, 1) = " " ' Mid(start_index as Integer, num_chars as Integer) as String. Ex: s.Mid(0, 1) returns the first letter of s, while s.Mid(2, 2) returns the 3rd and 4th letters
linePos = linePos +1
END WHILE
endLine = linePos ' Set endLine to the current position, and test it below
' Output line starts here; step thru words.
WHILE TRUE
IF endLine >= text.Len() THEN
IF endLine > linePos THEN splitTextLines.Push(text.Mid(linePos, endLine - linePos))
'? "SplitBlockText() took " timer.totalMilliseconds()
RETURN splitTextLines
END IF
newline = (text.Mid(endLine, 1) = Chr(10)) ' If the second two parts are equivalent, newline will be TRUE
IF NOT newline THEN e = endWord(text, endLine)
IF newline OR font.GetOneLineWidth(text.Mid(linePos, e - linePos), width) >= width THEN
splitTextLines.Push(text.Mid(linePos, endLine - linePos))
linePos = endLine
IF newline THEN linePos = linePos +1
EXIT WHILE
END IF
endLine = e
END WHILE
END WHILE
END FUNCTION
FUNCTION endWord(text AS STRING, index AS INTEGER) AS INTEGER 'trig by SplitBlockText(1), from RokuMarkn on the dev forums
FOR p = index TO text.Len()
IF text.Mid(p, 1) <> " " THEN EXIT FOR
END FOR
FOR p = p TO text.Len()
IF text.Mid(p, 1) = " " OR text.Mid(p, 1) = Chr(10) THEN EXIT FOR ' Handling for New Lines
END FOR
RETURN p
END FUNCTION