implement secrets.SystemRandom() for --race

This commit is contained in:
Fabian Dill 2020-07-14 07:01:51 +02:00
parent 59a71dbb05
commit 93ecf5988b
11 changed files with 312 additions and 250 deletions

View File

@ -10,6 +10,10 @@ from EntranceShuffle import door_addresses, indirect_connections
from Utils import int16_as_bytes from Utils import int16_as_bytes
from typing import Union from typing import Union
import secrets
import random
class World(object): class World(object):
debug_types = False debug_types = False
player_names: list player_names: list
@ -28,6 +32,8 @@ class World(object):
setattr(self, name[7:], method) setattr(self, name[7:], method)
logging.debug(f"Set {self}.{name[7:]} to {method}") logging.debug(f"Set {self}.{name[7:]} to {method}")
self.get_location = self._debug_get_location self.get_location = self._debug_get_location
self.random = random.Random() # world-local random state is saved in case of future use a
# persistently running program with multiple worlds rolling concurrently
self.players = players self.players = players
self.teams = 1 self.teams = 1
self.shuffle = shuffle.copy() self.shuffle = shuffle.copy()
@ -116,6 +122,9 @@ class World(object):
set_player_attr('triforce_pieces_available', 30) set_player_attr('triforce_pieces_available', 30)
set_player_attr('triforce_pieces_required', 20) set_player_attr('triforce_pieces_required', 20)
def secure(self):
self.random = secrets.SystemRandom()
@property @property
def player_ids(self): def player_ids(self):
yield from range(1, self.players + 1) yield from range(1, self.players + 1)

View File

@ -1,5 +1,4 @@
import logging import logging
import random
from BaseClasses import Boss from BaseClasses import Boss
from Fill import FillError from Fill import FillError
@ -193,11 +192,11 @@ def place_bosses(world, player):
if world.boss_shuffle[player] == "basic": # vanilla bosses shuffled if world.boss_shuffle[player] == "basic": # vanilla bosses shuffled
bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm'] bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm']
else: # all bosses present, the three duplicates chosen at random else: # all bosses present, the three duplicates chosen at random
bosses = all_bosses + [random.choice(placeable_bosses) for _ in range(3)] bosses = all_bosses + [world.random.choice(placeable_bosses) for _ in range(3)]
logging.getLogger('').debug('Bosses chosen %s', bosses) logging.getLogger('').debug('Bosses chosen %s', bosses)
random.shuffle(bosses) world.random.shuffle(bosses)
for [loc, level] in boss_locations: for [loc, level] in boss_locations:
loc_text = loc + (' ('+level+')' if level else '') loc_text = loc + (' ('+level+')' if level else '')
boss = next((b for b in bosses if can_place_boss(world, player, b, loc, level)), None) boss = next((b for b in bosses if can_place_boss(world, player, b, loc, level)), None)
@ -211,7 +210,8 @@ def place_bosses(world, player):
for [loc, level] in boss_locations: for [loc, level] in boss_locations:
loc_text = loc + (' ('+level+')' if level else '') loc_text = loc + (' ('+level+')' if level else '')
try: try:
boss = random.choice([b for b in placeable_bosses if can_place_boss(world, player, b, loc, level)]) boss = world.random.choice(
[b for b in placeable_bosses if can_place_boss(world, player, b, loc, level)])
except IndexError: except IndexError:
raise FillError('Could not place boss for location %s' % loc_text) raise FillError('Could not place boss for location %s' % loc_text)

View File

@ -1,5 +1,3 @@
import random
from BaseClasses import Dungeon from BaseClasses import Dungeon
from Bosses import BossFactory from Bosses import BossFactory
from Fill import fill_restrictive from Fill import fill_restrictive
@ -58,7 +56,7 @@ def fill_dungeons(world):
dungeon_regions, big_key, small_keys, dungeon_items = dungeons.pop(0) dungeon_regions, big_key, small_keys, dungeon_items = dungeons.pop(0)
# this is what we need to fill # this is what we need to fill
dungeon_locations = [location for location in world.get_unfilled_locations() if location.parent_region.name in dungeon_regions] dungeon_locations = [location for location in world.get_unfilled_locations() if location.parent_region.name in dungeon_regions]
random.shuffle(dungeon_locations) world.random.shuffle(dungeon_locations)
all_state = all_state_base.copy() all_state = all_state_base.copy()

View File

@ -3,7 +3,6 @@ import argparse
import copy import copy
import os import os
import logging import logging
import random
import textwrap import textwrap
import shlex import shlex
import sys import sys

View File

@ -1,5 +1,3 @@
import random
# ToDo: With shuffle_ganon option, prevent gtower from linking to an exit only location through a 2 entrance cave. # ToDo: With shuffle_ganon option, prevent gtower from linking to an exit only location through a 2 entrance cave.
from collections import defaultdict from collections import defaultdict
@ -13,7 +11,7 @@ def link_entrances(world, player):
Old_Man_House = Old_Man_House_Base.copy() Old_Man_House = Old_Man_House_Base.copy()
Cave_Three_Exits = Cave_Three_Exits_Base.copy() Cave_Three_Exits = Cave_Three_Exits_Base.copy()
unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits) unbias_some_entrances(world, Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits)
# setup mandatory connections # setup mandatory connections
for exitname, regionname in mandatory_connections: for exitname, regionname in mandatory_connections:
@ -75,8 +73,8 @@ def link_entrances(world, player):
# we shuffle all 2 entrance caves as pairs as a start # we shuffle all 2 entrance caves as pairs as a start
# start with the ones that need to be directed # start with the ones that need to be directed
two_door_caves = list(Two_Door_Caves_Directional) two_door_caves = list(Two_Door_Caves_Directional)
random.shuffle(two_door_caves) world.random.shuffle(two_door_caves)
random.shuffle(caves) world.random.shuffle(caves)
while two_door_caves: while two_door_caves:
entrance1, entrance2 = two_door_caves.pop() entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop() exit1, exit2 = caves.pop()
@ -85,7 +83,7 @@ def link_entrances(world, player):
# now the remaining pairs # now the remaining pairs
two_door_caves = list(Two_Door_Caves) two_door_caves = list(Two_Door_Caves)
random.shuffle(two_door_caves) world.random.shuffle(two_door_caves)
while two_door_caves: while two_door_caves:
entrance1, entrance2 = two_door_caves.pop() entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop() exit1, exit2 = caves.pop()
@ -96,10 +94,10 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)',
'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)'] 'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)']
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
remaining_entrances.extend(old_man_entrances) remaining_entrances.extend(old_man_entrances)
random.shuffle(remaining_entrances) world.random.shuffle(remaining_entrances)
old_man_entrance = remaining_entrances.pop() old_man_entrance = remaining_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
@ -115,13 +113,13 @@ def link_entrances(world, player):
scramble_holes(world, player) scramble_holes(world, player)
# place blacksmith, has limited options # place blacksmith, has limited options
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place bomb shop, has limited options # place bomb shop, has limited options
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -153,7 +151,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in lw_entrances] old_man_entrances = [door for door in old_man_entrances if door in lw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
lw_entrances.remove(old_man_exit) lw_entrances.remove(old_man_exit)
@ -162,7 +160,7 @@ def link_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
if blacksmith_hut in lw_entrances: if blacksmith_hut in lw_entrances:
@ -175,7 +173,7 @@ def link_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
if bomb_shop in lw_entrances: if bomb_shop in lw_entrances:
@ -184,7 +182,7 @@ def link_entrances(world, player):
dw_entrances.remove(bomb_shop) dw_entrances.remove(bomb_shop)
# place the old man cave's entrance somewhere in the light world # place the old man cave's entrance somewhere in the light world
random.shuffle(lw_entrances) world.random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop() old_man_entrance = lw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
@ -223,10 +221,10 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
lw_entrances.extend(old_man_entrances) lw_entrances.extend(old_man_entrances)
random.shuffle(lw_entrances) world.random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop() old_man_entrance = lw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
@ -241,13 +239,13 @@ def link_entrances(world, player):
scramble_holes(world, player) scramble_holes(world, player)
# place blacksmith, has limited options # place blacksmith, has limited options
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -278,7 +276,8 @@ def link_entrances(world, player):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) caves.append(tuple(world.random.sample(
['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'], 3)))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -290,7 +289,7 @@ def link_entrances(world, player):
# we randomize which world requirements we fulfill first so we get better dungeon distribution # we randomize which world requirements we fulfill first so we get better dungeon distribution
#we also places the Old Man House at this time to make sure he can be connected to the desert one way #we also places the Old Man House at this time to make sure he can be connected to the desert one way
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
caves += old_man_house caves += old_man_house
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player)
try: try:
@ -317,7 +316,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in lw_entrances] old_man_entrances = [door for door in old_man_entrances if door in lw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
lw_entrances.remove(old_man_exit) lw_entrances.remove(old_man_exit)
@ -326,7 +325,7 @@ def link_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
if blacksmith_hut in lw_entrances: if blacksmith_hut in lw_entrances:
@ -339,7 +338,7 @@ def link_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
if bomb_shop in lw_entrances: if bomb_shop in lw_entrances:
@ -381,7 +380,8 @@ def link_entrances(world, player):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) caves.append(tuple(world.random.sample(
['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'], 3)))
entrances.append('Hyrule Castle Entrance (South)') entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -400,7 +400,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in entrances] old_man_entrances = [door for door in old_man_entrances if door in entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
entrances.remove(old_man_exit) entrances.remove(old_man_exit)
@ -408,7 +408,7 @@ def link_entrances(world, player):
# place blacksmith, has limited options # place blacksmith, has limited options
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in entrances] blacksmith_doors = [door for door in blacksmith_doors if door in entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
entrances.remove(blacksmith_hut) entrances.remove(blacksmith_hut)
@ -418,14 +418,14 @@ def link_entrances(world, player):
# cannot place it anywhere already taken (or that are otherwise not eligable for placement) # cannot place it anywhere already taken (or that are otherwise not eligable for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
entrances.remove(bomb_shop) entrances.remove(bomb_shop)
# place the old man cave's entrance somewhere # place the old man cave's entrance somewhere
random.shuffle(entrances) world.random.shuffle(entrances)
old_man_entrance = entrances.pop() old_man_entrance = entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
@ -456,7 +456,8 @@ def link_entrances(world, player):
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
else: else:
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) caves.append(tuple(world.random.sample(
['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'], 3)))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -466,7 +467,7 @@ def link_entrances(world, player):
caves.append('Ganons Tower Exit') caves.append('Ganons Tower Exit')
# we randomize which world requirements we fulfill first so we get better dungeon distribution # we randomize which world requirements we fulfill first so we get better dungeon distribution
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player)
connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player)
else: else:
@ -479,11 +480,11 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in lw_entrances] old_man_entrances = [door for door in old_man_entrances if door in lw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
lw_entrances.remove(old_man_exit) lw_entrances.remove(old_man_exit)
random.shuffle(lw_entrances) world.random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop() old_man_entrance = lw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
@ -498,13 +499,13 @@ def link_entrances(world, player):
scramble_holes(world, player) scramble_holes(world, player)
# place blacksmith, has limited options # place blacksmith, has limited options
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place bomb shop, has limited options # place bomb shop, has limited options
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -520,18 +521,28 @@ def link_entrances(world, player):
dw_entrances = list(DW_Entrances + DW_Dungeon_Entrances) dw_entrances = list(DW_Entrances + DW_Dungeon_Entrances)
dw_entrances_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) dw_entrances_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit)
lw_doors = list(LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit) + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', lw_doors = list(LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit) + ['Kakariko Well Cave',
'Lumberjack Tree Cave'] + list(Old_Man_Entrances) 'Bat Cave Cave',
dw_doors = list(DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] 'North Fairy Cave',
'Sanctuary',
'Lost Woods Hideout Stump',
'Lumberjack Tree Cave'] + list(
Old_Man_Entrances)
dw_doors = list(
DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) + [
'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
'Skull Woods Second Section Door (West)']
random.shuffle(lw_doors) world.random.shuffle(lw_doors)
random.shuffle(dw_doors) world.random.shuffle(dw_doors)
dw_entrances_must_exits.append('Skull Woods Second Section Door (West)') dw_entrances_must_exits.append('Skull Woods Second Section Door (West)')
dw_entrances.append('Skull Woods Second Section Door (East)') dw_entrances.append('Skull Woods Second Section Door (East)')
dw_entrances.append('Skull Woods First Section Door') dw_entrances.append('Skull Woods First Section Door')
lw_entrances.extend(['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave']) lw_entrances.extend(
['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump',
'Lumberjack Tree Cave'])
lw_entrances_must_exits = list(LW_Dungeon_Entrances_Must_Exit) lw_entrances_must_exits = list(LW_Dungeon_Entrances_Must_Exit)
@ -576,19 +587,20 @@ def link_entrances(world, player):
dw_entrances_must_exits.append('Pyramid Entrance') dw_entrances_must_exits.append('Pyramid Entrance')
dw_doors.extend(['Ganons Tower', 'Pyramid Entrance']) dw_doors.extend(['Ganons Tower', 'Pyramid Entrance'])
random.shuffle(lw_hole_entrances) world.random.shuffle(lw_hole_entrances)
random.shuffle(dw_hole_entrances) world.random.shuffle(dw_hole_entrances)
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
# decide if skull woods first section should be in light or dark world # decide if skull woods first section should be in light or dark world
sw_light = random.randint(0, 1) == 0 sw_light = world.random.randint(0, 1) == 0
if sw_light: if sw_light:
sw_hole_pool = lw_hole_entrances sw_hole_pool = lw_hole_entrances
mandatory_light_world.append('Skull Woods First Section Exit') mandatory_light_world.append('Skull Woods First Section Exit')
else: else:
sw_hole_pool = dw_hole_entrances sw_hole_pool = dw_hole_entrances
mandatory_dark_world.append('Skull Woods First Section Exit') mandatory_dark_world.append('Skull Woods First Section Exit')
for target in ['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']: for target in ['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)',
'Skull Woods First Section (Top)']:
connect_entrance(world, sw_hole_pool.pop(), target, player) connect_entrance(world, sw_hole_pool.pop(), target, player)
# sanctuary has to be in light world # sanctuary has to be in light world
@ -619,7 +631,7 @@ def link_entrances(world, player):
# now let's deal with mandatory reachable stuff # now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist): def extract_reachable_exit(cavelist):
random.shuffle(cavelist) world.random.shuffle(cavelist)
candidate = None candidate = None
for cave in cavelist: for cave in cavelist:
if isinstance(cave, tuple) and len(cave) > 1: if isinstance(cave, tuple) and len(cave) > 1:
@ -636,7 +648,7 @@ def link_entrances(world, player):
def connect_reachable_exit(entrance, general, worldspecific, worldoors): def connect_reachable_exit(entrance, general, worldspecific, worldoors):
# select which one is the primary option # select which one is the primary option
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
primary = general primary = general
secondary = worldspecific secondary = worldspecific
else: else:
@ -656,7 +668,7 @@ def link_entrances(world, player):
worldspecific.append(cave) worldspecific.append(cave)
# we randomize which world requirements we fulfill first so we get better dungeon distribution # we randomize which world requirements we fulfill first so we get better dungeon distribution
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
for entrance in lw_entrances_must_exits: for entrance in lw_entrances_must_exits:
connect_reachable_exit(entrance, caves, mandatory_light_world, lw_doors) connect_reachable_exit(entrance, caves, mandatory_light_world, lw_doors)
for entrance in dw_entrances_must_exits: for entrance in dw_entrances_must_exits:
@ -670,7 +682,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [entrance for entrance in old_man_entrances if entrance in lw_entrances] old_man_entrances = [entrance for entrance in old_man_entrances if entrance in lw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
lw_entrances.remove(old_man_exit) lw_entrances.remove(old_man_exit)
@ -708,7 +720,7 @@ def link_entrances(world, player):
cave_candidate = (i, len(cave)) cave_candidate = (i, len(cave))
cave = caves.pop(cave_candidate[0]) cave = caves.pop(cave_candidate[0])
place_lightworld = random.randint(0, 1) == 0 place_lightworld = world.random.randint(0, 1) == 0
if place_lightworld: if place_lightworld:
target_doors = lw_doors target_doors = lw_doors
target_entrances = lw_entrances target_entrances = lw_entrances
@ -740,13 +752,13 @@ def link_entrances(world, player):
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
# place blacksmith, has limited options # place blacksmith, has limited options
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -774,7 +786,7 @@ def link_entrances(world, player):
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
random.shuffle(doors) world.random.shuffle(doors)
old_man_entrances = list(Old_Man_Entrances) + ['Tower of Hera'] old_man_entrances = list(Old_Man_Entrances) + ['Tower of Hera']
@ -817,9 +829,9 @@ def link_entrances(world, player):
entrances_must_exits.append('Pyramid Entrance') entrances_must_exits.append('Pyramid Entrance')
doors.extend(['Ganons Tower', 'Pyramid Entrance']) doors.extend(['Ganons Tower', 'Pyramid Entrance'])
random.shuffle(hole_entrances) world.random.shuffle(hole_entrances)
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
random.shuffle(entrances) world.random.shuffle(entrances)
# fill up holes # fill up holes
for hole in hole_entrances: for hole in hole_entrances:
@ -838,7 +850,7 @@ def link_entrances(world, player):
# now let's deal with mandatory reachable stuff # now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist): def extract_reachable_exit(cavelist):
random.shuffle(cavelist) world.random.shuffle(cavelist)
candidate = None candidate = None
for cave in cavelist: for cave in cavelist:
if isinstance(cave, tuple) and len(cave) > 1: if isinstance(cave, tuple) and len(cave) > 1:
@ -870,7 +882,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances] old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
entrances.remove(old_man_exit) entrances.remove(old_man_exit)
@ -880,14 +892,14 @@ def link_entrances(world, player):
# place blacksmith, has limited options # place blacksmith, has limited options
blacksmith_doors = [door for door in blacksmith_doors if door in doors] blacksmith_doors = [door for door in blacksmith_doors if door in doors]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
doors.remove(blacksmith_hut) doors.remove(blacksmith_hut)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
bomb_shop_doors = [door for door in bomb_shop_doors if door in doors] bomb_shop_doors = [door for door in bomb_shop_doors if door in doors]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
doors.remove(bomb_shop) doors.remove(bomb_shop)
@ -913,7 +925,7 @@ def link_entrances(world, player):
doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\ doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\
DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)']
random.shuffle(doors) world.random.shuffle(doors)
old_man_entrances = list(Old_Man_Entrances) + ['Tower of Hera'] old_man_entrances = list(Old_Man_Entrances) + ['Tower of Hera']
@ -952,9 +964,9 @@ def link_entrances(world, player):
entrances_must_exits.append('Pyramid Entrance') entrances_must_exits.append('Pyramid Entrance')
doors.extend(['Ganons Tower', 'Pyramid Entrance']) doors.extend(['Ganons Tower', 'Pyramid Entrance'])
random.shuffle(hole_entrances) world.random.shuffle(hole_entrances)
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
random.shuffle(entrances) world.random.shuffle(entrances)
# fill up holes # fill up holes
for hole in hole_entrances: for hole in hole_entrances:
@ -973,7 +985,7 @@ def link_entrances(world, player):
# now let's deal with mandatory reachable stuff # now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist): def extract_reachable_exit(cavelist):
random.shuffle(cavelist) world.random.shuffle(cavelist)
candidate = None candidate = None
for cave in cavelist: for cave in cavelist:
if isinstance(cave, tuple) and len(cave) > 1: if isinstance(cave, tuple) and len(cave) > 1:
@ -1005,7 +1017,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances] old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
entrances.remove(old_man_exit) entrances.remove(old_man_exit)
@ -1030,13 +1042,13 @@ def link_entrances(world, player):
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
# place blacksmith, has limited options # place blacksmith, has limited options
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -1073,7 +1085,7 @@ def link_inverted_entrances(world, player):
Old_Man_House = Old_Man_House_Base.copy() Old_Man_House = Old_Man_House_Base.copy()
Cave_Three_Exits = Cave_Three_Exits_Base.copy() Cave_Three_Exits = Cave_Three_Exits_Base.copy()
unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits) unbias_some_entrances(world, Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits)
# setup mandatory connections # setup mandatory connections
for exitname, regionname in inverted_mandatory_connections: for exitname, regionname in inverted_mandatory_connections:
@ -1102,7 +1114,7 @@ def link_inverted_entrances(world, player):
dw_entrances = list(Inverted_DW_Dungeon_Entrances) dw_entrances = list(Inverted_DW_Dungeon_Entrances)
# randomize which desert ledge door is a must-exit # randomize which desert ledge door is a must-exit
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (North)') lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (North)')
lw_entrances.append('Desert Palace Entrance (West)') lw_entrances.append('Desert Palace Entrance (West)')
else: else:
@ -1123,14 +1135,14 @@ def link_inverted_entrances(world, player):
# shuffle aga door first. If it's on HC ledge, remaining HC ledge door must be must-exit # shuffle aga door first. If it's on HC ledge, remaining HC ledge door must be must-exit
all_entrances_aga = lw_entrances + dw_entrances all_entrances_aga = lw_entrances + dw_entrances
aga_doors = [i for i in all_entrances_aga] aga_doors = [i for i in all_entrances_aga]
random.shuffle(aga_doors) world.random.shuffle(aga_doors)
aga_door = aga_doors.pop() aga_door = aga_doors.pop()
if aga_door in hc_ledge_entrances: if aga_door in hc_ledge_entrances:
lw_entrances.remove(aga_door) lw_entrances.remove(aga_door)
hc_ledge_entrances.remove(aga_door) hc_ledge_entrances.remove(aga_door)
random.shuffle(hc_ledge_entrances) world.random.shuffle(hc_ledge_entrances)
hc_ledge_must_exit = hc_ledge_entrances.pop() hc_ledge_must_exit = hc_ledge_entrances.pop()
lw_entrances.remove(hc_ledge_must_exit) lw_entrances.remove(hc_ledge_must_exit)
lw_dungeon_entrances_must_exit.append(hc_ledge_must_exit) lw_dungeon_entrances_must_exit.append(hc_ledge_must_exit)
@ -1162,8 +1174,8 @@ def link_inverted_entrances(world, player):
# we shuffle all 2 entrance caves as pairs as a start # we shuffle all 2 entrance caves as pairs as a start
# start with the ones that need to be directed # start with the ones that need to be directed
two_door_caves = list(Inverted_Two_Door_Caves_Directional) two_door_caves = list(Inverted_Two_Door_Caves_Directional)
random.shuffle(two_door_caves) world.random.shuffle(two_door_caves)
random.shuffle(caves) world.random.shuffle(caves)
while two_door_caves: while two_door_caves:
entrance1, entrance2 = two_door_caves.pop() entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop() exit1, exit2 = caves.pop()
@ -1172,7 +1184,7 @@ def link_inverted_entrances(world, player):
# now the remaining pairs # now the remaining pairs
two_door_caves = list(Inverted_Two_Door_Caves) two_door_caves = list(Inverted_Two_Door_Caves)
random.shuffle(two_door_caves) world.random.shuffle(two_door_caves)
while two_door_caves: while two_door_caves:
entrance1, entrance2 = two_door_caves.pop() entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop() exit1, exit2 = caves.pop()
@ -1180,8 +1192,9 @@ def link_inverted_entrances(world, player):
connect_two_way(world, entrance2, exit2, player) connect_two_way(world, entrance2, exit2, player)
# place links house # place links house
links_house_doors = [i for i in bomb_shop_doors + blacksmith_doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house_doors = [i for i in bomb_shop_doors + blacksmith_doors if
links_house = random.choice(list(links_house_doors)) i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = world.random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player) connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in bomb_shop_doors: if links_house in bomb_shop_doors:
bomb_shop_doors.remove(links_house) bomb_shop_doors.remove(links_house)
@ -1192,7 +1205,7 @@ def link_inverted_entrances(world, player):
# place dark sanc # place dark sanc
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in bomb_shop_doors] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in bomb_shop_doors]
sanc_door = random.choice(sanc_doors) sanc_door = world.random.choice(sanc_doors)
bomb_shop_doors.remove(sanc_door) bomb_shop_doors.remove(sanc_door)
connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player)
@ -1205,7 +1218,7 @@ def link_inverted_entrances(world, player):
# place old man, bumper cave bottom to DDM entrances not in east bottom # place old man, bumper cave bottom to DDM entrances not in east bottom
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player) connect_two_way(world, 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
@ -1225,14 +1238,14 @@ def link_inverted_entrances(world, player):
# place blacksmith, has limited options # place blacksmith, has limited options
blacksmith_doors = [door for door in blacksmith_doors[:]] blacksmith_doors = [door for door in blacksmith_doors[:]]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place bomb shop, has limited options # place bomb shop, has limited options
bomb_shop_doors = [door for door in bomb_shop_doors[:]] bomb_shop_doors = [door for door in bomb_shop_doors[:]]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) single_doors.extend(bomb_shop_doors)
@ -1257,8 +1270,9 @@ def link_inverted_entrances(world, player):
door_targets = list(Inverted_Single_Cave_Targets) door_targets = list(Inverted_Single_Cave_Targets)
# place links house # place links house
links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if
links_house = random.choice(list(links_house_doors)) i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = world.random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player) connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in lw_entrances: if links_house in lw_entrances:
lw_entrances.remove(links_house) lw_entrances.remove(links_house)
@ -1269,7 +1283,7 @@ def link_inverted_entrances(world, player):
# place dark sanc # place dark sanc
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
sanc_door = random.choice(sanc_doors) sanc_door = world.random.choice(sanc_doors)
dw_entrances.remove(sanc_door) dw_entrances.remove(sanc_door)
connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player)
world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
@ -1283,7 +1297,7 @@ def link_inverted_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in dw_entrances] old_man_entrances = [door for door in old_man_entrances if door in dw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
dw_entrances.remove(old_man_exit) dw_entrances.remove(old_man_exit)
@ -1292,7 +1306,7 @@ def link_inverted_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
if blacksmith_hut in lw_entrances: if blacksmith_hut in lw_entrances:
@ -1305,7 +1319,7 @@ def link_inverted_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player)
if bomb_shop in lw_entrances: if bomb_shop in lw_entrances:
@ -1314,7 +1328,7 @@ def link_inverted_entrances(world, player):
dw_entrances.remove(bomb_shop) dw_entrances.remove(bomb_shop)
# place the old man cave's entrance somewhere in the dark world # place the old man cave's entrance somewhere in the dark world
random.shuffle(dw_entrances) world.random.shuffle(dw_entrances)
old_man_entrance = dw_entrances.pop() old_man_entrance = dw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
@ -1341,7 +1355,7 @@ def link_inverted_entrances(world, player):
old_man_house = list(Old_Man_House) old_man_house = list(Old_Man_House)
# randomize which desert ledge door is a must-exit # randomize which desert ledge door is a must-exit
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
lw_must_exits.append('Desert Palace Entrance (North)') lw_must_exits.append('Desert Palace Entrance (North)')
lw_entrances.append('Desert Palace Entrance (West)') lw_entrances.append('Desert Palace Entrance (West)')
else: else:
@ -1351,7 +1365,8 @@ def link_inverted_entrances(world, player):
# tavern back door cannot be shuffled yet # tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player) connect_doors(world, ['Tavern North'], ['Tavern'], player)
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) caves.append(tuple(world.random.sample(
['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'], 3)))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
@ -1366,14 +1381,14 @@ def link_inverted_entrances(world, player):
# shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit # shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit
all_entrances_aga = lw_entrances + dw_entrances all_entrances_aga = lw_entrances + dw_entrances
aga_doors = [i for i in all_entrances_aga] aga_doors = [i for i in all_entrances_aga]
random.shuffle(aga_doors) world.random.shuffle(aga_doors)
aga_door = aga_doors.pop() aga_door = aga_doors.pop()
if aga_door in hc_ledge_entrances: if aga_door in hc_ledge_entrances:
lw_entrances.remove(aga_door) lw_entrances.remove(aga_door)
hc_ledge_entrances.remove(aga_door) hc_ledge_entrances.remove(aga_door)
random.shuffle(hc_ledge_entrances) world.random.shuffle(hc_ledge_entrances)
hc_ledge_must_exit = hc_ledge_entrances.pop() hc_ledge_must_exit = hc_ledge_entrances.pop()
lw_entrances.remove(hc_ledge_must_exit) lw_entrances.remove(hc_ledge_must_exit)
lw_must_exits.append(hc_ledge_must_exit) lw_must_exits.append(hc_ledge_must_exit)
@ -1387,8 +1402,9 @@ def link_inverted_entrances(world, player):
caves.remove('Inverted Agahnims Tower Exit') caves.remove('Inverted Agahnims Tower Exit')
# place links house # place links house
links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house_doors = [i for i in lw_entrances + dw_entrances + lw_must_exits if
links_house = random.choice(list(links_house_doors)) i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = world.random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player) connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in lw_entrances: if links_house in lw_entrances:
lw_entrances.remove(links_house) lw_entrances.remove(links_house)
@ -1399,14 +1415,14 @@ def link_inverted_entrances(world, player):
# place dark sanc # place dark sanc
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
sanc_door = random.choice(sanc_doors) sanc_door = world.random.choice(sanc_doors)
dw_entrances.remove(sanc_door) dw_entrances.remove(sanc_door)
connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player)
world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
# place old man house # place old man house
# no dw must exits in inverted, but we randomize whether cave is in light or dark world # no dw must exits in inverted, but we randomize whether cave is in light or dark world
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
caves += old_man_house caves += old_man_house
connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player)
try: try:
@ -1422,7 +1438,7 @@ def link_inverted_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in dw_entrances + lw_entrances] old_man_entrances = [door for door in old_man_entrances if door in dw_entrances + lw_entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
if old_man_exit in dw_entrances: if old_man_exit in dw_entrances:
@ -1436,7 +1452,7 @@ def link_inverted_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
if blacksmith_hut in lw_entrances: if blacksmith_hut in lw_entrances:
@ -1449,7 +1465,7 @@ def link_inverted_entrances(world, player):
all_entrances = lw_entrances + dw_entrances all_entrances = lw_entrances + dw_entrances
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player)
if bomb_shop in lw_entrances: if bomb_shop in lw_entrances:
@ -1459,11 +1475,11 @@ def link_inverted_entrances(world, player):
# place the old man cave's entrance somewhere in the same world he'll exit from # place the old man cave's entrance somewhere in the same world he'll exit from
if old_man_world == 'light': if old_man_world == 'light':
random.shuffle(lw_entrances) world.random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop() old_man_entrance = lw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
elif old_man_world == 'dark': elif old_man_world == 'dark':
random.shuffle(dw_entrances) world.random.shuffle(dw_entrances)
old_man_entrance = dw_entrances.pop() old_man_entrance = dw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
@ -1490,14 +1506,15 @@ def link_inverted_entrances(world, player):
door_targets = list(Inverted_Single_Cave_Targets) door_targets = list(Inverted_Single_Cave_Targets)
# randomize which desert ledge door is a must-exit # randomize which desert ledge door is a must-exit
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
must_exits.append('Desert Palace Entrance (North)') must_exits.append('Desert Palace Entrance (North)')
entrances.append('Desert Palace Entrance (West)') entrances.append('Desert Palace Entrance (West)')
else: else:
must_exits.append('Desert Palace Entrance (West)') must_exits.append('Desert Palace Entrance (West)')
entrances.append('Desert Palace Entrance (North)') entrances.append('Desert Palace Entrance (North)')
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) caves.append(tuple(world.random.sample(
['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'], 3)))
entrances.append('Hyrule Castle Entrance (South)') entrances.append('Hyrule Castle Entrance (South)')
if not world.shuffle_ganon: if not world.shuffle_ganon:
@ -1509,12 +1526,12 @@ def link_inverted_entrances(world, player):
hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower']
# shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit # shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit
aga_door = random.choice(list(entrances)) aga_door = world.random.choice(list(entrances))
if aga_door in hc_ledge_entrances: if aga_door in hc_ledge_entrances:
hc_ledge_entrances.remove(aga_door) hc_ledge_entrances.remove(aga_door)
random.shuffle(hc_ledge_entrances) world.random.shuffle(hc_ledge_entrances)
hc_ledge_must_exit = hc_ledge_entrances.pop() hc_ledge_must_exit = hc_ledge_entrances.pop()
entrances.remove(hc_ledge_must_exit) entrances.remove(hc_ledge_must_exit)
must_exits.append(hc_ledge_must_exit) must_exits.append(hc_ledge_must_exit)
@ -1525,8 +1542,9 @@ def link_inverted_entrances(world, player):
# place links house # place links house
links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house_doors = [i for i in entrances + must_exits if
links_house = random.choice(list(links_house_doors)) i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = world.random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player) connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in entrances: if links_house in entrances:
entrances.remove(links_house) entrances.remove(links_house)
@ -1535,7 +1553,7 @@ def link_inverted_entrances(world, player):
# place dark sanc # place dark sanc
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in entrances] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in entrances]
sanc_door = random.choice(sanc_doors) sanc_door = world.random.choice(sanc_doors)
entrances.remove(sanc_door) entrances.remove(sanc_door)
connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player)
world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
@ -1551,7 +1569,7 @@ def link_inverted_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [door for door in old_man_entrances if door in entrances] old_man_entrances = [door for door in old_man_entrances if door in entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
entrances.remove(old_man_exit) entrances.remove(old_man_exit)
@ -1559,7 +1577,7 @@ def link_inverted_entrances(world, player):
# place blacksmith, has limited options # place blacksmith, has limited options
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
blacksmith_doors = [door for door in blacksmith_doors if door in entrances] blacksmith_doors = [door for door in blacksmith_doors if door in entrances]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
entrances.remove(blacksmith_hut) entrances.remove(blacksmith_hut)
@ -1568,13 +1586,13 @@ def link_inverted_entrances(world, player):
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player)
entrances.remove(bomb_shop) entrances.remove(bomb_shop)
# place the old man cave's entrance somewhere # place the old man cave's entrance somewhere
random.shuffle(entrances) world.random.shuffle(entrances)
old_man_entrance = entrances.pop() old_man_entrance = entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
@ -1597,7 +1615,7 @@ def link_inverted_entrances(world, player):
Inverted_LW_Single_Cave_Doors + Inverted_DW_Single_Cave_Doors + ['Desert Palace Entrance (West)', 'Desert Palace Entrance (North)'] Inverted_LW_Single_Cave_Doors + Inverted_DW_Single_Cave_Doors + ['Desert Palace Entrance (West)', 'Desert Palace Entrance (North)']
# randomize which desert ledge door is a must-exit # randomize which desert ledge door is a must-exit
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
entrances_must_exits.append('Desert Palace Entrance (North)') entrances_must_exits.append('Desert Palace Entrance (North)')
entrances.append('Desert Palace Entrance (West)') entrances.append('Desert Palace Entrance (West)')
else: else:
@ -1612,7 +1630,7 @@ def link_inverted_entrances(world, player):
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors)
door_targets = list(Inverted_Single_Cave_Targets) door_targets = list(Inverted_Single_Cave_Targets)
random.shuffle(doors) world.random.shuffle(doors)
old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances) + ['Tower of Hera', 'Inverted Agahnims Tower'] old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances) + ['Tower of Hera', 'Inverted Agahnims Tower']
@ -1646,9 +1664,9 @@ def link_inverted_entrances(world, player):
hole_targets.append('Pyramid') hole_targets.append('Pyramid')
doors.extend(['Inverted Ganons Tower', 'Inverted Pyramid Entrance']) doors.extend(['Inverted Ganons Tower', 'Inverted Pyramid Entrance'])
random.shuffle(hole_entrances) world.random.shuffle(hole_entrances)
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
random.shuffle(entrances) world.random.shuffle(entrances)
# fill up holes # fill up holes
for hole in hole_entrances: for hole in hole_entrances:
@ -1658,8 +1676,9 @@ def link_inverted_entrances(world, player):
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
# place links house and dark sanc # place links house and dark sanc
links_house_doors = [i for i in entrances + entrances_must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house_doors = [i for i in entrances + entrances_must_exits if
links_house = random.choice(list(links_house_doors)) i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = world.random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Inverted Links House Exit', player) connect_two_way(world, links_house, 'Inverted Links House Exit', player)
if links_house in entrances: if links_house in entrances:
entrances.remove(links_house) entrances.remove(links_house)
@ -1668,7 +1687,7 @@ def link_inverted_entrances(world, player):
doors.remove(links_house) doors.remove(links_house)
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in entrances] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in entrances]
sanc_door = random.choice(sanc_doors) sanc_door = world.random.choice(sanc_doors)
entrances.remove(sanc_door) entrances.remove(sanc_door)
doors.remove(sanc_door) doors.remove(sanc_door)
connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player)
@ -1676,7 +1695,7 @@ def link_inverted_entrances(world, player):
# now let's deal with mandatory reachable stuff # now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist): def extract_reachable_exit(cavelist):
random.shuffle(cavelist) world.random.shuffle(cavelist)
candidate = None candidate = None
for cave in cavelist: for cave in cavelist:
if isinstance(cave, tuple) and len(cave) > 1: if isinstance(cave, tuple) and len(cave) > 1:
@ -1708,7 +1727,7 @@ def link_inverted_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances] old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances]
random.shuffle(old_man_entrances) world.random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
entrances.remove(old_man_exit) entrances.remove(old_man_exit)
@ -1718,14 +1737,14 @@ def link_inverted_entrances(world, player):
# place blacksmith, has limited options # place blacksmith, has limited options
blacksmith_doors = [door for door in blacksmith_doors if door in doors] blacksmith_doors = [door for door in blacksmith_doors if door in doors]
random.shuffle(blacksmith_doors) world.random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
doors.remove(blacksmith_hut) doors.remove(blacksmith_hut)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
bomb_shop_doors = [door for door in bomb_shop_doors if door in doors] bomb_shop_doors = [door for door in bomb_shop_doors if door in doors]
random.shuffle(bomb_shop_doors) world.random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player)
doors.remove(bomb_shop) doors.remove(bomb_shop)
@ -1843,14 +1862,14 @@ def scramble_holes(world, player):
if world.shuffle[player] == 'crossed': if world.shuffle[player] == 'crossed':
hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) hole_targets.append(('Sanctuary Exit', 'Sewer Drop'))
if world.shuffle_ganon: if world.shuffle_ganon:
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
exit, target = hole_targets.pop() exit, target = hole_targets.pop()
connect_two_way(world, 'Pyramid Entrance', exit, player) connect_two_way(world, 'Pyramid Entrance', exit, player)
connect_entrance(world, 'Pyramid Hole', target, player) connect_entrance(world, 'Pyramid Hole', target, player)
if world.shuffle[player] != 'crossed': if world.shuffle[player] != 'crossed':
hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) hole_targets.append(('Sanctuary Exit', 'Sewer Drop'))
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
for entrance, drop in hole_entrances: for entrance, drop in hole_entrances:
exit, target = hole_targets.pop() exit, target = hole_targets.pop()
connect_two_way(world, entrance, exit, player) connect_two_way(world, entrance, exit, player)
@ -1885,14 +1904,14 @@ def scramble_inverted_holes(world, player):
if world.shuffle[player] == 'crossed': if world.shuffle[player] == 'crossed':
hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) hole_targets.append(('Sanctuary Exit', 'Sewer Drop'))
if world.shuffle_ganon: if world.shuffle_ganon:
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
exit, target = hole_targets.pop() exit, target = hole_targets.pop()
connect_two_way(world, 'Inverted Pyramid Entrance', exit, player) connect_two_way(world, 'Inverted Pyramid Entrance', exit, player)
connect_entrance(world, 'Inverted Pyramid Hole', target, player) connect_entrance(world, 'Inverted Pyramid Hole', target, player)
if world.shuffle[player] != 'crossed': if world.shuffle[player] != 'crossed':
hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) hole_targets.append(('Sanctuary Exit', 'Sewer Drop'))
random.shuffle(hole_targets) world.random.shuffle(hole_targets)
for entrance, drop in hole_entrances: for entrance, drop in hole_entrances:
exit, target = hole_targets.pop() exit, target = hole_targets.pop()
connect_two_way(world, entrance, exit, player) connect_two_way(world, entrance, exit, player)
@ -1900,7 +1919,7 @@ def scramble_inverted_holes(world, player):
def connect_random(world, exitlist, targetlist, player, two_way=False): def connect_random(world, exitlist, targetlist, player, two_way=False):
targetlist = list(targetlist) targetlist = list(targetlist)
random.shuffle(targetlist) world.random.shuffle(targetlist)
for exit, target in zip(exitlist, targetlist): for exit, target in zip(exitlist, targetlist):
if two_way: if two_way:
@ -1927,15 +1946,17 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player):
entrances.append(entrance) entrances.append(entrance)
"""This works inplace""" """This works inplace"""
random.shuffle(entrances) world.random.shuffle(entrances)
random.shuffle(caves) world.random.shuffle(caves)
# Handle inverted Aga Tower - if it depends on connections, then so does Hyrule Castle Ledge # Handle inverted Aga Tower - if it depends on connections, then so does Hyrule Castle Ledge
if world.mode[player] == 'inverted': if world.mode[player] == 'inverted':
for entrance in invalid_connections: for entrance in invalid_connections:
if world.get_entrance(entrance, player).connected_region == world.get_region('Inverted Agahnims Tower', player): if world.get_entrance(entrance, player).connected_region == world.get_region('Inverted Agahnims Tower',
player):
for exit in invalid_connections[entrance]: for exit in invalid_connections[entrance]:
invalid_connections[exit] = invalid_connections[exit].union({'Inverted Ganons Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) invalid_connections[exit] = invalid_connections[exit].union(
{'Inverted Ganons Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'})
break break
used_caves = [] used_caves = []
@ -1984,7 +2005,7 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player):
else: else:
required_entrances += len(cave)-1 required_entrances += len(cave)-1
caves.append(cave[0:-1]) caves.append(cave[0:-1])
random.shuffle(caves) world.random.shuffle(caves)
used_caves.append(cave[0:-1]) used_caves.append(cave[0:-1])
invalid_cave_connections[tuple(cave[0:-1])] = invalid_cave_connections[tuple(cave)].union(invalid_connections[exit]) invalid_cave_connections[tuple(cave[0:-1])] = invalid_cave_connections[tuple(cave)].union(invalid_connections[exit])
caves.remove(cave) caves.remove(cave)
@ -2000,9 +2021,9 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player):
def connect_caves(world, lw_entrances, dw_entrances, caves, player): def connect_caves(world, lw_entrances, dw_entrances, caves, player):
"""This works inplace""" """This works inplace"""
random.shuffle(lw_entrances) world.random.shuffle(lw_entrances)
random.shuffle(dw_entrances) world.random.shuffle(dw_entrances)
random.shuffle(caves) world.random.shuffle(caves)
while caves: while caves:
# connect highest exit count caves first, prevent issue where we have 2 or 3 exits accross worlds left to fill # connect highest exit count caves first, prevent issue where we have 2 or 3 exits accross worlds left to fill
cave_candidate = (None, 0) cave_candidate = (None, 0)
@ -2013,7 +2034,7 @@ def connect_caves(world, lw_entrances, dw_entrances, caves, player):
cave_candidate = (i, len(cave)) cave_candidate = (i, len(cave))
cave = caves.pop(cave_candidate[0]) cave = caves.pop(cave_candidate[0])
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances target = lw_entrances if world.random.randint(0, 1) == 0 else dw_entrances
if isinstance(cave, str): if isinstance(cave, str):
cave = (cave,) cave = (cave,)
@ -2028,8 +2049,8 @@ def connect_caves(world, lw_entrances, dw_entrances, caves, player):
def connect_doors(world, doors, targets, player): def connect_doors(world, doors, targets, player):
"""This works inplace""" """This works inplace"""
random.shuffle(doors) world.random.shuffle(doors)
random.shuffle(targets) world.random.shuffle(targets)
while doors: while doors:
door = doors.pop() door = doors.pop()
target = targets.pop() target = targets.pop()
@ -2066,7 +2087,7 @@ def simple_shuffle_dungeons(world, player):
multi_dungeons = ['Desert', 'Turtle Rock'] multi_dungeons = ['Desert', 'Turtle Rock']
if world.mode[player] == 'open' or (world.mode[player] == 'inverted' and world.shuffle_ganon): if world.mode[player] == 'open' or (world.mode[player] == 'inverted' and world.shuffle_ganon):
multi_dungeons.append('Hyrule Castle') multi_dungeons.append('Hyrule Castle')
random.shuffle(multi_dungeons) world.random.shuffle(multi_dungeons)
dp_target = multi_dungeons[0] dp_target = multi_dungeons[0]
tr_target = multi_dungeons[1] tr_target = multi_dungeons[1]
@ -2175,11 +2196,12 @@ def simple_shuffle_dungeons(world, player):
connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', player) connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', player)
connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', player) connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', player)
def unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits):
def unbias_some_entrances(world, Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits):
def shuffle_lists_in_list(ls): def shuffle_lists_in_list(ls):
for i, item in enumerate(ls): for i, item in enumerate(ls):
if isinstance(item, list): if isinstance(item, list):
ls[i] = random.sample(item, len(item)) ls[i] = world.random.sample(item, len(item))
def tuplize_lists_in_list(ls): def tuplize_lists_in_list(ls):
for i, item in enumerate(ls): for i, item in enumerate(ls):
@ -2193,7 +2215,7 @@ def unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_E
# paradox fixup # paradox fixup
if Cave_Three_Exits[1][0] == "Paradox Cave Exit (Bottom)": if Cave_Three_Exits[1][0] == "Paradox Cave Exit (Bottom)":
i = random.randint(1,2) i = world.random.randint(1, 2)
Cave_Three_Exits[1][0] = Cave_Three_Exits[1][i] Cave_Three_Exits[1][0] = Cave_Three_Exits[1][i]
Cave_Three_Exits[1][i] = "Paradox Cave Exit (Bottom)" Cave_Three_Exits[1][i] = "Paradox Cave Exit (Bottom)"

