commit
						ee7ad585f0
					
				
							
								
								
									
										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