2017-10-29 03:42:35 +00:00
text_addresses = { ' Pedestal ' : ( 0x180300 , 256 ) ,
2017-05-20 12:07:19 +00:00
' Triforce ' : ( 0x180400 , 256 ) ,
' Uncle ' : ( 0x180500 , 256 ) ,
' Ganon1 ' : ( 0x180600 , 256 ) ,
' Ganon2 ' : ( 0x180700 , 256 ) ,
' Blind ' : ( 0x180800 , 256 ) ,
' TavernMan ' : ( 0x180C00 , 256 ) ,
' Sahasrahla1 ' : ( 0x180A00 , 256 ) ,
' Sahasrahla2 ' : ( 0x180B00 , 256 ) ,
' BombShop1 ' : ( 0x180E00 , 256 ) ,
' BombShop2 ' : ( 0x180D00 , 256 ) ,
2017-07-14 21:32:40 +00:00
' PyramidFairy ' : ( 0x180900 , 256 ) ,
' EtherTablet ' : ( 0x180F00 , 256 ) ,
2017-07-17 16:04:24 +00:00
' BombosTablet ' : ( 0x181000 , 256 ) ,
' Ganon1Invincible ' : ( 0x181100 , 256 ) ,
' Ganon2Invincible ' : ( 0x181200 , 256 ) }
2017-05-20 12:07:19 +00:00
2017-05-28 13:41:08 +00:00
Uncle_texts = [ ' Good Luck! \n You will need it. ' , ' Forward this message to 10 other people or this seed will be awful. ' , ' I hope you like your seeds bootless and fluteless. ' ,
' 10 \n 9 \n 8 \n 7 \n 6 \n 5 \n 4 \n 3 \n 2 \n 1 \n Go! ' , ' I have crippling depression. ' , ' I \' m off to visit cousin Fritzl. ' ]
Triforce_texts = [ ' Product has Hole in center. Bad seller, 0 out of 5. ' , ' Who stole the fourth triangle? ' , ' Trifource? \n More Like Tritrice, am I right? '
' \n Well Done! ' , ' You just wasted 2 hours of your life. ' , ' This was meant to be a trapezoid ' ]
2017-05-25 13:58:35 +00:00
BombShop2_texts = [ ' Bombs! \n Bombs! \n Biggest! \n Bestest! \n Greatest! \n Boomest! ' ]
PyramidFairy_texts = [ ' May I talk to you about our lord and savior, Ganon? ' ]
2017-05-28 13:41:08 +00:00
Sahasrahla2_texts = [ ' You already got my item, idiot. ' , ' Why are you still talking to me? ' , ' This text won \' t change. ' , ' Have you met my brother, Hasarahshla? ' ]
Blind_texts = [ ' I bet you expected a vision related pun? \n \n Not Today. \n Didn \' t see that coming, did you? ' , ' What do you call a blind dinosaur? \n A Doyouthinkhe-saurus ' ,
' A blind man walks into a bar... \n \n \n and a table \n \n \n and a door. ' ,
' Why can \' t blind people eat fish? \n Because it \' s see food ' ]
Ganon1_texts = [ ' \n \n \n \n \n \n \n \n \n Why are you reading an empty textbox? ' , ' Hi ' , ' Hey, can you turn off the lights? ' , ' Oink Oink ' ,
' Uncle: How do you like my Ganon cosplay? ' , ' I \' ll try spinning - that \' s a good trick! ' , ' Did you ever hear the tragedy of Darth Plagueis the Wise? ' ]
2017-05-25 13:58:35 +00:00
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. ' ]
2017-05-28 13:41:08 +00:00
KingsReturn_texts = [ ' Who is this even ' , ' The Harem ' ]
2017-05-25 13:58:35 +00:00
Sanctuary_texts = [ ' A Priest \' s love ' ]
2017-05-28 13:41:08 +00:00
Kakariko_texts = [ ' Shasschahshahsahahrahsashsa ' , ' Schaschlik ' ]
Blacksmiths_texts = [ ' frogs for bread ' , ' That \' s not a sword ' , ' The Rupeesmiths ' ]
DeathMountain_texts = [ ' lost again ' , ' Alzheimer ' ]
LostWoods_texts = [ ' thieves \' stump ' , ' He \' s got wood ' , ' Dancing pickles ' ]
2017-05-25 13:58:35 +00:00
WishingWell_texts = [ ' Bottle for Bottle ' ]
DesertPalace_texts = [ ' literacy moves ' ]
MountainTower_texts = [ ' up up and away ' ]
2017-05-28 13:41:08 +00:00
LinksHouse_texts = [ ' Home Sweet Home ' , ' Only one bed ' ]
2017-07-20 09:20:16 +00:00
Lumberjacks_texts = [ ' Chop Chop ' , ' logfellas ' ]
2017-05-25 13:58:35 +00:00
SickKid_texts = [ ' Next Time Stay Down ' ]
2017-05-28 13:41:08 +00:00
Zora_texts = [ ' Splashes For Sale ' , ' Slippery when wet ' ]
MagicShop_texts = [ ' Drug deal ' , ' Shrooms for days ' ]
2017-05-25 13:58:35 +00:00
FluteBoy_texts = [ ' Stumped ' ]
2017-11-05 04:06:00 +00:00
class Credits ( object ) :
def __init__ ( self ) :
self . credit_scenes = {
' castle ' : [
SceneSmallCreditLine ( 19 , ' The return of the King ' ) ,
SceneLargeCreditLine ( 23 , ' Hyrule Castle ' ) ,
] ,
' sancturary ' : [
SceneSmallCreditLine ( 19 , ' The loyal priest ' ) ,
SceneLargeCreditLine ( 23 , ' Sanctuary ' ) ,
] ,
' kakariko ' : [
SceneSmallCreditLine ( 19 , " Sahasralah ' s Homecoming " ) ,
SceneLargeCreditLine ( 23 , ' Kakariko Town ' ) ,
] ,
' desert ' : [
SceneSmallCreditLine ( 19 , ' vultures rule the desert ' ) ,
SceneLargeCreditLine ( 23 , ' Desert Palace ' ) ,
] ,
' hera ' : [
SceneSmallCreditLine ( 19 , ' the bully makes a friend ' ) ,
SceneLargeCreditLine ( 23 , ' Mountain Tower ' ) ,
] ,
' house ' : [
SceneSmallCreditLine ( 19 , ' your uncle recovers ' ) ,
SceneLargeCreditLine ( 23 , ' Your House ' ) ,
] ,
' zora ' : [
SceneSmallCreditLine ( 19 , ' finger webs for sale ' ) ,
SceneLargeCreditLine ( 23 , " Zora ' s Waterfall " ) ,
] ,
' witch ' : [
SceneSmallCreditLine ( 19 , ' the witch and assistant ' ) ,
SceneLargeCreditLine ( 23 , ' Magic Shop ' ) ,
] ,
' lumberjacks ' : [
SceneSmallCreditLine ( 19 , ' twin lumberjacks ' ) ,
SceneLargeCreditLine ( 23 , " Woodsmen ' s Hut " ) ,
] ,
' grove ' : [
SceneSmallCreditLine ( 19 , ' ocarina boy plays again ' ) ,
SceneLargeCreditLine ( 23 , ' Haunted Grove ' ) ,
] ,
' well ' : [
SceneSmallCreditLine ( 19 , ' venus, queen of faeries ' ) ,
SceneLargeCreditLine ( 23 , ' Wishing Well ' ) ,
] ,
' smithy ' : [
SceneSmallCreditLine ( 19 , ' the dwarven swordsmiths ' ) ,
SceneLargeCreditLine ( 23 , ' Smithery ' ) ,
] ,
' kakariko2 ' : [
SceneSmallCreditLine ( 19 , ' the bug-catching kid ' ) ,
SceneLargeCreditLine ( 23 , ' Kakariko Town ' ) ,
] ,
' bridge ' : [
SceneSmallCreditLine ( 19 , ' the lost old man ' ) ,
SceneLargeCreditLine ( 23 , ' Death Mountain ' ) ,
] ,
' woods ' : [
SceneSmallCreditLine ( 19 , ' the forest thief ' ) ,
SceneLargeCreditLine ( 23 , ' Lost Woods ' ) ,
] ,
' pedestal ' : [
SceneSmallCreditLine ( 19 , ' and the master sword ' ) ,
SceneSmallAltCreditLine ( 21 , ' sleeps again... ' ) ,
#SceneLargeCreditLine(23, 'Forever!'),
SceneLargeCreditLine ( 23 , ' Forever!!!!! ' ) ,
] ,
}
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
self . scene_order = [ ' castle ' , ' sancturary ' , ' kakariko ' , ' desert ' , ' hera ' , ' house ' , ' zora ' , ' witch ' ,
' lumberjacks ' , ' grove ' , ' well ' , ' smithy ' , ' kakariko2 ' , ' bridge ' , ' woods ' , ' pedestal ' ]
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
def update_credits_line ( self , scene , line , text , align = ' center ' ) :
scenes = self . credit_scenes
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
text = text [ : 32 ]
scenes [ scene ] [ line ] . text = text
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
def get_bytes ( self ) :
pointers = [ ]
data = bytearray ( )
for scene_name in self . scene_order :
scene = self . credit_scenes [ scene_name ]
pointers . append ( len ( data ) )
2017-05-20 12:07:19 +00:00
2017-11-05 04:06:00 +00:00
for part in scene :
data + = part . as_bytes ( )
2017-05-20 12:07:19 +00:00
2017-11-05 04:06:00 +00:00
pointers . append ( len ( data ) )
return ( pointers , data )
class CreditLine ( object ) :
""" Base class of credit lines """
def __init__ ( self , text , align = ' center ' ) :
self . text = text
self . align = align
@property
def x ( self ) :
x = 0
if self . align == ' left ' :
x = 0
elif self . align == ' right ' :
x = 32 - len ( self . text )
else : # center
x = ( 32 - len ( self . text ) ) / / 2
return x
class SceneCreditLine ( CreditLine ) :
""" Base class for credit lines for the scene portion of the credits """
def __init__ ( self , y , text , align = ' center ' ) :
self . y = y
super ( ) . __init__ ( text , align )
def header ( self , x = None , y = None , length = None ) :
if x is None :
x = self . x
if y is None :
y = self . y
if length is None :
length = len ( self . text )
header = ( 0x6000 | ( y >> 5 << 11 ) | ( ( y & 0x1F ) << 5 ) | ( x >> 5 << 10 ) | ( x & 0x1F ) ) << 16 | ( length * 2 - 1 )
return bytearray ( [ header >> 24 & 0xFF , header >> 16 & 0xFF , header >> 8 & 0xFF , header & 0xFF ] )
class SceneSmallCreditLine ( SceneCreditLine ) :
def as_bytes ( self ) :
buf = bytearray ( )
buf . extend ( self . header ( ) )
buf . extend ( GoldCreditMapper . convert ( self . text ) )
# handle upper half of apostrophe character if present
if " ' " in self . text :
apos = " " . join ( [ ' , ' if x == " ' " else ' ' for x in self . text ] )
buf . extend ( self . header ( self . x + apos . index ( ' , ' ) , self . y - 1 , len ( apos . strip ( ) ) ) )
buf . extend ( GoldCreditMapper . convert ( apos . strip ( ) ) )
# handle lower half of comma character if present
if ' , ' in self . text :
commas = " " . join ( [ " ' " if x == ' , ' else ' ' for x in self . text ] )
buf . extend ( self . header ( self . x + commas . index ( " ' " ) , self . y + 1 , len ( commas . strip ( ) ) ) )
buf . extend ( GoldCreditMapper . convert ( commas . strip ( ) ) )
return buf
class SceneSmallAltCreditLine ( SceneCreditLine ) :
def as_bytes ( self ) :
buf = bytearray ( )
buf + = self . header ( )
buf + = GreenCreditMapper . convert ( self . text )
return buf
class SceneLargeCreditLine ( SceneCreditLine ) :
def as_bytes ( self ) :
buf = bytearray ( )
buf + = self . header ( )
buf + = LargeCreditTopMapper . convert ( self . text )
buf + = self . header ( self . x , self . y + 1 )
buf + = LargeCreditBottomMapper . convert ( self . text )
return buf
2017-05-20 12:07:19 +00:00
def string_to_alttp_text ( s , maxbytes = 256 ) :
lines = s . upper ( ) . split ( ' \n ' )
outbuf = bytearray ( )
lineindex = 0
while lines :
linespace = 14
line = lines . pop ( 0 )
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 :
word = ' ' + word
word_first = word [ : linespace ]
words . insert ( 0 , word [ linespace : ] )
lines . insert ( 0 , ' ' . join ( words ) )
write_word ( outbuf , word_first )
break
if len ( word ) < = ( linespace if linespace == 14 else linespace - 1 ) :
if linespace < 14 :
word = ' ' + word
linespace - = len ( word )
write_word ( outbuf , word )
else :
# ran out of space, push word and lines back and continue with next line
words . insert ( 0 , word )
lines . insert ( 0 , ' ' . join ( words ) )
break
lineindex + = 1
if lineindex % 3 == 0 and lines :
outbuf . append ( 0x7E )
if lineindex > = 3 and lines :
outbuf . append ( 0x73 )
# check for max length
if len ( outbuf ) > maxbytes - 1 :
outbuf = outbuf [ : maxbytes - 1 ]
2017-05-20 18:03:13 +00:00
# make sure we interpret the end of box character
if outbuf [ - 1 ] == 0x00 :
outbuf [ - 1 ] = 0x73
2017-05-20 12:07:19 +00:00
outbuf . append ( 0x7F )
return outbuf
def write_word ( buf , word ) :
for char in word :
buf . extend ( [ 0x00 , char_to_alttp_char ( char ) ] )
char_map = { ' ' : 0xFF ,
' ? ' : 0xC6 ,
' ! ' : 0xC7 ,
' , ' : 0xC8 ,
' - ' : 0xC9 ,
' … ' : 0xCC ,
' . ' : 0xCD ,
' ~ ' : 0xCE ,
' ~ ' : 0xCE ,
2017-05-20 18:03:13 +00:00
" ' " : 0xD8 ,
2017-05-20 12:07:19 +00:00
' ’ ' : 0xD8 ,
' ↑ ' : 0xE0 ,
' ↓ ' : 0xE1 ,
' → ' : 0xE2 ,
' ← ' : 0xE3 ,
' あ ' : 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 ,
' ま ' : 0x30 ,
' み ' : 0x31 ,
' む ' : 0x32 ,
' め ' : 0x33 ,
' も ' : 0x34 ,
' づ ' : 0x35 ,
' で ' : 0x36 ,
' ど ' : 0x37 ,
' ら ' : 0x38 ,
' り ' : 0x39 ,
' る ' : 0x3A ,
' れ ' : 0x3B ,
' ろ ' : 0x3C ,
' ば ' : 0x3D ,
' び ' : 0x3E ,
' ぶ ' : 0x3F ,
' べ ' : 0x40 ,
' ぼ ' : 0x41 ,
' ぱ ' : 0x42 ,
' ぴ ' : 0x43 ,
' ぷ ' : 0x44 ,
' ぺ ' : 0x45 ,
' ぽ ' : 0x46 ,
' ゃ ' : 0x47 ,
' ゅ ' : 0x48 ,
' ょ ' : 0x49 ,
' っ ' : 0x4A ,
' ぁ ' : 0x4B ,
' ぃ ' : 0x4C ,
' ぅ ' : 0x4D ,
' ぇ ' : 0x4E ,
' ぉ ' : 0x4F ,
' ア ' : 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 }
def char_to_alttp_char ( char ) :
if 0x30 < = ord ( char ) < = 0x39 :
2017-05-20 18:03:13 +00:00
return ord ( char ) + 0x70
2017-05-20 12:07:19 +00:00
if 0x41 < = ord ( char ) < = 0x5A :
return ord ( char ) + 0x69
return char_map . get ( char , 0xFF )
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
class TextMapper ( object ) :
number_offset = None
@classmethod
def map_char ( cls , char ) :
if cls . number_offset is not None :
if 0x30 < = ord ( char ) < = 0x39 :
return ord ( char ) + cls . number_offset
if 0x61 < = ord ( char ) < = 0x7A :
return ord ( char ) + cls . alpha_offset
return cls . char_map . get ( char , cls . char_map [ ' ' ] )
@classmethod
def convert ( cls , text ) :
buf = bytearray ( )
for char in text . lower ( ) :
buf . append ( cls . map_char ( char ) )
return buf
class GoldCreditMapper ( TextMapper ) :
char_map = { ' ' : 0x9F ,
' , ' : 0x34 ,
' . ' : 0x37 ,
' - ' : 0x36 ,
" ' " : 0x35 }
alpha_offset = - 0x47
class GreenCreditMapper ( TextMapper ) :
char_map = { ' ' : 0x9F ,
' . ' : 0x52 }
alpha_offset = - 0x29
class RedCreditMapper ( TextMapper ) :
char_map = { ' ' : 0x9F } #fixme
alpha_offset = - 0x61
class LargeCreditTopMapper ( TextMapper ) :
char_map = { ' ' : 0x9F ,
" ' " : 0x77 ,
' ! ' : 0x78 ,
' . ' : 0xA0 ,
' # ' : 0xA1 ,
' / ' : 0xA2 ,
' : ' : 0xA3 }
alpha_offset = - 0x04
number_offset = 0x23
2017-05-25 13:58:35 +00:00
2017-11-05 04:06:00 +00:00
class LargeCreditBottomMapper ( TextMapper ) :
char_map = { ' ' : 0x9F ,
" ' " : 0x9D ,
' ! ' : 0x9E ,
' . ' : 0xC0 ,
' # ' : 0xC1 ,
' / ' : 0xC2 ,
' : ' : 0xC3 }
alpha_offset = 0x22
number_offset = 0x49