39
Fill.py
View File

@ -1,4 +1,3 @@
import random
import logging import logging
from BaseClasses import CollectionState from BaseClasses import CollectionState
@ -10,10 +9,10 @@ class FillError(RuntimeError):
def distribute_items_cutoff(world, cutoffrate=0.33): def distribute_items_cutoff(world, cutoffrate=0.33):
# get list of locations to fill in # get list of locations to fill in
fill_locations = world.get_unfilled_locations() fill_locations = world.get_unfilled_locations()
random.shuffle(fill_locations) world.random.shuffle(fill_locations)
# get items to distribute # get items to distribute
random.shuffle(world.itempool) world.random.shuffle(world.itempool)
itempool = world.itempool itempool = world.itempool
total_advancement_items = len([item for item in itempool if item.advancement]) total_advancement_items = len([item for item in itempool if item.advancement])
@ -83,10 +82,10 @@ def distribute_items_cutoff(world, cutoffrate=0.33):
def distribute_items_staleness(world): def distribute_items_staleness(world):
# get list of locations to fill in # get list of locations to fill in
fill_locations = world.get_unfilled_locations() fill_locations = world.get_unfilled_locations()
random.shuffle(fill_locations) world.random.shuffle(fill_locations)
# get items to distribute # get items to distribute
random.shuffle(world.itempool) world.random.shuffle(world.itempool)
itempool = world.itempool itempool = world.itempool
progress_done = False progress_done = False
@ -131,7 +130,7 @@ def distribute_items_staleness(world):
spot_to_fill = None spot_to_fill = None
for location in fill_locations: for location in fill_locations:
# increase likelyhood of skipping a location if it has been found stale # increase likelyhood of skipping a location if it has been found stale
if not progress_done and random.randint(0, location.staleness_count) > 2: if not progress_done and world.random.randint(0, location.staleness_count) > 2:
continue continue
if location.can_fill(world.state, item_to_place): if location.can_fill(world.state, item_to_place):
@ -215,10 +214,10 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
# If not passed in, then get a shuffled list of locations to fill in # If not passed in, then get a shuffled list of locations to fill in
if not fill_locations: if not fill_locations:
fill_locations = world.get_unfilled_locations() fill_locations = world.get_unfilled_locations()
random.shuffle(fill_locations) world.random.shuffle(fill_locations)
# get items to distribute # get items to distribute
random.shuffle(world.itempool) world.random.shuffle(world.itempool)
progitempool = [] progitempool = []
localprioitempool = {player: [] for player in range(1, world.players + 1)} localprioitempool = {player: [] for player in range(1, world.players + 1)}
localrestitempool = {player: [] for player in range(1, world.players + 1)} localrestitempool = {player: [] for player in range(1, world.players + 1)}
@ -244,17 +243,17 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
continue continue
gftower_trash_count = ( gftower_trash_count = (
random.randint(15, 50) if 'triforcehunt' in world.goal[player] world.random.randint(15, 50) if 'triforcehunt' in world.goal[player]
else random.randint(0, 15)) else world.random.randint(0, 15))
gtower_locations = [location for location in fill_locations if gtower_locations = [location for location in fill_locations if
'Ganons Tower' in location.name and location.player == player] 'Ganons Tower' in location.name and location.player == player]
random.shuffle(gtower_locations) world.random.shuffle(gtower_locations)
trashcnt = 0 trashcnt = 0
localrest = localrestitempool[player] localrest = localrestitempool[player]
if localrest: if localrest:
gt_item_pool = restitempool + localrest gt_item_pool = restitempool + localrest
random.shuffle(gt_item_pool) world.random.shuffle(gt_item_pool)
else: else:
gt_item_pool = restitempool.copy() gt_item_pool = restitempool.copy()
@ -269,7 +268,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
fill_locations.remove(spot_to_fill) fill_locations.remove(spot_to_fill)
trashcnt += 1 trashcnt += 1
random.shuffle(fill_locations) world.random.shuffle(fill_locations)
fill_locations.reverse() fill_locations.reverse()
# Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots # Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots
@ -283,20 +282,20 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
localprioitempool.values() or localrestitempool.values()): # we need to make sure some fills are limited to certain worlds localprioitempool.values() or localrestitempool.values()): # we need to make sure some fills are limited to certain worlds
for player, items in localprioitempool.items(): # items already shuffled for player, items in localprioitempool.items(): # items already shuffled
local_locations = [location for location in fill_locations if location.player == player] local_locations = [location for location in fill_locations if location.player == player]
random.shuffle(local_locations) world.random.shuffle(local_locations)
for item_to_place in items: for item_to_place in items:
spot_to_fill = local_locations.pop() spot_to_fill = local_locations.pop()
world.push_item(spot_to_fill, item_to_place, False) world.push_item(spot_to_fill, item_to_place, False)
fill_locations.remove(spot_to_fill) fill_locations.remove(spot_to_fill)
for player, items in localrestitempool.items(): # items already shuffled for player, items in localrestitempool.items(): # items already shuffled
local_locations = [location for location in fill_locations if location.player == player] local_locations = [location for location in fill_locations if location.player == player]
random.shuffle(local_locations) world.random.shuffle(local_locations)
for item_to_place in items: for item_to_place in items:
spot_to_fill = local_locations.pop() spot_to_fill = local_locations.pop()
world.push_item(spot_to_fill, item_to_place, False) world.push_item(spot_to_fill, item_to_place, False)
fill_locations.remove(spot_to_fill) fill_locations.remove(spot_to_fill)
random.shuffle(fill_locations) world.random.shuffle(fill_locations)
fast_fill(world, prioitempool, fill_locations) fast_fill(world, prioitempool, fill_locations)
@ -314,7 +313,7 @@ def fast_fill(world, item_pool, fill_locations):
def flood_items(world): def flood_items(world):
# get items to distribute # get items to distribute
random.shuffle(world.itempool) world.random.shuffle(world.itempool)
itempool = world.itempool itempool = world.itempool
progress_done = False progress_done = False
@ -324,7 +323,7 @@ def flood_items(world):
# fill world from top of itempool while we can # fill world from top of itempool while we can
while not progress_done: while not progress_done:
location_list = world.get_unfilled_locations() location_list = world.get_unfilled_locations()
random.shuffle(location_list) world.random.shuffle(location_list)
spot_to_fill = None spot_to_fill = None
for location in location_list: for location in location_list:
if location.can_fill(world.state, itempool[0]): if location.can_fill(world.state, itempool[0]):
@ -360,7 +359,7 @@ def flood_items(world):
# find item to replace with progress item # find item to replace with progress item
location_list = world.get_reachable_locations() location_list = world.get_reachable_locations()
random.shuffle(location_list) world.random.shuffle(location_list)
for location in location_list: for location in location_list:
if location.item is not None and not location.item.advancement and not location.item.priority and not location.item.smallkey and not location.item.bigkey: if location.item is not None and not location.item.advancement and not location.item.priority and not location.item.smallkey and not location.item.bigkey:
# safe to replace # safe to replace
@ -380,7 +379,7 @@ def balance_multiworld_progression(world):
state = CollectionState(world) state = CollectionState(world)
checked_locations = [] checked_locations = []
unchecked_locations = world.get_locations().copy() unchecked_locations = world.get_locations().copy()
random.shuffle(unchecked_locations) world.random.shuffle(unchecked_locations)
reachable_locations_count = {player: 0 for player in range(1, world.players + 1)} reachable_locations_count = {player: 0 for player in range(1, world.players + 1)}

