Update Text
Add some new messages, and add support for encoding compressed text
This commit is contained in:
		
							parent
							
								
									67fe623f00
								
							
						
					
					
						commit
						4bda38cc9f
					
				
							
								
								
									
										182
									
								
								Text.py
								
								
								
								
							
							
						
						
									
										182
									
								
								Text.py
								
								
								
								
							| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: UTF-8 -*-
 | 
			
		||||
text_addresses = {'Pedestal': (0x180300, 256),
 | 
			
		||||
                  'Triforce': (0x180400, 256),
 | 
			
		||||
                  'Uncle': (0x180500, 256),
 | 
			
		||||
| 
						 | 
				
			
			@ -137,10 +138,13 @@ Ganon1_texts = [
 | 
			
		|||
    "Did you know?\nThe biggest\nand heaviest\ncheese ever\nproduced\nweighed\n57,518 pounds\nand was 32\nfeet long.",
 | 
			
		||||
    "Now there was\na time, When\nyou loved me\nso. I couldn't\ndo wrong,\nAnd now you\nneed to know.\nSo How you\nlike me now?",
 | 
			
		||||
    "Did you know?\nNutrition\nexperts\nrecommend that\nat least half\nof our daily\ngrains come\nfrom whole\ngrain products",
 | 
			
		||||
    "The Hemiptera\nor true bugs\nare an order\nof insects\ncovering 50k\nto 80k species\nlike aphids,\ncicadas, and\nshield bugs.",
 | 
			
		||||
    "Thanks for\ndropping in,\nthe first\npassengers\nin a hot\nair balloon.\nwere a duck,\na sheep,\nand a rooster.",
 | 
			
		||||
    "You think you\nare so smart?\n\nI bet you\ndidn't know\nYou can't hum\nwhile holding\nyour nose\nclosed.",
 | 
			
		||||
    "grumble,\n\ngrumble…\ngrumble,\n\ngrumble…\nSeriously you\nwere supposed\nto bring food",
 | 
			
		||||
    "Join me hero,\nand I shall\nmake your face\nthe greatest\nin the dark\nworld!\n\nOr else you\nwill die!",
 | 
			
		||||
]
 | 
			
		||||
TavernMan_texts = [
 | 
			
		||||
    'Did you know that talking to random NPCs wastes time in a race? I hope this information may be of use to you in the future.'
 | 
			
		||||
] + [
 | 
			
		||||
    "What do you\ncall a blind\ndinosaur?\nadoyouthink-\nhesaurus\n",
 | 
			
		||||
    "A blind man\nwalks into\na bar.\nAnd a table.\nAnd a chair.\n",
 | 
			
		||||
    "What do ducks\nlike to eat?\n\nQuackers!\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -435,32 +439,78 @@ class SceneLargeCreditLine(SceneCreditLine):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def string_to_alttp_text(s, maxbytes=256):
 | 
			
		||||
    lines = s.upper().split('\n')
 | 
			
		||||
    outbuf = string_to_alttp_core(s)
 | 
			
		||||
 | 
			
		||||
    # check for max length
 | 
			
		||||
    if len(outbuf) > maxbytes - 2:
 | 
			
		||||
        outbuf = outbuf[:maxbytes - 2]
 | 
			
		||||
        # Note: this could crash if the last byte is part of a two byte command
 | 
			
		||||
        # depedning on how well the command handles a value of 0x7F.
 | 
			
		||||
        # Should probably do something about this.
 | 
			
		||||
 | 
			
		||||
    outbuf.append(0x7F)
 | 
			
		||||
    outbuf.append(0x7F)
 | 
			
		||||
    return outbuf
 | 
			
		||||
 | 
			
		||||
special_commands = {
 | 
			
		||||
    "{SPEED0}": [0x7A, 0x00],
 | 
			
		||||
    "{SPEED2}": [0x7A, 0x02],
 | 
			
		||||
    "{SPEED6}": [0x7A, 0x06],
 | 
			
		||||
    "{PAUSE1}": [0x78, 0x01],
 | 
			
		||||
    "{PAUSE3}": [0x78, 0x03],
 | 
			
		||||
    "{PAUSE5}": [0x78, 0x05],
 | 
			
		||||
    "{PAUSE7}": [0x78, 0x07],
 | 
			
		||||
    "{PAUSE9}": [0x78, 0x09],
 | 
			
		||||
    "{INPUT}": [0x7E],
 | 
			
		||||
    "{CHOICE}": [0x68],
 | 
			
		||||
    "{ITEMSELECT}": [0x69],
 | 
			
		||||
    "{CHOICE2}": [0x71],
 | 
			
		||||
    "{CHOICE3}": [0x72],
 | 
			
		||||
    "{HARP}": [0x79, 0x2D],
 | 
			
		||||
    "{MENU}": [0x6D, 0x00],
 | 
			
		||||
    "{BOTTOM}": [0x6D, 0x00],
 | 
			
		||||
    "{NOBORDER}": [0x6B, 0x02],
 | 
			
		||||
    "{CHANGEPIC}": [0x67, 0x67],
 | 
			
		||||
    "{CHANGEMUSIC}": [0x67],
 | 
			
		||||
    "{INTRO}": [0x6E, 0x00, 0x77, 0x07, 0x7A, 0x03, 0x6B, 0x02, 0x67],
 | 
			
		||||
    "{NOTEXT}": [0x6E, 0x00, 0x6B, 0x04],
 | 
			
		||||
    "{IBOX}": [0x6B, 0x02, 0x77, 0x07, 0x7A, 0x03],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def string_to_alttp_core(s, pause=True, wrap=14):
 | 
			
		||||
    s = s.upper()
 | 
			
		||||
    lines = s.split('\n')
 | 
			
		||||
    outbuf = bytearray()
 | 
			
		||||
    lineindex = 0
 | 
			
		||||
    is_intro = '{INTRO}' in s
 | 
			
		||||
 | 
			
		||||
    while lines:
 | 
			
		||||
        linespace = 14
 | 
			
		||||
        linespace = wrap
 | 
			
		||||
        line = lines.pop(0)
 | 
			
		||||
        if line.startswith('{'):
 | 
			
		||||
            outbuf.extend(special_commands[line])
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        words = line.split(' ')
 | 
			
		||||
        outbuf.append(0x74 if lineindex == 0 else 0x75 if lineindex == 1 else 0x76)  # line starter
 | 
			
		||||
 | 
			
		||||
        while words:
 | 
			
		||||
            word = words.pop(0)
 | 
			
		||||
            # sanity check: if the word we have is more than 14 characters, we take as much as we can still fit and push the rest back for later
 | 
			
		||||
            if len(word) > 14:
 | 
			
		||||
                if linespace < 14:
 | 
			
		||||
            if wordlen(word) > wrap:
 | 
			
		||||
                if linespace < wrap:
 | 
			
		||||
                    word = ' ' + word
 | 
			
		||||
                word_first = word[:linespace]
 | 
			
		||||
                words.insert(0, word[linespace:])
 | 
			
		||||
                (word_first, word_rest) = splitword(word, linespace)
 | 
			
		||||
                words.insert(0, word_rest)
 | 
			
		||||
                lines.insert(0, ' '.join(words))
 | 
			
		||||
 | 
			
		||||
                write_word(outbuf, word_first)
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            if len(word) <= (linespace if linespace == 14 else linespace - 1):
 | 
			
		||||
                if linespace < 14:
 | 
			
		||||
            if wordlen(word) <= (linespace if linespace == wrap else linespace - 1):
 | 
			
		||||
                if linespace < wrap:
 | 
			
		||||
                    word = ' ' + word
 | 
			
		||||
                linespace -= len(word)
 | 
			
		||||
                linespace -= wordlen(word)
 | 
			
		||||
                write_word(outbuf, word)
 | 
			
		||||
            else:
 | 
			
		||||
                # ran out of space, push word and lines back and continue with next line
 | 
			
		||||
| 
						 | 
				
			
			@ -468,26 +518,102 @@ def string_to_alttp_text(s, maxbytes=256):
 | 
			
		|||
                lines.insert(0, ' '.join(words))
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if is_intro and lineindex < 3:
 | 
			
		||||
            outbuf.extend([0xFF]*linespace)
 | 
			
		||||
 | 
			
		||||
        has_more_lines = len(lines) > 1 or (lines and not lines[0].startswith('{'))
 | 
			
		||||
 | 
			
		||||
        lineindex += 1
 | 
			
		||||
        if lineindex % 3 == 0 and lines:
 | 
			
		||||
        if pause and lineindex % 3 == 0 and has_more_lines:
 | 
			
		||||
            outbuf.append(0x7E)
 | 
			
		||||
        if lineindex >= 3 and lines:
 | 
			
		||||
        if lineindex >= 3 and has_more_lines:
 | 
			
		||||
            outbuf.append(0x73)
 | 
			
		||||
    return outbuf
 | 
			
		||||
 | 
			
		||||
    # check for max length
 | 
			
		||||
    if len(outbuf) > maxbytes - 1:
 | 
			
		||||
        outbuf = outbuf[:maxbytes - 1]
 | 
			
		||||
        # make sure we interpret the end of box character
 | 
			
		||||
        if outbuf[-1] == 0x00:
 | 
			
		||||
            outbuf[-1] = 0x73
 | 
			
		||||
two_byte_commands = [
 | 
			
		||||
    0x6B, 0x6C, 0x6D, 0x6E,
 | 
			
		||||
    0x77, 0x78, 0x79, 0x7A
 | 
			
		||||
]
 | 
			
		||||
specially_coded_commands = {
 | 
			
		||||
    0x73: 0xF6,
 | 
			
		||||
    0x74: 0xF7,
 | 
			
		||||
    0x75: 0xF8,
 | 
			
		||||
    0x76: 0xF9,
 | 
			
		||||
    0x7E: 0xFA,
 | 
			
		||||
    0x7A: 0xFC,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    outbuf.append(0x7F)
 | 
			
		||||
def string_to_alttp_text_compressed(s, pause=True, max_bytes_expanded=0x800, wrap=14):
 | 
			
		||||
    inbuf = string_to_alttp_core(s, pause, wrap)
 | 
			
		||||
 | 
			
		||||
    # Links name will need 8 bytes in the target buffer
 | 
			
		||||
    # and two will be used by the terminator
 | 
			
		||||
    # (Variables will use 2 bytes, but they start as 2 bytes)
 | 
			
		||||
    bufsize = len(inbuf) + 7 * inbuf.count(0x6A) + 2
 | 
			
		||||
    if bufsize > max_bytes_expanded:
 | 
			
		||||
        raise ValueError("Uncompressed string too long for buffer")
 | 
			
		||||
    inbuf.reverse()
 | 
			
		||||
    outbuf = bytearray()
 | 
			
		||||
    outbuf.append(0xfb) # terminator for previous record
 | 
			
		||||
    while inbuf:
 | 
			
		||||
        val = inbuf.pop()
 | 
			
		||||
        if val == 0xFF:
 | 
			
		||||
            outbuf.append(val)
 | 
			
		||||
        elif val == 0x00:
 | 
			
		||||
            outbuf.append(inbuf.pop())
 | 
			
		||||
        elif val == 0x01: #kanji
 | 
			
		||||
            outbuf.append(0xFD)
 | 
			
		||||
            outbuf.append(inbuf.pop())
 | 
			
		||||
        elif val >= 0x67:
 | 
			
		||||
            if val in specially_coded_commands:
 | 
			
		||||
                outbuf.append(specially_coded_commands[val])
 | 
			
		||||
            else:
 | 
			
		||||
                outbuf.append(0xFE)
 | 
			
		||||
                outbuf.append(val)
 | 
			
		||||
            if val in two_byte_commands:
 | 
			
		||||
                outbuf.append(inbuf.pop())
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError("Unexpected byte found in uncompressed string")
 | 
			
		||||
    return outbuf
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def wordlen(word):
 | 
			
		||||
    l = 0
 | 
			
		||||
    offset = 0
 | 
			
		||||
    while offset < len(word):
 | 
			
		||||
        c_len, offset = charlen(word, offset)
 | 
			
		||||
        l += c_len
 | 
			
		||||
    return l
 | 
			
		||||
 | 
			
		||||
def splitword(word, length):
 | 
			
		||||
    l = 0
 | 
			
		||||
    offset = 0
 | 
			
		||||
    while True:
 | 
			
		||||
        c_len, new_offset = charlen(word, offset)
 | 
			
		||||
        if l+c_len > length:
 | 
			
		||||
            break
 | 
			
		||||
        l += c_len
 | 
			
		||||
        offset = new_offset
 | 
			
		||||
    return (word[0:offset], word[offset:])
 | 
			
		||||
 | 
			
		||||
def charlen(word, offset):
 | 
			
		||||
    c = word[offset]
 | 
			
		||||
    if c in ['>', '¼', '½', '♥']:
 | 
			
		||||
        return (2, offset+1)
 | 
			
		||||
    if c in ['@']:
 | 
			
		||||
        return (4, offset+1)
 | 
			
		||||
    if c in ['ᚋ', 'ᚌ', 'ᚍ', 'ᚎ']:
 | 
			
		||||
        return (2, offset+1)
 | 
			
		||||
    return (1, offset+1)
 | 
			
		||||
 | 
			
		||||
def write_word(buf, word):
 | 
			
		||||
    for char in word:
 | 
			
		||||
        buf.extend([0x00, char_to_alttp_char(char)])
 | 
			
		||||
        res = char_to_alttp_char(char)
 | 
			
		||||
        if isinstance(res, int):
 | 
			
		||||
            buf.extend([0x00, res])
 | 
			
		||||
        else:
 | 
			
		||||
            buf.extend(res)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char_map = {' ': 0xFF,
 | 
			
		||||
| 
						 | 
				
			
			@ -499,12 +625,26 @@ char_map = {' ': 0xFF,
 | 
			
		|||
            '.': 0xCD,
 | 
			
		||||
            '~': 0xCE,
 | 
			
		||||
            '~': 0xCE,
 | 
			
		||||
            '>': [0x6A], # Links name (only works if compressed)
 | 
			
		||||
            '@': [0x00, 0xD2, 0x00, 0xD3], # Link's face
 | 
			
		||||
            "'": 0xD8,
 | 
			
		||||
            '’': 0xD8,
 | 
			
		||||
            '%': 0xDD, # Hylian Bird
 | 
			
		||||
            '^': 0xDE, # Hylian Ankh
 | 
			
		||||
            '=': 0xDF, # Hylian Wavy Lines
 | 
			
		||||
            '↑': 0xE0,
 | 
			
		||||
            '↓': 0xE1,
 | 
			
		||||
            '→': 0xE2,
 | 
			
		||||
            '←': 0xE3,
 | 
			
		||||
            '≥': 0xE4, # Cursor
 | 
			
		||||
            '¼': [0x00, 0xE5, 0x00, 0xE7], # ¼ heart
 | 
			
		||||
            '½': [0x00, 0xE6, 0x00, 0xE7], # ½ heart
 | 
			
		||||
            '¾': [0x00, 0xE8, 0x00, 0xE9], # ¾ heart
 | 
			
		||||
            '♥': [0x00, 0xEA, 0x00, 0xEB], # full heart
 | 
			
		||||
            'ᚋ': [0x6C, 0x00], # var 0
 | 
			
		||||
            'ᚌ': [0x6C, 0x01], # var 1
 | 
			
		||||
            'ᚍ': [0x6C, 0x02], # var 2
 | 
			
		||||
            'ᚎ': [0x6C, 0x03], # var 3
 | 
			
		||||
            'あ': 0x00,
 | 
			
		||||
            'い': 0x01,
 | 
			
		||||
            'う': 0x02,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue