324 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
| import re
 | ||
| 
 | ||
| class Dialog:
 | ||
| 
 | ||
|     command = re.compile(r"^\{[^}]*\}")
 | ||
|     invalid = re.compile(r"(?<!^)\{[^}]*\}(?!$)", re.MULTILINE)
 | ||
|     digit = re.compile(r"\d")
 | ||
|     uppercaseLetter = re.compile(r"[A-Z]")
 | ||
|     lowercaseLetter = re.compile(r"[a-z]")
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def Simple(text: str):
 | ||
|         maxBytes = 256
 | ||
|         wrap = 19
 | ||
| 
 | ||
|         bytes = []
 | ||
|         lines = text.split('\n')
 | ||
|         lineIndex = 0
 | ||
|         for line in lines:
 | ||
|             bytes.append(0x74 if 0 else 0x75 if 1 else 0x76)
 | ||
|             letters = line[:wrap] if len(line) > wrap else line
 | ||
|             for letter in letters:
 | ||
|                 write = Dialog.LetterToBytes(letter)
 | ||
|                 if (write[0] == 0xFD):
 | ||
|                     bytes += write
 | ||
|                 else:
 | ||
|                     for b in write:
 | ||
|                         bytes += [ 0x00, b ]
 | ||
| 
 | ||
|             lineIndex += 1
 | ||
| 
 | ||
|             if (lineIndex % 3 == 0 and lineIndex < len(lines)):
 | ||
|                 bytes.append(0x7E)
 | ||
|             if (lineIndex >= 3 and lineIndex < len(lines)):
 | ||
|                 bytes.append(0x73)
 | ||
| 
 | ||
|         bytes.append(0x7F)
 | ||
|         if (len(bytes) > maxBytes):
 | ||
|             return bytes[:maxBytes - 1].append(0x7F)
 | ||
| 
 | ||
|         return bytes
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def Compiled(text: str, pause = True):
 | ||
|         maxBytes = 2046
 | ||
|         wrap = 19
 | ||
| 
 | ||
|         if (Dialog.invalid.match(text)):
 | ||
|             raise Exception("Dialog commands must be placed on separate lines", text)
 | ||
| 
 | ||
|         padOut = False
 | ||
| 
 | ||
|         bytes = [ 0xFB ]
 | ||
|         lines = Dialog.Wordwrap(text, wrap)
 | ||
|         lineCount = len([l for l in lines if not Dialog.command.match(l)])
 | ||
|         lineIndex = 0
 | ||
|         for line in lines:
 | ||
|             match = Dialog.command.match(line)
 | ||
|             if (match is not None):
 | ||
|                 if (match.string == "{NOTEXT}"):
 | ||
|                     return [ 0xFB, 0xFE, 0x6E, 0x00, 0xFE, 0x6B, 0x04 ]
 | ||
|                 if (match.string == "{INTRO}"):
 | ||
|                     padOut = True
 | ||
| 
 | ||
|                 bytesMap = {
 | ||
|                             "{SPEED0}" : [ 0xFC, 0x00 ],
 | ||
|                             "{SPEED2}" : [ 0xFC, 0x02 ],
 | ||
|                             "{SPEED6}" : [ 0xFC, 0x06 ],
 | ||
|                             "{PAUSE1}" : [ 0xFE, 0x78, 0x01 ],
 | ||
|                             "{PAUSE3}" : [ 0xFE, 0x78, 0x03 ],
 | ||
|                             "{PAUSE5}" : [ 0xFE, 0x78, 0x05 ],
 | ||
|                             "{PAUSE7}" : [ 0xFE, 0x78, 0x07 ],
 | ||
|                             "{PAUSE9}" : [ 0xFE, 0x78, 0x09 ],
 | ||
|                             "{INPUT}" : [ 0xFA ],
 | ||
|                             "{CHOICE}" : [ 0xFE, 0x68 ],
 | ||
|                             "{ITEMSELECT}" : [ 0xFE, 0x69 ],
 | ||
|                             "{CHOICE2}" : [ 0xFE, 0x71 ],
 | ||
|                             "{CHOICE3}" : [ 0xFE, 0x72 ],
 | ||
|                             "{C:GREEN}" : [ 0xFE, 0x77, 0x07 ],
 | ||
|                             "{C:YELLOW}" : [ 0xFE, 0x77, 0x02 ],
 | ||
|                             "{HARP}" : [ 0xFE, 0x79, 0x2D ],
 | ||
|                             "{MENU}" : [ 0xFE, 0x6D, 0x00 ],
 | ||
|                             "{BOTTOM}" : [ 0xFE, 0x6D, 0x01 ],
 | ||
|                             "{NOBORDER}" : [ 0xFE, 0x6B, 0x02 ],
 | ||
|                             "{CHANGEPIC}" : [ 0xFE, 0x67, 0xFE, 0x67 ],
 | ||
|                             "{CHANGEMUSIC}" : [ 0xFE, 0x67 ],
 | ||
|                             "{INTRO}" : [ 0xFE, 0x6E, 0x00, 0xFE, 0x77, 0x07, 0xFC, 0x03, 0xFE, 0x6B, 0x02, 0xFE, 0x67 ],
 | ||
|                             "{IBOX}" : [ 0xFE, 0x6B, 0x02, 0xFE, 0x77, 0x07, 0xFC, 0x03, 0xF7 ],
 | ||
|                         }
 | ||