View File

@ -1,6 +1,5 @@
from collections import namedtuple from collections import namedtuple
import logging import logging
import random
from BaseClasses import Region, RegionType, Shop, ShopType, Location from BaseClasses import Region, RegionType, Shop, ShopType, Location
from Bosses import place_bosses from Bosses import place_bosses
@ -181,10 +180,7 @@ def generate_itempool(world, player):
# set up item pool # set up item pool
if world.custom: if world.custom:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon,
lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive[player], world.shuffle[player], lamps_needed_for_dark_rooms) = make_custom_item_pool(world, player)
world.difficulty[player], world.timer[player], world.goal[player],
world.mode[player], world.swords[player],
world.retro[player], world.customitemarray)
world.rupoor_cost = min(world.customitemarray[69], 9999) world.rupoor_cost = min(world.customitemarray[69], 9999)
else: else:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon,
@ -209,7 +205,7 @@ def generate_itempool(world, player):
if item in ['Hammer', 'Bombs (10)', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']: if item in ['Hammer', 'Bombs (10)', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']:
if item not in possible_weapons: if item not in possible_weapons:
possible_weapons.append(item) possible_weapons.append(item)
starting_weapon = random.choice(possible_weapons) starting_weapon = world.random.choice(possible_weapons)
placed_items["Link's Uncle"] = starting_weapon placed_items["Link's Uncle"] = starting_weapon
pool.remove(starting_weapon) pool.remove(starting_weapon)
if placed_items["Link's Uncle"] in ['Bow', 'Progressive Bow', 'Bombs (10)', 'Cane of Somaria', 'Cane of Byrna'] and world.enemy_health[player] not in ['default', 'easy']: if placed_items["Link's Uncle"] in ['Bow', 'Progressive Bow', 'Bombs (10)', 'Cane of Somaria', 'Cane of Byrna'] and world.enemy_health[player] not in ['default', 'easy']:
@ -255,13 +251,14 @@ def generate_itempool(world, player):
4: {'trap': 100}} 4: {'trap': 100}}
def beemizer(item): def beemizer(item):
if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type: if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type:
choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0] choice = world.random.choices(list(beeweights[world.beemizer[item.player]].keys()),
weights=list(beeweights[world.beemizer[item.player]].values()))[0]
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player) return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player)
return item return item
progressionitems = [item for item in items if item.advancement or item.priority or item.type] progressionitems = [item for item in items if item.advancement or item.priority or item.type]
nonprogressionitems = [beemizer(item) for item in items if not item.advancement and not item.priority and not item.type] nonprogressionitems = [beemizer(item) for item in items if not item.advancement and not item.priority and not item.type]
random.shuffle(nonprogressionitems) world.random.shuffle(nonprogressionitems)
triforce_pieces = world.triforce_pieces_available[player] triforce_pieces = world.triforce_pieces_available[player]
if 'triforcehunt' in world.goal[player] and triforce_pieces > 30: if 'triforcehunt' in world.goal[player] and triforce_pieces > 30:
@ -271,8 +268,8 @@ def generate_itempool(world, player):
world.itempool += progressionitems + nonprogressionitems world.itempool += progressionitems + nonprogressionitems
# shuffle medallions # shuffle medallions
mm_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] mm_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)]
tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] tr_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)]
world.required_medallions[player] = (mm_medallion, tr_medallion) world.required_medallions[player] = (mm_medallion, tr_medallion)
place_bosses(world, player) place_bosses(world, player)
@ -297,7 +294,7 @@ def set_up_take_anys(world, player):
if world.mode[player] == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations: if world.mode[player] == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations:
take_any_locations.remove('Dark Sanctuary Hint') take_any_locations.remove('Dark Sanctuary Hint')
regions = random.sample(take_any_locations, 5) regions = world.random.sample(take_any_locations, 5)
old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave, 'the sword cave', player) old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave, 'the sword cave', player)
world.regions.append(old_man_take_any) world.regions.append(old_man_take_any)
@ -312,7 +309,7 @@ def set_up_take_anys(world, player):
swords = [item for item in world.itempool if item.type == 'Sword' and item.player == player] swords = [item for item in world.itempool if item.type == 'Sword' and item.player == player]
if swords: if swords:
sword = random.choice(swords) sword = world.random.choice(swords)
world.itempool.remove(sword) world.itempool.remove(sword)
world.itempool.append(ItemFactory('Rupees (20)', player)) world.itempool.append(ItemFactory('Rupees (20)', player))
old_man_take_any.shop.add_inventory(0, sword.name, 0, 0, create_location=True) old_man_take_any.shop.add_inventory(0, sword.name, 0, 0, create_location=True)
@ -324,7 +321,7 @@ def set_up_take_anys(world, player):
world.regions.append(take_any) world.regions.append(take_any)
world.dynamic_regions.append(take_any) world.dynamic_regions.append(take_any)
target, room_id = random.choice([(0x58, 0x0112), (0x60, 0x010F), (0x46, 0x011F)]) target, room_id = world.random.choice([(0x58, 0x0112), (0x60, 0x010F), (0x46, 0x011F)])
reg = regions.pop() reg = regions.pop()
entrance = world.get_region(reg, player).entrances[0] entrance = world.get_region(reg, player).entrances[0]
connect_entrance(world, entrance.name, take_any.name, player) connect_entrance(world, entrance.name, take_any.name, player)
@ -368,8 +365,8 @@ def fill_prizes(world, attempts=15):
try: try:
prizepool = list(unplaced_prizes) prizepool = list(unplaced_prizes)
prize_locs = list(empty_crystal_locations) prize_locs = list(empty_crystal_locations)
random.shuffle(prizepool) world.random.shuffle(prizepool)
random.shuffle(prize_locs) world.random.shuffle(prize_locs)
fill_restrictive(world, all_state, prize_locs, prizepool, True) fill_restrictive(world, all_state, prize_locs, prizepool, True)
except FillError as e: except FillError as e:
logging.getLogger('').exception("Failed to place dungeon prizes (%s). Will retry %s more times", e, logging.getLogger('').exception("Failed to place dungeon prizes (%s). Will retry %s more times", e,
@ -389,7 +386,9 @@ def set_up_shops(world, player):
rss = world.get_region('Red Shield Shop', player).shop rss = world.get_region('Red Shield Shop', player).shop
if not rss.locked: if not rss.locked:
rss.add_inventory(2, 'Single Arrow', 80) rss.add_inventory(2, 'Single Arrow', 80)
for shop in random.sample([s for s in world.shops if s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player], 5): for shop in world.random.sample([s for s in world.shops if
s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player],
5):
shop.locked = True shop.locked = True
shop.add_inventory(0, 'Single Arrow', 80) shop.add_inventory(0, 'Single Arrow', 80)
shop.add_inventory(1, 'Small Key (Universal)', 100) shop.add_inventory(1, 'Small Key (Universal)', 100)
@ -422,7 +421,7 @@ def get_pool_core(world, player: int):
placed_items[loc] = item placed_items[loc] = item
def want_progressives(): def want_progressives():
return random.choice([True, False]) if progressive == 'random' else progressive == 'on' return world.random.choice([True, False]) if progressive == 'random' else progressive == 'on'
# provide boots to major glitch dependent seeds # provide boots to major glitch dependent seeds
if logic in {'owglitches', 'nologic'} and world.glitch_boots[player]: if logic in {'owglitches', 'nologic'} and world.glitch_boots[player]:
@ -455,10 +454,10 @@ def get_pool_core(world, player: int):
# expert+ difficulties produce the same contents for # expert+ difficulties produce the same contents for
# all bottles, since only one bottle is available # all bottles, since only one bottle is available
if diff.same_bottle: if diff.same_bottle:
thisbottle = random.choice(diff.bottles) thisbottle = world.random.choice(diff.bottles)
for _ in range(diff.bottle_count): for _ in range(diff.bottle_count):
if not diff.same_bottle: if not diff.same_bottle:
thisbottle = random.choice(diff.bottles) thisbottle = world.random.choice(diff.bottles)
pool.append(thisbottle) pool.append(thisbottle)
if want_progressives(): if want_progressives():
@ -482,7 +481,7 @@ def get_pool_core(world, player: int):
pool.extend(diff.swordless) pool.extend(diff.swordless)
elif swords == 'vanilla': elif swords == 'vanilla':
swords_to_use = diff.progressivesword.copy() if want_progressives() else diff.basicsword.copy() swords_to_use = diff.progressivesword.copy() if want_progressives() else diff.basicsword.copy()
random.shuffle(swords_to_use) world.random.shuffle(swords_to_use)
place_item('Link\'s Uncle', swords_to_use.pop()) place_item('Link\'s Uncle', swords_to_use.pop())
place_item('Blacksmith', swords_to_use.pop()) place_item('Blacksmith', swords_to_use.pop())
@ -535,13 +534,24 @@ def get_pool_core(world, player: int):
pool = [item.replace('Arrow Upgrade (+10)','Rupees (5)') for item in pool] pool = [item.replace('Arrow Upgrade (+10)','Rupees (5)') for item in pool]
pool.extend(diff.retro) pool.extend(diff.retro)
if mode == 'standard': if mode == 'standard':
key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross']) key_location = world.random.choice(
['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest',
'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
place_item(key_location, 'Small Key (Universal)') place_item(key_location, 'Small Key (Universal)')
else: else:
pool.extend(['Small Key (Universal)']) pool.extend(['Small Key (Universal)'])
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray):
def make_custom_item_pool(world, player):
shuffle = world.shuffle[player]
difficulty = world.difficulty[player]
timer = world.timer[player]
goal = world.goal[player]
mode = world.mode[player]
retro = world.retro[player]
customitemarray = world.customitemarray[player]
pool = [] pool = []
placed_items = {} placed_items = {}
precollected_items = [] precollected_items = []
@ -636,10 +646,10 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
# expert+ difficulties produce the same contents for # expert+ difficulties produce the same contents for
# all bottles, since only one bottle is available # all bottles, since only one bottle is available
if diff.same_bottle: if diff.same_bottle:
thisbottle = random.choice(diff.bottles) thisbottle = world.random.choice(diff.bottles)
for _ in range(customitemarray[18]): for _ in range(customitemarray[18]):
if not diff.same_bottle: if not diff.same_bottle:
thisbottle = random.choice(diff.bottles) thisbottle = world.random.choice(diff.bottles)
pool.append(thisbottle) pool.append(thisbottle)
if customitemarray[66] > 0 or customitemarray[67] > 0: if customitemarray[66] > 0 or customitemarray[67] > 0:
@ -664,7 +674,9 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
if mode == 'standard': if mode == 'standard':
if retro: if retro:
key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross']) key_location = world.random.choice(
['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest',
'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
place_item(key_location, 'Small Key (Universal)') place_item(key_location, 'Small Key (Universal)')
pool.extend(['Small Key (Universal)'] * max((customitemarray[70] - 1), 0)) pool.extend(['Small Key (Universal)'] * max((customitemarray[70] - 1), 0))
else: else:

18
Main.py
View File

@ -43,17 +43,25 @@ def main(args, seed=None):
world = World(args.multi, args.shuffle, args.logic, args.mode, args.swords, args.difficulty, world = World(args.multi, args.shuffle, args.logic, args.mode, args.swords, args.difficulty,
args.item_functionality, args.timer, args.progressive.copy(), args.goal, args.algorithm, args.item_functionality, args.timer, args.progressive.copy(), args.goal, args.algorithm,
args.accessibility, args.shuffleganon, args.retro, args.custom, args.customitemarray, args.hints) args.accessibility, args.shuffleganon, args.retro, args.custom, args.customitemarray, args.hints)
logger = logging.getLogger('') logger = logging.getLogger('')
world.seed = get_seed(seed) world.seed = get_seed(seed)
random.seed(world.seed) if args.race:
world.secure()
else:
world.random.seed(world.seed)
world.remote_items = args.remote_items.copy() world.remote_items = args.remote_items.copy()
world.mapshuffle = args.mapshuffle.copy() world.mapshuffle = args.mapshuffle.copy()
world.compassshuffle = args.compassshuffle.copy() world.compassshuffle = args.compassshuffle.copy()
world.keyshuffle = args.keyshuffle.copy() world.keyshuffle = args.keyshuffle.copy()
world.bigkeyshuffle = args.bigkeyshuffle.copy() world.bigkeyshuffle = args.bigkeyshuffle.copy()
world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_ganon = {
world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)} player: world.random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(
args.crystals_ganon[player]) for player in range(1, world.players + 1)}
world.crystals_needed_for_gt = {
player: world.random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player])
for player in range(1, world.players + 1)}
world.open_pyramid = args.openpyramid.copy() world.open_pyramid = args.openpyramid.copy()
world.boss_shuffle = args.shufflebosses.copy() world.boss_shuffle = args.shufflebosses.copy()
world.enemy_shuffle = args.shuffleenemies.copy() world.enemy_shuffle = args.shuffleenemies.copy()
@ -69,7 +77,7 @@ def main(args, seed=None):
world.triforce_pieces_required = args.triforce_pieces_required.copy() 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.progression_balancing = {player: not balance for player, balance in args.skip_progression_balancing.items()}
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.rom_seeds = {player: 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) logger.info('ALttP Berserker\'s Multiworld Version %s - Seed: %s\n', __version__, world.seed)
@ -134,7 +142,7 @@ def main(args, seed=None):
if args.algorithm in ['balanced', 'vt26'] or any(list(args.mapshuffle.values()) + list(args.compassshuffle.values()) + if args.algorithm in ['balanced', 'vt26'] or any(list(args.mapshuffle.values()) + list(args.compassshuffle.values()) +
list(args.keyshuffle.values()) + list(args.bigkeyshuffle.values())): list(args.keyshuffle.values()) + list(args.bigkeyshuffle.values())):
shuffled_locations = world.get_unfilled_locations() shuffled_locations = world.get_unfilled_locations()
random.shuffle(shuffled_locations) world.random.shuffle(shuffled_locations)
fill_dungeons_restrictive(world, shuffled_locations) fill_dungeons_restrictive(world, shuffled_locations)
else: else:
fill_dungeons(world) fill_dungeons(world)

