Merge remote-tracking branch 'origin/master'

This commit is contained in:
Fabian Dill 2020-07-16 16:57:48 +02:00
commit 34b04179ce
2 changed files with 54 additions and 52 deletions

View File

@ -77,7 +77,7 @@ def main(args, seed=None):
world.triforce_pieces_required = args.triforce_pieces_required.copy()
world.progression_balancing = {player: not balance for player, balance in args.skip_progression_balancing.items()}
world.rom_seeds = {player: world.random.randint(0, 999999999) for player in range(1, world.players + 1)}
world.rom_seeds = {player: random.Random(world.random.randint(0, 999999999)) for player in range(1, world.players + 1)}
logger.info('ALttP Berserker\'s Multiworld Version %s - Seed: %s\n', __version__, world.seed)
@ -199,7 +199,7 @@ def main(args, seed=None):
apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player],
args.fastmenu[player], args.disablemusic[player], args.sprite[player],
args.ow_palettes[player], args.uw_palettes[player])
args.ow_palettes[player], args.uw_palettes[player], world, player)
mcsb_name = ''
if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],

102
Rom.py
View File

@ -236,9 +236,8 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
'BeesLevel': 0,
'RandomizeTileTrapPattern': world.enemy_shuffle[player] == 'chaos',
'RandomizeTileTrapFloorTile': False,
'AllowKillableThief': bool(world.random.randint(0, 1)) if 'thieves' in world.enemy_shuffle[player] else
'AllowKillableThief': bool(world.rom_seeds[player].randint(0, 1)) if 'thieves' in world.enemy_shuffle[player] else
world.enemy_shuffle[player] != 'none',
# TODO: this is currently non-deterministic due to being called in a thread
'RandomizeSpriteOnHit': random_sprite_on_hit,
'DebugMode': False,
'DebugForceEnemy': False,
@ -276,7 +275,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
subprocess.check_call([os.path.abspath(enemizercli),
'--rom', randopatch_path,
'--seed', str(world.rom_seeds[player]),
'--seed', str(world.rom_seeds[player].randint(0, 999999999)),
'--binary',
'--enemizer', options_path,
'--output', enemizer_output_path],
@ -290,7 +289,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
if sprites:
while len(sprites) < 32:
sprites.extend(sprites)
world.random.shuffle(sprites)
world.rom_seeds[player].shuffle(sprites)
for i, path in enumerate(sprites[:32]):
sprite = Sprite(path)
@ -317,11 +316,11 @@ def _populate_sprite_table():
if sprite.valid:
_sprite_table[sprite.name.lower()] = filepath
def get_sprite_from_name(name):
def get_sprite_from_name(name, local_random=random):
_populate_sprite_table()
name = name.lower()
if name in ['random', 'randomonhit']:
return Sprite(random.choice(list(_sprite_table.values())))
return Sprite(local_random.choice(list(_sprite_table.values())))
return Sprite(_sprite_table[name]) if name in _sprite_table else None
class Sprite(object):
@ -483,7 +482,7 @@ class Sprite(object):
return array_chunk(palette_as_colors, 15)
def patch_rom(world, rom, player, team, enemized):
local_random = random.Random(world.rom_seeds[player])
local_random = world.rom_seeds[player]
# progressive bow silver arrow hint hack
prog_bow_locs = world.find_items('Progressive Bow', player)
@ -1365,9 +1364,10 @@ def hud_format_text(text):
return output[:32]
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, ow_palettes, uw_palettes):
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, ow_palettes, uw_palettes, world=None, player=1):
local_random = random if not world else world.rom_seeds[player]
if sprite and not isinstance(sprite, Sprite):
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite)
sprite = Sprite(sprite) if os.path.isfile(sprite) else get_sprite_from_name(sprite, local_random)
# enable instant item menu
if fastmenu == 'instant':
@ -1405,7 +1405,7 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
# set heart color
if color == 'random':
color = random.choice(['red', 'blue', 'green', 'yellow'])
color = local_random.choice(['red', 'blue', 'green', 'yellow'])
rom.write_byte(0x6FA1E, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
rom.write_byte(0x6FA20, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
rom.write_byte(0x6FA22, {'red': 0x24, 'blue': 0x2C, 'green': 0x3C, 'yellow': 0x28}[color])
@ -1424,13 +1424,13 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
default_ow_palettes(rom)
if ow_palettes == 'random':
randomize_ow_palettes(rom)
randomize_ow_palettes(rom, local_random)
elif ow_palettes == 'blackout':
blackout_ow_palettes(rom)
default_uw_palettes(rom)
if uw_palettes == 'random':
randomize_uw_palettes(rom)
randomize_uw_palettes(rom, local_random)
elif uw_palettes == 'blackout':
blackout_uw_palettes(rom)
@ -1460,11 +1460,11 @@ def default_ow_palettes(rom):
for address in [0x067FB4, 0x067F94, 0x067FC6, 0x067FE6, 0x067FE1, 0x05FEA9, 0x05FEB3]:
rom.write_bytes(address, rom.orig_buffer[address:address+2])
def randomize_ow_palettes(rom):
def randomize_ow_palettes(rom, local_random):
grass, grass2, grass3, dirt, dirt2, water, clouds, dwdirt,\
dwgrass, dwwater, dwdmdirt, dwdmgrass, dwdmclouds1, dwdmclouds2 = [[random.randint(60, 215) for _ in range(3)] for _ in range(14)]
dwtree = [c + random.randint(-20, 10) for c in dwgrass]
treeleaf = [c + random.randint(-20, 10) for c in grass]
dwgrass, dwwater, dwdmdirt, dwdmgrass, dwdmclouds1, dwdmclouds2 = [[local_random.randint(60, 215) for _ in range(3)] for _ in range(14)]
dwtree = [c + local_random.randint(-20, 10) for c in dwgrass]
treeleaf = [c + local_random.randint(-20, 10) for c in grass]
patches = {0x067FB4: (grass, 0), 0x067F94: (grass, 0), 0x067FC6: (grass, 0), 0x067FE6: (grass, 0), 0x067FE1: (grass, 3), 0x05FEA9: (grass, 0), 0x05FEB3: (dwgrass, 1),
0x0DD4AC: (grass, 2), 0x0DE6DE: (grass2, 2), 0x0DE6E0: (grass2, 1), 0x0DD4AE: (grass2, 1), 0x0DE9FA: (grass2, 1), 0x0DEA0E: (grass2, 1), 0x0DE9FE: (grass2, 0),
@ -1518,9 +1518,9 @@ def default_uw_palettes(rom):
return
rom.write_bytes(0xDD734, rom.orig_buffer[0xDD734:0xDE544])
def randomize_uw_palettes(rom):
def randomize_uw_palettes(rom, local_random):
for dungeon in range(20):
wall, pot, chest, floor1, floor2, floor3 = [[random.randint(60, 240) for _ in range(3)] for _ in range(6)]
wall, pot, chest, floor1, floor2, floor3 = [[local_random.randint(60, 240) for _ in range(3)] for _ in range(6)]
for i in range(5):
shade = 10 - (i * 2)
@ -1579,6 +1579,8 @@ def write_string_to_rom(rom, target, string):
def write_strings(rom, world, player, team):
local_random = world.rom_seeds[player]
tt = TextTable()
tt.removeUnwantedText()
@ -1607,9 +1609,9 @@ def write_strings(rom, world, player, team):
if world.hints[player]:
tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!'
hint_locations = HintLocations.copy()
world.random.shuffle(hint_locations)
local_random.shuffle(hint_locations)
all_entrances = [entrance for entrance in world.get_entrances() if entrance.player == player]
world.random.shuffle(all_entrances)
local_random.shuffle(all_entrances)
#First we take care of the one inconvenient dungeon in the appropriately simple shuffles.
entrances_to_hint = {}
@ -1684,12 +1686,12 @@ def write_strings(rom, world, player, team):
locations_to_hint = InconvenientLocations.copy()
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
locations_to_hint.extend(InconvenientVanillaLocations)
world.random.shuffle(locations_to_hint)
local_random.shuffle(locations_to_hint)
hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 5
del locations_to_hint[hint_count:]
for location in locations_to_hint:
if location == 'Swamp Left':
if world.random.randint(0, 1) == 0:
if local_random.randint(0, 1) == 0:
first_item = hint_text(world.get_location('Swamp Palace - West Chest', player).item)
second_item = hint_text(world.get_location('Swamp Palace - Big Key Chest', player).item)
else:
@ -1698,7 +1700,7 @@ def write_strings(rom, world, player, team):
this_hint = ('The westmost chests in Swamp Palace contain ' + first_item + ' and ' + second_item + '.')
tt[hint_locations.pop(0)] = this_hint
elif location == 'Mire Left':
if world.random.randint(0, 1) == 0:
if local_random.randint(0, 1) == 0:
first_item = hint_text(world.get_location('Misery Mire - Compass Chest', player).item)
second_item = hint_text(world.get_location('Misery Mire - Big Key Chest', player).item)
else:
@ -1737,12 +1739,12 @@ def write_strings(rom, world, player, team):
items_to_hint.extend(SmallKeys)
if world.bigkeyshuffle[player]:
items_to_hint.extend(BigKeys)
world.random.shuffle(items_to_hint)
local_random.shuffle(items_to_hint)
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8
while hint_count > 0:
this_item = items_to_hint.pop(0)
this_location = world.find_items(this_item, player)
world.random.shuffle(this_location)
local_random.shuffle(this_location)
#This looks dumb but prevents hints for Skull Woods Pinball Room's key safely with any item pool.
if this_location:
if this_location[0].name == 'Skull Woods - Pinball Room':
@ -1754,7 +1756,7 @@ def write_strings(rom, world, player, team):
# All remaining hint slots are filled with junk hints. It is done this way to ensure the same junk hint isn't selected twice.
junk_hints = junk_texts.copy()
world.random.shuffle(junk_hints)
local_random.shuffle(junk_hints)
for location in hint_locations:
tt[location] = junk_hints.pop(0)
@ -1762,7 +1764,7 @@ def write_strings(rom, world, player, team):
silverarrows = world.find_items('Silver Bow', player)
world.random.shuffle(silverarrows)
local_random.shuffle(silverarrows)
silverarrow_hint = (' %s?' % hint_text(silverarrows[0]).replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!'
tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint
tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
@ -1776,7 +1778,7 @@ def write_strings(rom, world, player, team):
tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint
if any(prog_bow_locs):
silverarrow_hint = (' %s?' % hint_text(world.random.choice(prog_bow_locs)).replace('Ganon\'s',
silverarrow_hint = (' %s?' % hint_text(local_random.choice(prog_bow_locs)).replace('Ganon\'s',
'my')) if progressive_silvers else '?\nI think not!'
tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
@ -1798,13 +1800,13 @@ def write_strings(rom, world, player, team):
if world.goal[player] in ['dungeons']:
tt['sign_ganon'] = 'You need to complete all the dungeons.'
tt['uncle_leaving_text'] = Uncle_texts[world.random.randint(0, len(Uncle_texts) - 1)]
tt['end_triforce'] = "{NOBORDER}\n" + Triforce_texts[world.random.randint(0, len(Triforce_texts) - 1)]
tt['bomb_shop_big_bomb'] = BombShop2_texts[world.random.randint(0, len(BombShop2_texts) - 1)]
tt['uncle_leaving_text'] = Uncle_texts[local_random.randint(0, len(Uncle_texts) - 1)]
tt['end_triforce'] = "{NOBORDER}\n" + Triforce_texts[local_random.randint(0, len(Triforce_texts) - 1)]
tt['bomb_shop_big_bomb'] = BombShop2_texts[local_random.randint(0, len(BombShop2_texts) - 1)]
# this is what shows after getting the green pendant item in rando
tt['sahasrahla_quest_have_master_sword'] = Sahasrahla2_texts[world.random.randint(0, len(Sahasrahla2_texts) - 1)]
tt['blind_by_the_light'] = Blind_texts[world.random.randint(0, len(Blind_texts) - 1)]
tt['sahasrahla_quest_have_master_sword'] = Sahasrahla2_texts[local_random.randint(0, len(Sahasrahla2_texts) - 1)]
tt['blind_by_the_light'] = Blind_texts[local_random.randint(0, len(Blind_texts) - 1)]
if world.goal[player] in ['triforcehunt', 'localtriforcehunt']:
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.'
@ -1821,7 +1823,7 @@ def write_strings(rom, world, player, team):
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
tt['sign_ganon'] = 'You need to get to the pedestal... Ganon is invincible!'
else:
tt['ganon_fall_in'] = Ganon1_texts[world.random.randint(0, len(Ganon1_texts) - 1)]
tt['ganon_fall_in'] = Ganon1_texts[local_random.randint(0, len(Ganon1_texts) - 1)]
tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!'
tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!'
if world.goal[player] == 'ganontriforcehunt' and world.players > 1:
@ -1829,7 +1831,7 @@ def write_strings(rom, world, player, team):
elif world.goal[player] in ['ganontriforcehunt', 'localganontriforcehunt']:
tt['sign_ganon'] = 'You need to find %d Triforce pieces to defeat Ganon.' % world.treasure_hunt_count[player]
tt['kakariko_tavern_fisherman'] = TavernMan_texts[world.random.randint(0, len(TavernMan_texts) - 1)]
tt['kakariko_tavern_fisherman'] = TavernMan_texts[local_random.randint(0, len(TavernMan_texts) - 1)]
pedestalitem = world.get_location('Master Sword Pedestal', player).item
pedestal_text = 'Some Hot Air' if pedestalitem is None else hint_text(pedestalitem, True) if pedestalitem.pedestal_hint_text is not None else 'Unknown Item'
@ -1860,38 +1862,38 @@ def write_strings(rom, world, player, team):
credits = Credits()
sickkiditem = world.get_location('Sick Kid', player).item
sickkiditem_text = world.random.choice(
sickkiditem_text = local_random.choice(
SickKid_texts) if sickkiditem is None or sickkiditem.sickkid_credit_text is None else sickkiditem.sickkid_credit_text
zoraitem = world.get_location('King Zora', player).item
zoraitem_text = world.random.choice(
zoraitem_text = local_random.choice(
Zora_texts) if zoraitem is None or zoraitem.zora_credit_text is None else zoraitem.zora_credit_text
magicshopitem = world.get_location('Potion Shop', player).item
magicshopitem_text = world.random.choice(
magicshopitem_text = local_random.choice(
MagicShop_texts) if magicshopitem is None or magicshopitem.magicshop_credit_text is None else magicshopitem.magicshop_credit_text
fluteboyitem = world.get_location('Flute Spot', player).item
fluteboyitem_text = world.random.choice(
fluteboyitem_text = local_random.choice(
FluteBoy_texts) if fluteboyitem is None or fluteboyitem.fluteboy_credit_text is None else fluteboyitem.fluteboy_credit_text
credits.update_credits_line('castle', 0, world.random.choice(KingsReturn_texts))
credits.update_credits_line('sanctuary', 0, world.random.choice(Sanctuary_texts))
credits.update_credits_line('castle', 0, local_random.choice(KingsReturn_texts))
credits.update_credits_line('sanctuary', 0, local_random.choice(Sanctuary_texts))
credits.update_credits_line('kakariko', 0,
world.random.choice(Kakariko_texts).format(world.random.choice(Sahasrahla_names)))
credits.update_credits_line('desert', 0, world.random.choice(DesertPalace_texts))
credits.update_credits_line('hera', 0, world.random.choice(MountainTower_texts))
credits.update_credits_line('house', 0, world.random.choice(LinksHouse_texts))
local_random.choice(Kakariko_texts).format(local_random.choice(Sahasrahla_names)))
credits.update_credits_line('desert', 0, local_random.choice(DesertPalace_texts))
credits.update_credits_line('hera', 0, local_random.choice(MountainTower_texts))
credits.update_credits_line('house', 0, local_random.choice(LinksHouse_texts))
credits.update_credits_line('zora', 0, zoraitem_text)
credits.update_credits_line('witch', 0, magicshopitem_text)
credits.update_credits_line('lumberjacks', 0, world.random.choice(Lumberjacks_texts))
credits.update_credits_line('lumberjacks', 0, local_random.choice(Lumberjacks_texts))
credits.update_credits_line('grove', 0, fluteboyitem_text)
credits.update_credits_line('well', 0, world.random.choice(WishingWell_texts))
credits.update_credits_line('smithy', 0, world.random.choice(Blacksmiths_texts))
credits.update_credits_line('well', 0, local_random.choice(WishingWell_texts))
credits.update_credits_line('smithy', 0, local_random.choice(Blacksmiths_texts))
credits.update_credits_line('kakariko2', 0, sickkiditem_text)
credits.update_credits_line('bridge', 0, world.random.choice(DeathMountain_texts))
credits.update_credits_line('woods', 0, world.random.choice(LostWoods_texts))
credits.update_credits_line('bridge', 0, local_random.choice(DeathMountain_texts))
credits.update_credits_line('woods', 0, local_random.choice(LostWoods_texts))
credits.update_credits_line('pedestal', 0, pedestal_credit_text)
(pointers, data) = credits.get_bytes()