|                 result = bytesMap.get(match.string, None)
 | ||
|                 if (result is None):
 | ||
|                     raise Exception(f"Dialog text contained unknown command {match.string}", text)
 | ||
|                 else:
 | ||
|                     bytes += result
 | ||
| 
 | ||
|                 if (len(bytes) > maxBytes):
 | ||
|                     raise Exception("Command overflowed maximum byte length", text)
 | ||
| 
 | ||
|                 continue
 | ||
| 
 | ||
|             if (lineIndex == 1):
 | ||
|                 bytes.append(0xF8); #// row 2
 | ||
|             elif (lineIndex >= 3 and lineIndex < lineCount):
 | ||
|                 bytes.append(0xF6); #// scroll
 | ||
|             elif (lineIndex >= 2):
 | ||
|                 bytes.append(0xF9); #// row 3
 | ||
| 
 | ||
|             #// The first box needs to fill the full width with spaces as the palette is loaded weird.
 | ||
|             letters = line + (" " * wrap) if padOut and lineIndex < 3 else line
 | ||
|             for letter in letters:
 | ||
|                 bytes += Dialog.LetterToBytes(letter)
 | ||
| 
 | ||
|             lineIndex += 1
 | ||
| 
 | ||
|             if (pause and lineIndex % 3 == 0 and lineIndex < lineCount):
 | ||
|                 bytes.append(0xFA) #// wait for input
 | ||
| 
 | ||
|         return bytes[:maxBytes]
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def Wordwrap(text: str, width: int):
 | ||
|         result = []
 | ||
|         for line in text.split('\n'):
 | ||
|             line = line.rstrip()
 | ||
|             if (len(line) <= width):
 | ||
|                 result.append(line)
 | ||
|             else:
 | ||
|                 words = line.split(' ')
 | ||
|                 lines = [ "" ]
 | ||
|                 for word in words:
 | ||
|                     line = lines.pop()
 | ||
|                     if (len(line) + len(word) <= width):
 | ||
|                         line = f"{line}{word} "
 | ||
|                     else:
 | ||
|                         if (len(line) > 0):
 | ||
|                             lines.append(line)
 | ||
|                         line = word
 | ||
|                         while (len(line) > width):
 | ||
|                             lines.append(line[:width])
 | ||
|                             line = line[width:]
 | ||
|                         line = f"{line} "
 | ||
|                     lines.append(line)
 | ||
|                 #lines.reverse()
 | ||
|                 result += [l.strip() for l in lines]
 | ||
|         return result
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def LetterToBytes(c: str):
 | ||
|         if Dialog.digit.match(c): return [(ord(c) - ord('0') + 0xA0) ]
 | ||
|         elif Dialog.uppercaseLetter.match(c): return [ (ord(c) - ord('A') + 0xAA) ]
 | ||
|         elif Dialog.lowercaseLetter.match(c): return [ (ord(c) - ord('a') + 0x30) ]
 | ||
|         else:
 | ||
|             value = Dialog.letters.get(c, None)
 | ||
|             return value if value else [ 0xFF ]
 | ||
| 
 | ||
|         #region letter bytes lookup
 | ||
| 
 | ||