View File

@ -12,6 +12,7 @@ import inspect
import weakref import weakref
import datetime import datetime
import threading import threading
import random
import ModuleUpdate import ModuleUpdate
@ -830,7 +831,6 @@ class ClientMessageProcessor(CommonCommandProcessor):
can_pay = points_available // self.ctx.hint_cost can_pay = points_available // self.ctx.hint_cost
else: else:
can_pay = 1000 can_pay = 1000
import random
random.shuffle(not_found_hints) random.shuffle(not_found_hints)

View File

@ -56,6 +56,9 @@ def main(args=None):
seed = get_seed(args.seed) seed = get_seed(args.seed)
random.seed(seed) random.seed(seed)
if args.race:
random.seed() # reset to time-based random source
seedname = "M" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) seedname = "M" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits))
print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}") print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}")

86
Rom.py
View File

@ -236,8 +236,9 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
'BeesLevel': 0, 'BeesLevel': 0,
'RandomizeTileTrapPattern': world.enemy_shuffle[player] == 'chaos', 'RandomizeTileTrapPattern': world.enemy_shuffle[player] == 'chaos',
'RandomizeTileTrapFloorTile': False, 'RandomizeTileTrapFloorTile': False,
'AllowKillableThief': bool(random.randint(0, 1)) if 'thieves' in world.enemy_shuffle[player] else 'AllowKillableThief': bool(world.random.randint(0, 1)) if 'thieves' in world.enemy_shuffle[player] else
world.enemy_shuffle[player] != 'none', world.enemy_shuffle[player] != 'none',
# TODO: this is currently non-deterministic due to being called in a thread
'RandomizeSpriteOnHit': random_sprite_on_hit, 'RandomizeSpriteOnHit': random_sprite_on_hit,
'DebugMode': False, 'DebugMode': False,
'DebugForceEnemy': False, 'DebugForceEnemy': False,
@ -289,7 +290,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite
if sprites: if sprites:
while len(sprites) < 32: while len(sprites) < 32:
sprites.extend(sprites) sprites.extend(sprites)
random.shuffle(sprites) world.random.shuffle(sprites)
for i, path in enumerate(sprites[:32]): for i, path in enumerate(sprites[:32]):
sprite = Sprite(path) sprite = Sprite(path)
@ -1606,9 +1607,9 @@ def write_strings(rom, world, player, team):
if world.hints[player]: if world.hints[player]:
tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!' tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!'
hint_locations = HintLocations.copy() hint_locations = HintLocations.copy()
random.shuffle(hint_locations) world.random.shuffle(hint_locations)
all_entrances = [entrance for entrance in world.get_entrances() if entrance.player == player] all_entrances = [entrance for entrance in world.get_entrances() if entrance.player == player]
random.shuffle(all_entrances) world.random.shuffle(all_entrances)
#First we take care of the one inconvenient dungeon in the appropriately simple shuffles. #First we take care of the one inconvenient dungeon in the appropriately simple shuffles.
entrances_to_hint = {} entrances_to_hint = {}
@ -1683,12 +1684,12 @@ def write_strings(rom, world, player, team):
locations_to_hint = InconvenientLocations.copy() locations_to_hint = InconvenientLocations.copy()
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
locations_to_hint.extend(InconvenientVanillaLocations) locations_to_hint.extend(InconvenientVanillaLocations)
random.shuffle(locations_to_hint) world.random.shuffle(locations_to_hint)
hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 5 hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 5
del locations_to_hint[hint_count:] del locations_to_hint[hint_count:]
for location in locations_to_hint: for location in locations_to_hint:
if location == 'Swamp Left': if location == 'Swamp Left':
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
first_item = hint_text(world.get_location('Swamp Palace - West Chest', player).item) 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) second_item = hint_text(world.get_location('Swamp Palace - Big Key Chest', player).item)
else: else:
@ -1697,7 +1698,7 @@ def write_strings(rom, world, player, team):
this_hint = ('The westmost chests in Swamp Palace contain ' + first_item + ' and ' + second_item + '.') this_hint = ('The westmost chests in Swamp Palace contain ' + first_item + ' and ' + second_item + '.')
tt[hint_locations.pop(0)] = this_hint tt[hint_locations.pop(0)] = this_hint
elif location == 'Mire Left': elif location == 'Mire Left':
if random.randint(0, 1) == 0: if world.random.randint(0, 1) == 0:
first_item = hint_text(world.get_location('Misery Mire - Compass Chest', player).item) 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) second_item = hint_text(world.get_location('Misery Mire - Big Key Chest', player).item)
else: else:
@ -1736,12 +1737,12 @@ def write_strings(rom, world, player, team):
items_to_hint.extend(SmallKeys) items_to_hint.extend(SmallKeys)
if world.bigkeyshuffle[player]: if world.bigkeyshuffle[player]:
items_to_hint.extend(BigKeys) items_to_hint.extend(BigKeys)
random.shuffle(items_to_hint) world.random.shuffle(items_to_hint)
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8 hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8
while hint_count > 0: while hint_count > 0:
this_item = items_to_hint.pop(0) this_item = items_to_hint.pop(0)
this_location = world.find_items(this_item, player) this_location = world.find_items(this_item, player)
random.shuffle(this_location) world.random.shuffle(this_location)
#This looks dumb but prevents hints for Skull Woods Pinball Room's key safely with any item pool. #This looks dumb but prevents hints for Skull Woods Pinball Room's key safely with any item pool.
if this_location: if this_location:
if this_location[0].name == 'Skull Woods - Pinball Room': if this_location[0].name == 'Skull Woods - Pinball Room':
@ -1753,7 +1754,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. # 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() junk_hints = junk_texts.copy()
random.shuffle(junk_hints) world.random.shuffle(junk_hints)
for location in hint_locations: for location in hint_locations:
tt[location] = junk_hints.pop(0) tt[location] = junk_hints.pop(0)
@ -1761,7 +1762,7 @@ def write_strings(rom, world, player, team):
silverarrows = world.find_items('Silver Bow', player) silverarrows = world.find_items('Silver Bow', player)
random.shuffle(silverarrows) world.random.shuffle(silverarrows)
silverarrow_hint = (' %s?' % hint_text(silverarrows[0]).replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!' 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'] = '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 tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
@ -1775,7 +1776,8 @@ def write_strings(rom, world, player, team):
tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint
if any(prog_bow_locs): if any(prog_bow_locs):
silverarrow_hint = (' %s?' % hint_text(random.choice(prog_bow_locs)).replace('Ganon\'s', 'my')) if progressive_silvers else '?\nI think not!' silverarrow_hint = (' %s?' % hint_text(world.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 tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
@ -1786,19 +1788,23 @@ def write_strings(rom, world, player, team):
greenpendant = world.find_items('Green Pendant', player)[0] greenpendant = world.find_items('Green Pendant', player)[0]
tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant.hint_text tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant.hint_text
tt['sign_ganons_tower'] = ('You need %d crystal to enter.' if world.crystals_needed_for_gt[player] == 1 else 'You need %d crystals to enter.') % world.crystals_needed_for_gt[player] tt['sign_ganons_tower'] = ('You need %d crystal to enter.' if world.crystals_needed_for_gt[
tt['sign_ganon'] = ('You need %d crystal to beat Ganon.' if world.crystals_needed_for_ganon[player] == 1 else 'You need %d crystals to beat Ganon.') % world.crystals_needed_for_ganon[player] player] == 1 else 'You need %d crystals to enter.') % \
world.crystals_needed_for_gt[player]
tt['sign_ganon'] = ('You need %d crystal to beat Ganon.' if world.crystals_needed_for_ganon[
player] == 1 else 'You need %d crystals to beat Ganon.') % \
world.crystals_needed_for_ganon[player]
if world.goal[player] in ['dungeons']: if world.goal[player] in ['dungeons']:
tt['sign_ganon'] = 'You need to complete all the dungeons.' tt['sign_ganon'] = 'You need to complete all the dungeons.'
tt['uncle_leaving_text'] = Uncle_texts[random.randint(0, len(Uncle_texts) - 1)] tt['uncle_leaving_text'] = Uncle_texts[world.random.randint(0, len(Uncle_texts) - 1)]
tt['end_triforce'] = "{NOBORDER}\n" + Triforce_texts[random.randint(0, len(Triforce_texts) - 1)] tt['end_triforce'] = "{NOBORDER}\n" + Triforce_texts[world.random.randint(0, len(Triforce_texts) - 1)]
tt['bomb_shop_big_bomb'] = BombShop2_texts[random.randint(0, len(BombShop2_texts) - 1)] tt['bomb_shop_big_bomb'] = BombShop2_texts[world.random.randint(0, len(BombShop2_texts) - 1)]
# this is what shows after getting the green pendant item in rando # this is what shows after getting the green pendant item in rando
tt['sahasrahla_quest_have_master_sword'] = Sahasrahla2_texts[random.randint(0, len(Sahasrahla2_texts) - 1)] tt['sahasrahla_quest_have_master_sword'] = Sahasrahla2_texts[world.random.randint(0, len(Sahasrahla2_texts) - 1)]
tt['blind_by_the_light'] = Blind_texts[random.randint(0, len(Blind_texts) - 1)] tt['blind_by_the_light'] = Blind_texts[world.random.randint(0, len(Blind_texts) - 1)]
if world.goal[player] in ['triforcehunt', 'localtriforcehunt']: 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.' tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.'
@ -1807,14 +1813,15 @@ def write_strings(rom, world, player, team):
tt['sign_ganon'] = 'Go find the Triforce pieces with your friends... Ganon is invincible!' tt['sign_ganon'] = 'Go find the Triforce pieces with your friends... Ganon is invincible!'
else: else:
tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!'
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % \ tt[
'murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % \
world.treasure_hunt_count[player] world.treasure_hunt_count[player]
elif world.goal[player] in ['pedestal']: elif world.goal[player] in ['pedestal']:
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.' tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.'
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' 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!' tt['sign_ganon'] = 'You need to get to the pedestal... Ganon is invincible!'
else: else:
tt['ganon_fall_in'] = Ganon1_texts[random.randint(0, len(Ganon1_texts) - 1)] tt['ganon_fall_in'] = Ganon1_texts[world.random.randint(0, len(Ganon1_texts) - 1)]
tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!' 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!' tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!'
if world.goal[player] == 'ganontriforcehunt' and world.players > 1: if world.goal[player] == 'ganontriforcehunt' and world.players > 1:
@ -1822,7 +1829,7 @@ def write_strings(rom, world, player, team):
elif world.goal[player] in ['ganontriforcehunt', 'localganontriforcehunt']: 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['sign_ganon'] = 'You need to find %d Triforce pieces to defeat Ganon.' % world.treasure_hunt_count[player]
tt['kakariko_tavern_fisherman'] = TavernMan_texts[random.randint(0, len(TavernMan_texts) - 1)] tt['kakariko_tavern_fisherman'] = TavernMan_texts[world.random.randint(0, len(TavernMan_texts) - 1)]
pedestalitem = world.get_location('Master Sword Pedestal', player).item 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' 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'
@ -1853,33 +1860,38 @@ def write_strings(rom, world, player, team):
credits = Credits() credits = Credits()
sickkiditem = world.get_location('Sick Kid', player).item sickkiditem = world.get_location('Sick Kid', player).item
sickkiditem_text = random.choice(SickKid_texts) if sickkiditem is None or sickkiditem.sickkid_credit_text is None else sickkiditem.sickkid_credit_text sickkiditem_text = world.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 = world.get_location('King Zora', player).item
zoraitem_text = random.choice(Zora_texts) if zoraitem is None or zoraitem.zora_credit_text is None else zoraitem.zora_credit_text zoraitem_text = world.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 = world.get_location('Potion Shop', player).item
magicshopitem_text = random.choice(MagicShop_texts) if magicshopitem is None or magicshopitem.magicshop_credit_text is None else magicshopitem.magicshop_credit_text magicshopitem_text = world.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 = world.get_location('Flute Spot', player).item
fluteboyitem_text = random.choice(FluteBoy_texts) if fluteboyitem is None or fluteboyitem.fluteboy_credit_text is None else fluteboyitem.fluteboy_credit_text fluteboyitem_text = world.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, random.choice(KingsReturn_texts)) credits.update_credits_line('castle', 0, world.random.choice(KingsReturn_texts))
credits.update_credits_line('sanctuary', 0, random.choice(Sanctuary_texts)) credits.update_credits_line('sanctuary', 0, world.random.choice(Sanctuary_texts))
credits.update_credits_line('kakariko', 0, random.choice(Kakariko_texts).format(random.choice(Sahasrahla_names))) credits.update_credits_line('kakariko', 0,
credits.update_credits_line('desert', 0, random.choice(DesertPalace_texts)) world.random.choice(Kakariko_texts).format(world.random.choice(Sahasrahla_names)))
credits.update_credits_line('hera', 0, random.choice(MountainTower_texts)) credits.update_credits_line('desert', 0, world.random.choice(DesertPalace_texts))
credits.update_credits_line('house', 0, random.choice(LinksHouse_texts)) credits.update_credits_line('hera', 0, world.random.choice(MountainTower_texts))
credits.update_credits_line('house', 0, world.random.choice(LinksHouse_texts))
credits.update_credits_line('zora', 0, zoraitem_text) credits.update_credits_line('zora', 0, zoraitem_text)
credits.update_credits_line('witch', 0, magicshopitem_text) credits.update_credits_line('witch', 0, magicshopitem_text)
credits.update_credits_line('lumberjacks', 0, random.choice(Lumberjacks_texts)) credits.update_credits_line('lumberjacks', 0, world.random.choice(Lumberjacks_texts))
credits.update_credits_line('grove', 0, fluteboyitem_text) credits.update_credits_line('grove', 0, fluteboyitem_text)
credits.update_credits_line('well', 0, random.choice(WishingWell_texts)) credits.update_credits_line('well', 0, world.random.choice(WishingWell_texts))
credits.update_credits_line('smithy', 0, random.choice(Blacksmiths_texts)) credits.update_credits_line('smithy', 0, world.random.choice(Blacksmiths_texts))
credits.update_credits_line('kakariko2', 0, sickkiditem_text) credits.update_credits_line('kakariko2', 0, sickkiditem_text)
credits.update_credits_line('bridge', 0, random.choice(DeathMountain_texts)) credits.update_credits_line('bridge', 0, world.random.choice(DeathMountain_texts))
credits.update_credits_line('woods', 0, random.choice(LostWoods_texts)) credits.update_credits_line('woods', 0, world.random.choice(LostWoods_texts))
credits.update_credits_line('pedestal', 0, pedestal_credit_text) credits.update_credits_line('pedestal', 0, pedestal_credit_text)
(pointers, data) = credits.get_bytes() (pointers, data) = credits.get_bytes()