parent
3e31502fc0
commit
9d4d3b8456
|
@ -185,7 +185,7 @@ class World(object):
|
|||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def has_beaten_game(self, state):
|
||||
if state.has('Triforce'): return True
|
||||
if self.goal in ['triforcehunt']:
|
||||
|
@ -329,7 +329,7 @@ class CollectionState(object):
|
|||
return item in self.prog_items
|
||||
else:
|
||||
return self.item_count(item) >= count
|
||||
|
||||
|
||||
def item_count(self, item):
|
||||
return len([pritem for pritem in self.prog_items if pritem == item])
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ if __name__ == '__main__':
|
|||
parser.add_argument('--logic', default='noglitches', const='noglitches', nargs='?', choices=['noglitches', 'minorglitches'],
|
||||
help='''\
|
||||
Select Enforcement of Item Requirements. (default: %(default)s)
|
||||
No Glitches:
|
||||
No Glitches:
|
||||
Minor Glitches: May require Fake Flippers, Bunny Revival
|
||||
and Dark Room Navigation.
|
||||
and Dark Room Navigation.
|
||||
''')
|
||||
parser.add_argument('--mode', default='open', const='open', nargs='?', choices=['standard', 'open', 'swordless'],
|
||||
help='''\
|
||||
|
@ -37,19 +37,19 @@ if __name__ == '__main__':
|
|||
Agahnim\'s Tower barrier can be destroyed with
|
||||
hammer. Misery Mire and Turtle Rock can be opened
|
||||
without a sword. Hammer damages Ganon. Ether and
|
||||
Bombos Tablet can be activated with Hammer (and Book).
|
||||
Bombos Tablet can be activated with Hammer (and Book).
|
||||
''')
|
||||
parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'],
|
||||
help='''\
|
||||
Select completion goal. (default: %(default)s)
|
||||
Ganon: Collect all crystals, beat Agahnim 2 then
|
||||
Ganon: Collect all crystals, beat Agahnim 2 then
|
||||
defeat Ganon.
|
||||
Crystals: Collect all crystals then defeat Ganon.
|
||||
Pedestal: Places the Triforce at the Master Sword Pedestal.
|
||||
All Dungeons: Collect all crystals, pendants, beat both
|
||||
Agahnim fights and then defeat Ganon.
|
||||
Triforce Hunt: Places 30 Triforce Pieces in the world, collect
|
||||
20 of them to beat the game.
|
||||
Triforce Hunt: Places 30 Triforce Pieces in the world, collect
|
||||
20 of them to beat the game.
|
||||
''')
|
||||
parser.add_argument('--difficulty', default='normal', const='normal', nargs='?', choices=['easy', 'normal', 'hard', 'expert', 'insane'],
|
||||
help='''\
|
||||
|
@ -58,7 +58,7 @@ if __name__ == '__main__':
|
|||
Normal: Normal difficulty.
|
||||
Hard: A harder setting with less equipment and reduced health.
|
||||
Expert: A harder yet setting with minimum equipment and health.
|
||||
Insane: A setting with the absolute minimum in equipment and no extra health.
|
||||
Insane: A setting with the absolute minimum in equipment and no extra health.
|
||||
''')
|
||||
parser.add_argument('--timer', default='none', const='normal', nargs='?', choices=['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'],
|
||||
help='''\
|
||||
|
@ -78,7 +78,7 @@ if __name__ == '__main__':
|
|||
and the clock is permenantly at zero.
|
||||
Timed Countdown: Starts with clock at 40 minutes. Same clocks as
|
||||
Timed mode. If time runs out, you lose (but can
|
||||
still keep playing).
|
||||
still keep playing).
|
||||
''')
|
||||
parser.add_argument('--progressive', default='on', const='normal', nargs='?', choices=['on', 'off', 'random'],
|
||||
help='''\
|
||||
|
@ -92,7 +92,7 @@ if __name__ == '__main__':
|
|||
be found at any time. Downgrades are not possible.
|
||||
Random: Swords, Shields, Armor, and Gloves will, per
|
||||
category, be randomly progressive or not.
|
||||
Link will die in one hit.
|
||||
Link will die in one hit.
|
||||
''')
|
||||
parser.add_argument('--algorithm', default='balanced', const='balanced', nargs='?', choices=['freshness', 'flood', 'vt21', 'vt22', 'vt25', 'vt26', 'balanced'],
|
||||
help='''\
|
||||
|
@ -115,7 +115,7 @@ if __name__ == '__main__':
|
|||
them the more often they were found unreachable.
|
||||
Flood: Push out items starting from Link\'s House and
|
||||
slightly biased to placing progression items with
|
||||
less restrictions.
|
||||
less restrictions.
|
||||
''')
|
||||
parser.add_argument('--shuffle', default='full', const='full', nargs='?', choices=['vanilla', 'simple', 'restricted', 'full', 'madness', 'insanity', 'dungeonsfull', 'dungeonssimple'],
|
||||
help='''\
|
||||
|
@ -137,7 +137,7 @@ if __name__ == '__main__':
|
|||
discretion.
|
||||
Experimental.
|
||||
The dungeon variants only mix up dungeons and keep the rest of
|
||||
the overworld vanilla.
|
||||
the overworld vanilla.
|
||||
''')
|
||||
parser.add_argument('--rom', default='Zelda no Densetsu - Kamigami no Triforce (Japan).sfc', help='Path to an ALttP JAP(1.0) rom to use as a base.')
|
||||
parser.add_argument('--loglevel', default='info', const='info', nargs='?', choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.')
|
||||
|
@ -147,7 +147,7 @@ if __name__ == '__main__':
|
|||
If --seed is provided, it will be used for the first seed, then
|
||||
used to derive the next seed (i.e. generating 10 seeds with
|
||||
--seed given will produce the same 10 (different) roms each
|
||||
time).
|
||||
time).
|
||||
''', type=int)
|
||||
parser.add_argument('--fastmenu', help='Enable instant menu', action='store_true')
|
||||
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
|
||||
|
@ -157,33 +157,33 @@ if __name__ == '__main__':
|
|||
''', action='store_true')
|
||||
parser.add_argument('--nodungeonitems', help='''\
|
||||
Remove Maps and Compasses from Itempool, replacing them by
|
||||
empty slots.
|
||||
empty slots.
|
||||
''', action='store_true')
|
||||
parser.add_argument('--beatableonly', help='''\
|
||||
Only check if the game is beatable with placement. Do not
|
||||
ensure all locations are reachable. This only has an effect
|
||||
on the restrictive algorithm currently.
|
||||
on the restrictive algorithm currently.
|
||||
''', action='store_true')
|
||||
parser.add_argument('--shuffleganon', help='''\
|
||||
If set, include the Pyramid Hole and Ganon's Tower in the
|
||||
entrance shuffle pool.
|
||||
If set, include the Pyramid Hole and Ganon's Tower in the
|
||||
entrance shuffle pool.
|
||||
''', action='store_true')
|
||||
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
|
||||
help='''\
|
||||
Select the rate at which the heart beep sound is played at
|
||||
low health. (default: %(default)s)
|
||||
low health. (default: %(default)s)
|
||||
''')
|
||||
parser.add_argument('--sprite', help='''\
|
||||
Path to a sprite sheet to use for Link. Needs to be in
|
||||
binary format and have a length of 0x7000 (28672) bytes,
|
||||
binary format and have a length of 0x7000 (28672) bytes,
|
||||
or 0x7078 (28792) bytes including palette data.
|
||||
Alternatively, can be a ALttP Rom patched with a Link
|
||||
sprite that will be extracted.
|
||||
sprite that will be extracted.
|
||||
''')
|
||||
parser.add_argument('--suppress_rom', help='Do not create an output rom file.', action='store_true')
|
||||
parser.add_argument('--gui', help='Launch the GUI', action='store_true')
|
||||
parser.add_argument('--jsonout', action='store_true', help='''\
|
||||
Output .json patch to stdout instead of a patched rom. Used
|
||||
Output .json patch to stdout instead of a patched rom. Used
|
||||
for VT site integration, do not use otherwise.
|
||||
''')
|
||||
args = parser.parse_args()
|
||||
|
|
2
Fill.py
2
Fill.py
|
@ -167,7 +167,7 @@ def fill_restrictive(world, base_state, locations, itempool):
|
|||
while itempool and locations:
|
||||
item_to_place = itempool.pop()
|
||||
maximum_exploration_state = sweep_from_pool()
|
||||
|
||||
|
||||
if world.check_beatable_only:
|
||||
can_beat_without = world.has_beaten_game(maximum_exploration_state)
|
||||
|
||||
|
|
2
Main.py
2
Main.py
|
@ -228,4 +228,4 @@ def create_playthrough(world):
|
|||
old_world.required_locations = [location.name for sphere in collection_spheres for location in sphere]
|
||||
|
||||
# we can finally output our playthrough
|
||||
old_world.spoiler.playthrough = OrderedDict([(str(i + 1), {str(location): str(location.item) for location in sphere}) for i, sphere in enumerate(collection_spheres)])
|
||||
old_world.spoiler.playthrough = OrderedDict([(str(i + 1), {str(location): str(location.item) for location in sphere}) for i, sphere in enumerate(collection_spheres)])
|
||||
|
|
10
README.md
10
README.md
|
@ -209,7 +209,7 @@ randomized.
|
|||
--algorithm [{freshness,flood,vt21,vt22,vt25,vt26,balanced}]
|
||||
```
|
||||
|
||||
Select item filling algorithm.
|
||||
Select item filling algorithm.
|
||||
|
||||
### Balanced (Default)
|
||||
This is a variation of vt26 that aims to strike a balance between the overworld heavy vt25 and the dungeon heavy vt26 algorithm.
|
||||
|
@ -220,7 +220,7 @@ Items and locations are shuffled like in VT25, and dungeon items are now placed
|
|||
shuffled it includes a slight deliberate bias against having too many desireable items in Ganon's Tower to help counterbalance
|
||||
the sheer number of chests in that single location.
|
||||
|
||||
### VT25
|
||||
### VT25
|
||||
Items and locations are shuffled and placed from the top of the lists. The only thing preventing an item from being placed into a spot
|
||||
is if is absolutely impossible to be there given the previous made placement choices. Leads to very uniform but guaranteed solvable distributions.
|
||||
|
||||
|
@ -243,7 +243,7 @@ staleness, decreasing the likelihood of receiving a progress item.
|
|||
--shuffle [{default,simple,restricted,full,madness,insanity,dungeonsfull,dungeonssimple}]
|
||||
```
|
||||
|
||||
Select Entrance Shuffling Algorithm.
|
||||
Select Entrance Shuffling Algorithm.
|
||||
|
||||
### Default
|
||||
|
||||
|
@ -256,7 +256,7 @@ on the overworld. On Death Mountain, entrances are connected more freely.
|
|||
|
||||
### Full (Default)
|
||||
|
||||
Mixes cave and dungeon entrances freely.
|
||||
Mixes cave and dungeon entrances freely.
|
||||
|
||||
### Restricted
|
||||
|
||||
|
@ -296,7 +296,7 @@ Define seed number to generate. (default: None) Using the same seed with same se
|
|||
--count COUNT
|
||||
```
|
||||
|
||||
Use to batch generate multiple seeds with same settings.
|
||||
Use to batch generate multiple seeds with same settings.
|
||||
If --seed is provided, it will be used for the first seed, then used to derive the next seed (i.e. generating 10 seeds with --seed given will produce the same 10 (different) roms each time). (default: None)
|
||||
|
||||
```
|
||||
|
|
8
Rom.py
8
Rom.py
|
@ -21,10 +21,10 @@ class JsonRom(object):
|
|||
|
||||
def write_bytes(self, startaddress, values):
|
||||
self.patches[str(startaddress)] = list(values)
|
||||
|
||||
|
||||
def write_int16_to_rom(self, address, value):
|
||||
self.write_bytes(address, int16_as_bytes(value))
|
||||
|
||||
|
||||
def write_int32_to_rom(self, address, value):
|
||||
self.write_bytes(address, int32_as_bytes(value))
|
||||
|
||||
|
@ -47,7 +47,7 @@ class LocalRom(object):
|
|||
|
||||
def write_int16_to_rom(self, address, value):
|
||||
self.write_bytes(address, int16_as_bytes(value))
|
||||
|
||||
|
||||
def write_int32_to_rom(self, address, value):
|
||||
self.write_bytes(address, int32_as_bytes(value))
|
||||
|
||||
|
@ -86,7 +86,7 @@ class LocalRom(object):
|
|||
def int16_as_bytes(value):
|
||||
value = value & 0xFFFF
|
||||
return [value & 0xFF, (value >> 8) & 0xFF]
|
||||
|
||||
|
||||
def int32_as_bytes(value):
|
||||
value = value & 0xFFFFFFFF
|
||||
return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF]
|
||||
|
|
24
Rules.py
24
Rules.py
|
@ -301,7 +301,7 @@ def global_rules(world):
|
|||
set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)'])))
|
||||
set_rule(world.get_entrance('Palace of Darkness (North)'), lambda state: state.has('Small Key (Palace of Darkness)', 4))
|
||||
set_rule(world.get_location('Palace of Darkness - Big Chest'), lambda state: state.has('Big Key (Palace of Darkness)'))
|
||||
|
||||
|
||||
if world.keysanity:
|
||||
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('Palace of Darkness - Harmless Hellway').item is not None and (state.world.get_location('Palace of Darkness - Harmless Hellway').item.name in ['Small Key (Palace of Darkness)'])))
|
||||
set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)'])))
|
||||
|
@ -310,7 +310,7 @@ def global_rules(world):
|
|||
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Harmless Hellway').item is not None and (state.world.get_location('Palace of Darkness - Harmless Hellway').item.name in ['Small Key (Palace of Darkness)'])))
|
||||
set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)'])))
|
||||
set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has('Small Key (Palace of Darkness)', 5))
|
||||
|
||||
|
||||
for location in ['Palace of Darkness - Big Chest', 'Palace of Darkness - Helmasaur']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Palace of Darkness)')
|
||||
|
||||
|
@ -320,7 +320,7 @@ def global_rules(world):
|
|||
# these key rules are conservative, you might be able to get away with more lenient rules
|
||||
randomizer_room_chests = ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', 'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right']
|
||||
compass_room_chests = ['Ganons Tower - Compass Room - Top Left', 'Ganons Tower - Compass Room - Top Right', 'Ganons Tower - Compass Room - Bottom Left', 'Ganons Tower - Compass Room - Bottom Right']
|
||||
|
||||
|
||||
set_rule(world.get_location('Ganons Tower - Bob\'s Torch'), lambda state: state.has_Boots())
|
||||
set_rule(world.get_entrance('Ganons Tower (Tile Room)'), lambda state: state.has('Cane of Somaria'))
|
||||
set_rule(world.get_entrance('Ganons Tower (Hookshot Room)'), lambda state: state.has('Hammer'))
|
||||
|
@ -328,24 +328,24 @@ def global_rules(world):
|
|||
set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 4) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Big Key (Ganons Tower)' and state.has('Small Key (Ganons Tower)', 3)) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Small Key (Ganons Tower)'))
|
||||
else:
|
||||
set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Small Key (Ganons Tower)'))
|
||||
|
||||
|
||||
# It is possible to need more than 2 keys to get through this entance if you spend keys elsewhere We reflect this in the chest requirements.
|
||||
# However we need to leave these at the lower values derive that with 3 keys it is always possible to reach Bob and Ice Armos.
|
||||
set_rule(world.get_entrance('Ganons Tower (Double Switch Room)'), lambda state: state.has('Small Key (Ganons Tower)', 2))
|
||||
# It is possible to need more than 3 keys ....
|
||||
set_rule(world.get_entrance('Ganons Tower (Firesnake Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3))
|
||||
|
||||
|
||||
#The actual requirements for these rooms to avoid key-lock
|
||||
set_rule(world.get_location('Ganons Tower - Firesnake Room'), lambda state: state.has('Small Key (Ganons Tower)', 3) or (item_in_locations(state, 'Big Key (Ganons Tower)', randomizer_room_chests) and state.has('Small Key (Ganons Tower)', 2)))
|
||||
for location in randomizer_room_chests:
|
||||
set_rule(world.get_location(location), lambda state: state.has('Small Key (Ganons Tower)', 4) or (item_in_locations(state, 'Big Key (Ganons Tower)', randomizer_room_chests) and state.has('Small Key (Ganons Tower)', 3)))
|
||||
|
||||
|
||||
# Once again it is possible to need more than 3 keys...
|
||||
set_rule(world.get_entrance('Ganons Tower (Tile Room) Key Door'), lambda state: state.has('Small Key (Ganons Tower)', 3) and state.has('Fire Rod'))
|
||||
# Actual requirements
|
||||
for location in compass_room_chests:
|
||||
set_rule(world.get_location(location), lambda state: state.has('Fire Rod') and (state.has('Small Key (Ganons Tower)', 4) or (item_in_locations(state, 'Big Key (Ganons Tower)', compass_room_chests) and state.has('Small Key (Ganons Tower)', 3))))
|
||||
|
||||
|
||||
set_rule(world.get_location('Ganons Tower - Big Chest'), lambda state: state.has('Big Key (Ganons Tower)'))
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Room - Left'), lambda state: state.has('Bow') or state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Chest'), lambda state: state.has('Bow') or state.has_blunt_weapon())
|
||||
|
@ -429,7 +429,7 @@ def open_rules(world):
|
|||
# softlock protection as you can reach the sewers small key door with a guard drop key
|
||||
forbid_item(world.get_location('Hyrule Castle - Boomerang Chest'), 'Small Key (Escape)')
|
||||
forbid_item(world.get_location('Hyrule Castle - Zelda\'s Chest'), 'Small Key (Escape)')
|
||||
|
||||
|
||||
# to prevent key-lock in keysanity we need to prevent these chests from having an item that
|
||||
# blocks the small key
|
||||
if (world.keysanity):
|
||||
|
@ -443,7 +443,7 @@ def swordless_rules(world):
|
|||
# should there ever be fixes that apply to open mode but not swordless, this
|
||||
# can be revisited.
|
||||
open_rules(world)
|
||||
|
||||
|
||||
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has('Hammer') or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
|
||||
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has('Hammer') or state.has('Bug Catching Net') and state.has('Small Key (Agahnims Tower)', 2))
|
||||
set_rule(world.get_location('Ether Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer'))
|
||||
|
@ -479,7 +479,7 @@ def set_trock_key_rules(world):
|
|||
|
||||
# if we have backdoor access we can waste a key on the trinexx door, then have no lamp to reverse traverse the maze room. We simply require an additional key just to be super safe then. The backdoor access to the chest is otherwise free
|
||||
if not can_reach_back:
|
||||
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 1))
|
||||
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 1))
|
||||
else:
|
||||
set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 2))
|
||||
|
||||
|
@ -496,8 +496,8 @@ def set_trock_key_rules(world):
|
|||
# however in keysanity being able to reach all other chests while only having three keys does not imply this contains
|
||||
# a key, so we again need all four keys unless it contains the big key
|
||||
if can_reach_back:
|
||||
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)'])))
|
||||
elif world.keysanity:
|
||||
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)'])))
|
||||
elif world.keysanity:
|
||||
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Big Key (Turtle Rock)'])) else state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)'])))
|
||||
else:
|
||||
set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Big Key (Turtle Rock)'])) else state.has('Small Key (Turtle Rock)', 3) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)'])))
|
||||
|
|
10
Text.py
10
Text.py
|
@ -141,11 +141,11 @@ class Credits(object):
|
|||
|
||||
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
|
||||
|
@ -157,7 +157,7 @@ class CreditLine(object):
|
|||
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'):
|
||||
|
@ -214,7 +214,7 @@ class SceneLargeCreditLine(SceneCreditLine):
|
|||
buf += LargeCreditBottomMapper.convert(self.text)
|
||||
return buf
|
||||
|
||||
|
||||
|
||||
def string_to_alttp_text(s, maxbytes=256):
|
||||
lines = s.upper().split('\n')
|
||||
outbuf = bytearray()
|
||||
|
@ -489,7 +489,7 @@ class GreenCreditMapper(TextMapper):
|
|||
char_map = {' ': 0x9F,
|
||||
'.': 0x52}
|
||||
alpha_offset = -0x29
|
||||
|
||||
|
||||
class RedCreditMapper(TextMapper):
|
||||
char_map = {' ': 0x9F} #fixme
|
||||
alpha_offset= -0x61
|
||||
|
|
Loading…
Reference in New Issue