|     letters = {
 | ||
|         ' ' : [ 0x4F ],
 | ||
|         '?' : [ 0xC6 ],
 | ||
|         '!' : [ 0xC7 ],
 | ||
|         ',' : [ 0xC8 ],
 | ||
|         '-' : [ 0xC9 ],
 | ||
|         '…' : [ 0xCC ],
 | ||
|         '.' : [ 0xCD ],
 | ||
|         '~' : [ 0xCE ],
 | ||
|         '~' : [ 0xCE ],
 | ||
|         '\'' : [ 0xD8 ],
 | ||
|         '’' : [ 0xD8 ],
 | ||
|         '"' : [ 0xD8 ],
 | ||
|         ':' : [ 0x4A ],
 | ||
|         '@' : [ 0x4B ],
 | ||
|         '#' : [ 0x4C ],
 | ||
|         '¤' : [ 0x4D, 0x4E ], #// Morphing ball
 | ||
|         '_' : [ 0xFF ], #// Full width space
 | ||
|         '£' : [ 0xFE, 0x6A ], #// link's name compressed
 | ||
|         '>' : [ 0xD2, 0xD3 ], #// link face
 | ||
|         '%' : [ 0xDD ], #// Hylian Bird
 | ||
|         '^' : [ 0xDE ], #// Hylian Ankh
 | ||
|         '=' : [ 0xDF ], #// Hylian Wavy lines
 | ||
|         '↑' : [ 0xE0 ],
 | ||
|         '↓' : [ 0xE1 ],
 | ||
|         '→' : [ 0xE2 ],
 | ||
|         '←' : [ 0xE3 ],
 | ||
|         '≥' : [ 0xE4 ], #// cursor
 | ||
|         '¼' : [ 0xE5, 0xE7 ], #// 1/4 heart
 | ||
|         '½' : [ 0xE6, 0xE7 ], #// 1/2 heart
 | ||
|         '¾' : [ 0xE8, 0xE9 ], #// 3/4 heart
 | ||
|         '♥' : [ 0xEA, 0xEB ], #// full heart
 | ||
|         'ᚋ' : [ 0xFE, 0x6C, 0x00 ], #// var 0
 | ||
|         'ᚌ' : [ 0xFE, 0x6C, 0x01 ], #// var 1
 | ||
|         'ᚍ' : [ 0xFE, 0x6C, 0x02 ], #// var 2
 | ||
|         'ᚎ' : [ 0xFE, 0x6C, 0x03 ], #// var 3
 | ||
| 
 | ||
|         'あ' : [ 0x00 ],
 | ||
|         'い' : [ 0x01 ],
 | ||
|         'う' : [ 0x02 ],
 | ||
|         'え' : [ 0x03 ],
 | ||
|         'お' : [ 0x04 ],
 | ||
|         'や' : [ 0x05 ],
 | ||
|         'ゆ' : [ 0x06 ],
 | ||
|         'よ' : [ 0x07 ],
 | ||
|         'か' : [ 0x08 ],
 | ||
|         'き' : [ 0x09 ],
 | ||
|         'く' : [ 0x0A ],
 | ||
|         'け' : [ 0x0B ],
 | ||
|         'こ' : [ 0x0C ],
 | ||
|         'わ' : [ 0x0D ],
 | ||
|         'を' : [ 0x0E ],
 | ||
|         'ん' : [ 0x0F ],
 | ||
|         'さ' : [ 0x10 ],
 | ||
|         'し' : [ 0x11 ],
 | ||
|         'す' : [ 0x12 ],
 | ||
|         'せ' : [ 0x13 ],
 | ||
|         'そ' : [ 0x14 ],
 | ||
|         'が' : [ 0x15 ],
 | ||
|         'ぎ' : [ 0x16 ],
 | ||
|         'ぐ' : [ 0x17 ],
 | ||
|         'た' : [ 0x18 ],
 | ||
|         'ち' : [ 0x19 ],
 | ||
|         'つ' : [ 0x1A ],
 | ||
|         'て' : [ 0x1B ],
 | ||
|         'と' : [ 0x1C ],
 | ||
|         'げ' : [ 0x1D ],
 | ||
|         'ご' : [ 0x1E ],
 | ||
|         'ざ' : [ 0x1F ],
 | ||
|         'な' : [ 0x20 ],
 | ||
|         'に' : [ 0x21 ],
 | ||
|         'ぬ' : [ 0x22 ],
 | ||
|         'ね' : [ 0x23 ],
 | ||
|         'の' : [ 0x24 ],
 | ||
|         'じ' : [ 0x25 ],
 | ||
|         'ず' : [ 0x26 ],
 | ||
|         'ぜ' : [ 0x27 ],
 | ||
|         'は' : [ 0x28 ],
 | ||
|         'ひ' : [ 0x29 ],
 | ||
|         'ふ' : [ 0x2A ],
 | ||
|         'へ' : [ 0x2B ],
 | ||
|         'ほ' : [ 0x2C ],
 | ||
|         'ぞ' : [ 0x2D ],
 | ||
|         'だ' : [ 0x2E ],
 | ||
|         'ぢ' : [ 0x2F ],
 | ||
| 
 | ||
|         'ア' : [ 0x50 ],
 | ||
|         'イ' : [ 0x51 ],
 | ||
|         'ウ' : [ 0x52 ],
 | ||
|         'エ' : [ 0x53 ],
 | ||
|         'オ' : [ 0x54 ],
 | ||
|         'ヤ' : [ 0x55 ],
 | ||
|         'ユ' : [ 0x56 ],
 | ||
|         'ヨ' : [ 0x57 ],
 | ||
|         'カ' : [ 0x58 ],
 | ||
|         'キ' : [ 0x59 ],
 | ||
|         'ク' : [ 0x5A ],
 | ||
|         'ケ' : [ 0x5B ],
 | ||
|         'コ' : [ 0x5C ],
 | ||
|         'ワ' : [ 0x5D ],
 | ||
|         'ヲ' : [ 0x5E ],
 | ||
|         'ン' : [ 0x5F ],
 | ||
|         'サ' : [ 0x60 ],
 | ||
|         'シ' : [ 0x61 ],
 | ||
|         'ス' : [ 0x62 ],
 | ||
|         'セ' : [ 0x63 ],
 | ||
|         'ソ' : [ 0x64 ],
 | ||
|         'ガ' : [ 0x65 ],
 | ||
|         'ギ' : [ 0x66 ],
 | ||
|         'グ' : [ 0x67 ],
 | ||
|         'タ' : [ 0x68 ],
 | ||
|         'チ' : [ 0x69 ],
 | ||
|         'ツ' : [ 0x6A ],
 | ||
|         'テ' : [ 0x6B ],
 | ||
|         'ト' : [ 0x6C ],
 | ||
|         'ゲ' : [ 0x6D ],
 | ||
|         'ゴ' : [ 0x6E ],
 | ||
|         'ザ' : [ 0x6F ],
 | ||
|         'ナ' : [ 0x70 ],
 | ||
|         'ニ' : [ 0x71 ],
 | ||
|         'ヌ' : [ 0x72 ],
 | ||
|         'ネ' : [ 0x73 ],
 | ||
|         'ノ' : [ 0x74 ],
 | ||
|         'ジ' : [ 0x75 ],
 | ||
|         'ズ' : [ 0x76 ],
 | ||
|         'ゼ' : [ 0x77 ],
 | ||
|         'ハ' : [ 0x78 ],
 | ||
|         'ヒ' : [ 0x79 ],
 | ||
|         'フ' : [ 0x7A ],
 | ||
|         'ヘ' : [ 0x7B ],
 | ||
|         'ホ' : [ 0x7C ],
 | ||
|         'ゾ' : [ 0x7D ],
 | ||
|         'ダ' : [ 0x7E ],
 | ||
|         'マ' : [ 0x80 ],
 | ||
|         'ミ' : [ 0x81 ],
 | ||
|         'ム' : [ 0x82 ],
 | ||
|         'メ' : [ 0x83 ],
 | ||
|         'モ' : [ 0x84 ],
 | ||
|         'ヅ' : [ 0x85 ],
 | ||
|         'デ' : [ 0x86 ],
 | ||
|         'ド' : [ 0x87 ],
 | ||
|         'ラ' : [ 0x88 ],
 | ||
|         'リ' : [ 0x89 ],
 | ||
|         'ル' : [ 0x8A ],
 | ||
|         'レ' : [ 0x8B ],
 | ||
|         'ロ' : [ 0x8C ],
 | ||
|         'バ' : [ 0x8D ],
 | ||
|         'ビ' : [ 0x8E ],
 | ||
|         'ブ' : [ 0x8F ],
 | ||
|         'ベ' : [ 0x90 ],
 | ||
|         'ボ' : [ 0x91 ],
 | ||
|         'パ' : [ 0x92 ],
 | ||
|         'ピ' : [ 0x93 ],
 | ||
|         'プ' : [ 0x94 ],
 | ||
|         'ペ' : [ 0x95 ],
 | ||
|         'ポ' : [ 0x96 ],
 | ||
|         'ャ' : [ 0x97 ],
 | ||
|         'ュ' : [ 0x98 ],
 | ||
|         'ョ' : [ 0x99 ],
 | ||
|         'ッ' : [ 0x9A ],
 | ||
|         'ァ' : [ 0x9B ],
 | ||
|         'ィ' : [ 0x9C ],
 | ||
|         'ゥ' : [ 0x9D ],
 | ||
|         'ェ' : [ 0x9E ],
 | ||
|         'ォ' : [ 0x9F ],
 | ||
|     }
 |