Retro break up of various options
This commit is contained in:
@@ -22,7 +22,7 @@ from source.dungeon.RoomObject import RoomObject
|
||||
class World(object):
|
||||
|
||||
def __init__(self, players, shuffle, doorShuffle, logic, mode, swords, difficulty, difficulty_adjustments,
|
||||
timer, progressive, goal, algorithm, accessibility, shuffle_ganon, retro, custom, customitemarray, hints):
|
||||
timer, progressive, goal, algorithm, accessibility, shuffle_ganon, custom, customitemarray, hints):
|
||||
self.players = players
|
||||
self.teams = 1
|
||||
self.shuffle = shuffle.copy()
|
||||
@@ -64,7 +64,6 @@ class World(object):
|
||||
self.fix_trock_exit = {}
|
||||
self.shuffle_ganon = shuffle_ganon
|
||||
self.fix_gtower_exit = self.shuffle_ganon
|
||||
self.retro = retro.copy()
|
||||
self.custom = custom
|
||||
self.customitemarray = customitemarray
|
||||
self.can_take_damage = True
|
||||
@@ -91,10 +90,6 @@ class World(object):
|
||||
self.pot_contents = {}
|
||||
|
||||
for player in range(1, players + 1):
|
||||
# If World State is Retro, set to Open and set Retro flag
|
||||
if self.mode[player] == "retro":
|
||||
self.mode[player] = "open"
|
||||
self.retro[player] = True
|
||||
def set_player_attr(attr, val):
|
||||
self.__dict__.setdefault(attr, {})[player] = val
|
||||
set_player_attr('_region_cache', {})
|
||||
@@ -118,10 +113,12 @@ class World(object):
|
||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'nologic'] or shuffle[player] in ['crossed', 'insanity'])
|
||||
set_player_attr('mapshuffle', False)
|
||||
set_player_attr('compassshuffle', False)
|
||||
set_player_attr('keyshuffle', False)
|
||||
set_player_attr('keyshuffle', 'standard')
|
||||
set_player_attr('bigkeyshuffle', False)
|
||||
set_player_attr('restrict_boss_items', 'none')
|
||||
set_player_attr('bombbag', False)
|
||||
set_player_attr('flute_mode', False)
|
||||
set_player_attr('bow_mode', False)
|
||||
set_player_attr('difficulty_requirements', None)
|
||||
set_player_attr('boss_shuffle', 'none')
|
||||
set_player_attr('enemy_shuffle', 'none')
|
||||
@@ -134,6 +131,7 @@ class World(object):
|
||||
set_player_attr('crystals_ganon_orig', {})
|
||||
set_player_attr('crystals_gt_orig', {})
|
||||
set_player_attr('open_pyramid', False)
|
||||
set_player_attr('take_any', 'none')
|
||||
set_player_attr('treasure_hunt_icon', 'Triforce Piece')
|
||||
set_player_attr('treasure_hunt_count', 0)
|
||||
set_player_attr('treasure_hunt_total', 0)
|
||||
@@ -154,6 +152,11 @@ class World(object):
|
||||
set_player_attr('exp_cache', defaultdict(dict))
|
||||
set_player_attr('enabled_entrances', {})
|
||||
|
||||
def finish_init(self):
|
||||
for player in range(1, self.players + 1):
|
||||
if self.mode[player] == 'retro':
|
||||
self.mode[player] == 'open'
|
||||
|
||||
def get_name_string_for_object(self, obj):
|
||||
return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})'
|
||||
|
||||
@@ -375,7 +378,8 @@ class World(object):
|
||||
|
||||
def push_precollected(self, item):
|
||||
item.world = self
|
||||
if (item.smallkey and self.keyshuffle[item.player]) or (item.bigkey and self.bigkeyshuffle[item.player]):
|
||||
if ((item.smallkey and self.keyshuffle[item.player] != 'none')
|
||||
or (item.bigkey and self.bigkeyshuffle[item.player])):
|
||||
item.advancement = True
|
||||
self.precollected_items.append(item)
|
||||
self.state.collect(item, True)
|
||||
@@ -587,7 +591,7 @@ class CollectionState(object):
|
||||
if key_logic.sm_doors[door]:
|
||||
self.reached_doors[player].add(key_logic.sm_doors[door].name)
|
||||
if not connection.can_reach(self):
|
||||
checklist_key = 'Universal' if self.world.retro[player] else dungeon_name
|
||||
checklist_key = 'Universal' if self.world.keyshuffle[player] == 'universal' else dungeon_name
|
||||
checklist = self.dungeons_to_check[player][checklist_key]
|
||||
checklist[connection.name] = (connection, crystal_state)
|
||||
elif door.name not in self.opened_doors[player]:
|
||||
@@ -759,7 +763,7 @@ class CollectionState(object):
|
||||
return None
|
||||
|
||||
def set_dungeon_limits(self, player, dungeon_name):
|
||||
if self.world.retro[player] and self.world.mode[player] == 'standard':
|
||||
if self.world.keyshuffle[player] == 'universal' and self.world.mode[player] == 'standard':
|
||||
self.dungeon_limits = ['Hyrule Castle', 'Agahnims Tower']
|
||||
else:
|
||||
self.dungeon_limits = [dungeon_name]
|
||||
@@ -935,7 +939,7 @@ class CollectionState(object):
|
||||
checked_locations = 0
|
||||
while new_locations:
|
||||
reachable_events = [location for location in locations if location.event and
|
||||
(not key_only or (not self.world.keyshuffle[location.item.player] and location.item.smallkey) or (not self.world.bigkeyshuffle[location.item.player] and location.item.bigkey))
|
||||
(not key_only or (self.world.keyshuffle[location.item.player] == 'none' and location.item.smallkey) or (not self.world.bigkeyshuffle[location.item.player] and location.item.bigkey))
|
||||
and location.can_reach(self)]
|
||||
reachable_events = self._do_not_flood_the_keys(reachable_events)
|
||||
for event in reachable_events:
|
||||
@@ -995,7 +999,7 @@ class CollectionState(object):
|
||||
return self.prog_items[item, player] >= count
|
||||
|
||||
def has_sm_key(self, item, player, count=1):
|
||||
if self.world.retro[player]:
|
||||
if self.world.keyshuffle[player] == 'universal':
|
||||
if self.world.mode[player] == 'standard' and self.world.doorShuffle[player] == 'vanilla' and item == 'Small Key (Escape)':
|
||||
return True # Cannot access the shop until escape is finished. This is safe because the key is manually placed in make_custom_item_pool
|
||||
return self.can_buy_unlimited('Small Key (Universal)', player)
|
||||
@@ -1091,7 +1095,7 @@ class CollectionState(object):
|
||||
or self.has('Cane of Somaria', player))
|
||||
|
||||
def can_shoot_arrows(self, player):
|
||||
if self.world.retro[player]:
|
||||
if self.world.bow_mode[player] in ['retro', 'retro_silvers']:
|
||||
#todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe
|
||||
return self.has('Bow', player) and (self.can_buy_unlimited('Single Arrow', player) or self.has('Single Arrow', player))
|
||||
return self.has('Bow', player)
|
||||
@@ -1373,7 +1377,7 @@ class Region(object):
|
||||
return False
|
||||
|
||||
def can_fill(self, item):
|
||||
inside_dungeon_item = ((item.smallkey and not self.world.keyshuffle[item.player])
|
||||
inside_dungeon_item = ((item.smallkey and self.world.keyshuffle[item.player] == 'none')
|
||||
or (item.bigkey and not self.world.bigkeyshuffle[item.player])
|
||||
or (item.map and not self.world.mapshuffle[item.player])
|
||||
or (item.compass and not self.world.compassshuffle[item.player]))
|
||||
@@ -2239,7 +2243,7 @@ class Item(object):
|
||||
return item_dungeon
|
||||
|
||||
def is_inside_dungeon_item(self, world):
|
||||
return ((self.smallkey and not world.keyshuffle[self.player])
|
||||
return ((self.smallkey and world.keyshuffle[self.player] == 'none')
|
||||
or (self.bigkey and not world.bigkeyshuffle[self.player])
|
||||
or (self.compass and not world.compassshuffle[self.player])
|
||||
or (self.map and not world.mapshuffle[self.player]))
|
||||
@@ -2371,15 +2375,16 @@ class Spoiler(object):
|
||||
self.metadata = {'version': ERVersion,
|
||||
'logic': self.world.logic,
|
||||
'mode': self.world.mode,
|
||||
'retro': self.world.retro,
|
||||
'bombbag': self.world.bombbag,
|
||||
'weapons': self.world.swords,
|
||||
'flute_mode': self.world.flute_mode,
|
||||
'bow_mode': self.world.bow_mode,
|
||||
'goal': self.world.goal,
|
||||
'shuffle': self.world.shuffle,
|
||||
'shuffleganon': self.world.shuffle_ganon,
|
||||
'shufflelinks': self.world.shufflelinks,
|
||||
'shuffletavern': self.world.shuffletavern,
|
||||
'take_any': self.world.take_any,
|
||||
'overworld_map': self.world.overworld_map,
|
||||
'door_shuffle': self.world.doorShuffle,
|
||||
'intensity': self.world.intensity,
|
||||
@@ -2561,7 +2566,6 @@ class Spoiler(object):
|
||||
outfile.write(f'Settings Code: {self.metadata["code"][player]}\n')
|
||||
outfile.write('Logic: %s\n' % self.metadata['logic'][player])
|
||||
outfile.write('Mode: %s\n' % self.metadata['mode'][player])
|
||||
outfile.write('Retro: %s\n' % ('Yes' if self.metadata['retro'][player] else 'No'))
|
||||
outfile.write('Swords: %s\n' % self.metadata['weapons'][player])
|
||||
outfile.write('Goal: %s\n' % self.metadata['goal'][player])
|
||||
if self.metadata['goal'][player] in ['triforcehunt', 'trinity']:
|
||||
@@ -2574,6 +2578,7 @@ class Spoiler(object):
|
||||
outfile.write('Difficulty: %s\n' % self.metadata['item_pool'][player])
|
||||
outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality'][player])
|
||||
outfile.write(f"Flute Mode: {self.metadata['flute_mode'][player]}\n")
|
||||
outfile.write(f"Bow Mode: {self.metadata['bow_mode'][player]}\n")
|
||||
outfile.write(f"Shopsanity: {yn(self.metadata['shopsanity'][player])}\n")
|
||||
outfile.write(f"Bombbag: {yn(self.metadata['bombbag'][player])}\n")
|
||||
outfile.write(f"Pseudoboots: {yn(self.metadata['pseudoboots'][player])}\n")
|
||||
@@ -2583,6 +2588,8 @@ class Spoiler(object):
|
||||
outfile.write(f"Back of Tavern Shuffled: {yn(self.metadata['shuffletavern'][player])}\n")
|
||||
outfile.write(f"GT/Ganon Shuffled: {yn(self.metadata['shuffleganon'])}\n")
|
||||
outfile.write(f"Overworld Map: {self.metadata['overworld_map'][player]}\n")
|
||||
outfile.write(f"Take Any Caves: {self.metadata['take_any'][player]}\n")
|
||||
outfile.write(f"Overworld Map: {self.metadata['overworld_map'][player]}\n")
|
||||
if self.metadata['goal'][player] != 'trinity':
|
||||
outfile.write('Pyramid hole pre-opened: %s\n' % ('Yes' if self.metadata['open_pyramid'][player] else 'No'))
|
||||
outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle'][player])
|
||||
@@ -2597,7 +2604,7 @@ class Spoiler(object):
|
||||
outfile.write(f"Pot Shuffle (Legacy): {yn(self.metadata['potshuffle'][player])}\n")
|
||||
outfile.write('Map shuffle: %s\n' % ('Yes' if self.metadata['mapshuffle'][player] else 'No'))
|
||||
outfile.write('Compass shuffle: %s\n' % ('Yes' if self.metadata['compassshuffle'][player] else 'No'))
|
||||
outfile.write('Small Key shuffle: %s\n' % ('Yes' if self.metadata['keyshuffle'][player] else 'No'))
|
||||
outfile.write(f"Small Key shuffle: {self.metadata['keyshuffle'][player]}\n")
|
||||
outfile.write('Big Key shuffle: %s\n' % ('Yes' if self.metadata['bigkeyshuffle'][player] else 'No'))
|
||||
outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player])
|
||||
outfile.write('Enemy shuffle: %s\n' % self.metadata['enemy_shuffle'][player])
|
||||
@@ -2835,7 +2842,7 @@ dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3}
|
||||
er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4, "insanity": 5, 'lite': 8,
|
||||
'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6}
|
||||
|
||||
# byte 1: LLLW WSSR (logic, mode, sword, retro)
|
||||
# byte 1: LLLW WSS? (logic, mode, sword)
|
||||
logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4}
|
||||
world_mode = {"open": 0, "standard": 1, "inverted": 2}
|
||||
sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3}
|
||||
@@ -2861,7 +2868,7 @@ counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3}
|
||||
# byte 6: CCCC CPAA (crystals ganon, pyramid, access
|
||||
access_mode = {"items": 0, "locations": 1, "none": 2}
|
||||
|
||||
# byte 7: BSMC DDEE (big, small, maps, compass, door_type, enemies)
|
||||
# byte 7: B?MC DDEE (big, ?, maps, compass, door_type, enemies)
|
||||
door_type_mode = {'original': 0, 'big': 1, 'all': 2, 'chaos': 3}
|
||||
enemy_mode = {"none": 0, "shuffled": 1, "chaos": 2, "random": 2, "legacy": 3}
|
||||
|
||||
@@ -2878,15 +2885,18 @@ boss_mode = {"none": 0, "simple": 1, "full": 2, "chaos": 3, 'random': 3, 'unique
|
||||
|
||||
|
||||
# byte 10: settings_version
|
||||
# byte 11: F???, ???? (flute_mode)
|
||||
# byte 11: FBBB, TTSS (flute_mode, bow_mode, take_any, small_key_mode)
|
||||
flute_mode = {'normal': 0, 'active': 1}
|
||||
keyshuffle_mode = {'none': 0, 'wild': 1, 'universal': 2} # reserved 8 modes?
|
||||
take_any_mode = {'none': 0, 'random': 1, 'fixed': 2}
|
||||
bow_mode = {'progressive': 0, 'silvers': 1, 'retro': 2, 'retro_silver': 3}
|
||||
|
||||
# additions
|
||||
# psuedoboots does not effect code
|
||||
# sfx_shuffle and other adjust items does not effect settings code
|
||||
|
||||
# Bump this when making changes that are not backwards compatible (nearly all of them)
|
||||
settings_version = 0
|
||||
settings_version = 1
|
||||
|
||||
|
||||
class Settings(object):
|
||||
@@ -2897,7 +2907,7 @@ class Settings(object):
|
||||
(dr_mode[w.doorShuffle[p]] << 5) | er_mode[w.shuffle[p]],
|
||||
|
||||
(logic_mode[w.logic[p]] << 5) | (world_mode[w.mode[p]] << 3)
|
||||
| (sword_mode[w.swords[p]] << 1) | (1 if w.retro[p] else 0),
|
||||
| (sword_mode[w.swords[p]] << 1),
|
||||
|
||||
(goal_mode[w.goal[p]] << 5) | (diff_mode[w.difficulty[p]] << 3)
|
||||
| (func_mode[w.difficulty_adjustments[p]] << 1) | (1 if w.hints[p] else 0),
|
||||
@@ -2915,7 +2925,7 @@ class Settings(object):
|
||||
((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3)
|
||||
| (0x4 if w.open_pyramid[p] else 0) | access_mode[w.accessibility[p]],
|
||||
|
||||
(0x80 if w.bigkeyshuffle[p] else 0) | (0x40 if w.keyshuffle[p] else 0)
|
||||
(0x80 if w.bigkeyshuffle[p] else 0)
|
||||
| (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0)
|
||||
| (door_type_mode[w.door_type_mode[p]] << 2) | (enemy_mode[w.enemy_shuffle[p]]),
|
||||
|
||||
@@ -2926,14 +2936,16 @@ class Settings(object):
|
||||
|
||||
settings_version,
|
||||
|
||||
flute_mode[w.flute_mode[p]] << 7])
|
||||
(flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4
|
||||
| take_any_mode[w.take_any[p]] << 2 | keyshuffle_mode[w.keyshuffle[p]])
|
||||
])
|
||||
return base64.b64encode(code, "+-".encode()).decode()
|
||||
|
||||
@staticmethod
|
||||
def adjust_args_from_code(code, player, args):
|
||||
settings, p = base64.b64decode(code.encode(), "+-".encode()), player
|
||||
|
||||
if len(settings) < 11:
|
||||
if len(settings) < 12:
|
||||
raise Exception('Provided code is incompatible with this version')
|
||||
if settings[10] != settings_version:
|
||||
raise Exception('Provided code is incompatible with this version')
|
||||
@@ -2950,7 +2962,7 @@ class Settings(object):
|
||||
args.item_functionality[p] = r(func_mode)[(settings[2] & 0x6) >> 1]
|
||||
args.goal[p] = r(goal_mode)[(settings[2] & 0xE0) >> 5]
|
||||
args.accessibility[p] = r(access_mode)[settings[6] & 0x3]
|
||||
args.retro[p] = True if settings[1] & 0x01 else False
|
||||
# args.retro[p] = True if settings[1] & 0x01 else False
|
||||
args.hints[p] = True if settings[2] & 0x01 else False
|
||||
args.shopsanity[p] = True if settings[3] & 0x80 else False
|
||||
args.decoupledoors[p] = True if settings[3] & 0x40 else False
|
||||
@@ -2973,7 +2985,7 @@ class Settings(object):
|
||||
args.openpyramid[p] = True if settings[6] & 0x4 else False
|
||||
|
||||
args.bigkeyshuffle[p] = True if settings[7] & 0x80 else False
|
||||
args.keyshuffle[p] = True if settings[7] & 0x40 else False
|
||||
# args.keyshuffle[p] = True if settings[7] & 0x40 else False
|
||||
args.mapshuffle[p] = True if settings[7] & 0x20 else False
|
||||
args.compassshuffle[p] = True if settings[7] & 0x10 else False
|
||||
args.door_type_mode[p] = r(door_type_mode)[(settings[7] & 0xc) >> 2]
|
||||
@@ -2990,6 +3002,9 @@ class Settings(object):
|
||||
args.shufflebosses[p] = r(boss_mode)[(settings[9] & 0x07)]
|
||||
if len(settings) > 11:
|
||||
args.flute_mode[p] = r(flute_mode)[(settings[11] & 0x80) >> 7]
|
||||
args.bow_mode[p] = r(bow_mode)[(settings[11] & 0x70) >> 4]
|
||||
args.take_any[p] = r(take_any_mode)[(settings[11] & 0xC) >> 2]
|
||||
args.keyshuffle[p] = r(keyshuffle_mode)[settings[11] & 0x3]
|
||||
|
||||
|
||||
class KeyRuleType(FastEnum):
|
||||
|
||||
25
CLI.py
25
CLI.py
@@ -103,19 +103,28 @@ def parse_cli(argv, no_defaults=False):
|
||||
ret = parser.parse_args(argv)
|
||||
|
||||
if ret.keysanity:
|
||||
ret.mapshuffle, ret.compassshuffle, ret.keyshuffle, ret.bigkeyshuffle = [True] * 4
|
||||
ret.mapshuffle, ret.compassshuffle, ret.bigkeyshuffle = [True] * 3
|
||||
ret.keyshuffle = 'wild'
|
||||
|
||||
if ret.keydropshuffle:
|
||||
ret.dropshuffle = True
|
||||
ret.pottery = 'keys' if ret.pottery == 'none' else ret.pottery
|
||||
|
||||
if ret.retro or ret.mode == 'retro':
|
||||
if ret.bow_mode == 'progressive':
|
||||
ret.bow_mode = 'retro'
|
||||
elif ret.bow_mode == 'silvers':
|
||||
ret.bow_mode = 'retro_silvers'
|
||||
ret.take_any = 'random' if ret.take_any == 'none' else ret.take_any
|
||||
ret.keyshuffle = 'universal'
|
||||
|
||||
if player_num:
|
||||
defaults = copy.deepcopy(ret)
|
||||
for player in range(1, player_num + 1):
|
||||
playerargs = parse_cli(shlex.split(getattr(ret, f"p{player}")), True)
|
||||
|
||||
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality',
|
||||
'flute_mode',
|
||||
'flute_mode', 'bow_mode', 'take_any',
|
||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||
'usestartinventory', 'bombbag', 'overworld_map', 'restrict_boss_items',
|
||||
@@ -158,6 +167,7 @@ def parse_settings():
|
||||
"crystals_ganon": "7",
|
||||
"swords": "random",
|
||||
'flute_mode': 'normal',
|
||||
'bow_mode': 'progressive',
|
||||
"difficulty": "normal",
|
||||
"item_functionality": "normal",
|
||||
"timer": "none",
|
||||
@@ -175,6 +185,7 @@ def parse_settings():
|
||||
"shufflelinks": False,
|
||||
"shuffletavern": False,
|
||||
"overworld_map": "default",
|
||||
'take_any': 'none',
|
||||
"pseudoboots": False,
|
||||
|
||||
"shuffleenemies": "none",
|
||||
@@ -189,11 +200,11 @@ def parse_settings():
|
||||
'pottery': 'none',
|
||||
'colorizepots': False,
|
||||
'shufflepots': False,
|
||||
"mapshuffle": False,
|
||||
"compassshuffle": False,
|
||||
"keyshuffle": False,
|
||||
"bigkeyshuffle": False,
|
||||
"keysanity": False,
|
||||
'mapshuffle': False,
|
||||
'compassshuffle': False,
|
||||
'keyshuffle': 'none',
|
||||
'bigkeyshuffle': False,
|
||||
'keysanity': False,
|
||||
"door_shuffle": "basic",
|
||||
"intensity": 2,
|
||||
'door_type_mode': 'original',
|
||||
|
||||
@@ -470,7 +470,7 @@ def choose_portals(world, player):
|
||||
for dungeon, info in shuffled_info:
|
||||
outstanding_portals = list(dungeon_portals[dungeon])
|
||||
hc_flag = std_flag and dungeon == 'Hyrule Castle'
|
||||
rupee_bow_flag = hc_flag and world.retro[player] # rupee bow
|
||||
rupee_bow_flag = hc_flag and world.bow_mode[player].startswith('retro') # rupee bow
|
||||
if hc_flag:
|
||||
sanc = world.get_portal('Sanctuary', player)
|
||||
sanc.destination = True
|
||||
@@ -843,7 +843,7 @@ def main_dungeon_pool(dungeon_pool, world, player):
|
||||
|
||||
all_dungeon_items_cnt = len(list(y for x in world.dungeons if x.player == player for y in x.all_items))
|
||||
target_items = 34
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
target_items += 1 if world.dropshuffle[player] else 0 # the hc big key
|
||||
else:
|
||||
target_items += 29 # small keys in chests
|
||||
@@ -1248,7 +1248,7 @@ def cross_dungeon(world, player):
|
||||
assign_cross_keys(dungeon_builders, world, player)
|
||||
all_dungeon_items_cnt = len(list(y for x in world.dungeons if x.player == player for y in x.all_items))
|
||||
target_items = 34
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
target_items += 1 if world.dropshuffle[player] else 0 # the hc big key
|
||||
else:
|
||||
target_items += 29 # small keys in chests
|
||||
@@ -1336,7 +1336,7 @@ def filter_key_door_pool(pool, selected_custom):
|
||||
def assign_cross_keys(dungeon_builders, world, player):
|
||||
logging.getLogger('').info(world.fish.translate("cli", "cli", "shuffling.keydoors"))
|
||||
start = time.process_time()
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
remaining = 29
|
||||
if world.dropshuffle[player]:
|
||||
remaining += 13
|
||||
@@ -1424,7 +1424,7 @@ def assign_cross_keys(dungeon_builders, world, player):
|
||||
# Last Step: Adjust Small Key Dungeon Pool
|
||||
for name, builder in dungeon_builders.items():
|
||||
reassign_key_doors(builder, world, player)
|
||||
if not world.retro[player]:
|
||||
if world.keyshuffle[player] != 'universal':
|
||||
log_key_logic(builder.name, world.key_logic[player][builder.name])
|
||||
actual_chest_keys = max(builder.key_doors_num - builder.key_drop_cnt, 0)
|
||||
dungeon = world.get_dungeon(name, player)
|
||||
@@ -1963,7 +1963,7 @@ def shuffle_small_key_doors(door_type_pools, used_doors, start_regions_map, worl
|
||||
# time to re-assign
|
||||
reassign_key_doors(small_map, world, player)
|
||||
for dungeon_name in pool:
|
||||
if not world.retro[player]:
|
||||
if world.keyshuffle[player] != 'universal':
|
||||
builder = world.dungeon_layouts[player][dungeon_name]
|
||||
log_key_logic(builder.name, world.key_logic[player][builder.name])
|
||||
if world.doorShuffle[player] != 'basic':
|
||||
@@ -2470,7 +2470,7 @@ def reassign_big_key_doors(bk_map, world, player):
|
||||
pass # we don't have spiral stairs candidates yet that aren't already key doors
|
||||
elif d.type is DoorType.Normal:
|
||||
change_door_to_big_key(d, world, player)
|
||||
if not world.decoupledoors[player] and d.dest:
|
||||
if not world.decoupledoors[player] and d.dest and world.door_type_mode[player] != 'original':
|
||||
if d.dest.type in [DoorType.Normal]:
|
||||
dest_room = world.get_room(d.dest.roomIndex, player)
|
||||
if stateful_door(d.dest, dest_room.kind(d.dest)):
|
||||
|
||||
@@ -1355,7 +1355,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
|
||||
sanc_builder = random.choice(lw_builders)
|
||||
assign_sector(sanc, sanc_builder, candidate_sectors, global_pole)
|
||||
|
||||
bow_sectors, retro_std_flag = {}, world.retro[player] and world.mode[player] == 'standard'
|
||||
bow_sectors, retro_std_flag = {}, world.bow_mode[player].startswith('retro') and world.mode[player] == 'standard'
|
||||
free_location_sectors = {}
|
||||
crystal_switches = {}
|
||||
crystal_barriers = {}
|
||||
|
||||
@@ -5,7 +5,7 @@ from Items import ItemFactory
|
||||
|
||||
def create_dungeons(world, player):
|
||||
def make_dungeon(name, id, default_boss, dungeon_regions, big_key, small_keys, dungeon_items):
|
||||
dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.retro[player] else small_keys,
|
||||
dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.keyshuffle[player] == 'universal' else small_keys,
|
||||
dungeon_items, player, id)
|
||||
dungeon.boss = BossFactory(default_boss, player)
|
||||
for region in dungeon.regions:
|
||||
|
||||
22
Fill.py
22
Fill.py
@@ -39,7 +39,8 @@ def fill_dungeons_restrictive(world, shuffled_locations):
|
||||
|
||||
# with shuffled dungeon items they are distributed as part of the normal item pool
|
||||
for item in world.get_items():
|
||||
if (item.smallkey and world.keyshuffle[item.player]) or (item.bigkey and world.bigkeyshuffle[item.player]):
|
||||
if ((item.smallkey and world.keyshuffle[item.player] != 'none')
|
||||
or (item.bigkey and world.bigkeyshuffle[item.player])):
|
||||
item.advancement = True
|
||||
elif (item.map and world.mapshuffle[item.player]) or (item.compass and world.compassshuffle[item.player]):
|
||||
item.priority = True
|
||||
@@ -50,7 +51,7 @@ def fill_dungeons_restrictive(world, shuffled_locations):
|
||||
(bigs if i.bigkey else smalls if i.smallkey else others).append(i)
|
||||
unplaced_smalls = list(smalls)
|
||||
for i in world.itempool:
|
||||
if i.smallkey and world.keyshuffle[i.player]:
|
||||
if i.smallkey and world.keyshuffle[i.player] != 'none':
|
||||
unplaced_smalls.append(i)
|
||||
|
||||
def fill(base_state, items, key_pool):
|
||||
@@ -160,7 +161,7 @@ def valid_key_placement(item, location, key_pool, world):
|
||||
if not valid_reserved_placement(item, location, world):
|
||||
return False
|
||||
if ((not item.smallkey and not item.bigkey) or item.player != location.player
|
||||
or world.retro[item.player] or world.logic[item.player] == 'nologic'):
|
||||
or world.keyshuffle[item.player] == 'universal' or world.logic[item.player] == 'nologic'):
|
||||
return True
|
||||
dungeon = location.parent_region.dungeon
|
||||
if dungeon:
|
||||
@@ -215,7 +216,7 @@ def track_dungeon_items(item, location, world):
|
||||
|
||||
|
||||
def is_dungeon_item(item, world):
|
||||
return ((item.smallkey and not world.keyshuffle[item.player])
|
||||
return ((item.smallkey and world.keyshuffle[item.player] == 'none')
|
||||
or (item.bigkey and not world.bigkeyshuffle[item.player])
|
||||
or (item.compass and not world.compassshuffle[item.player])
|
||||
or (item.map and not world.mapshuffle[item.player]))
|
||||
@@ -419,7 +420,8 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
|
||||
|
||||
# Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots
|
||||
# todo: crossed
|
||||
progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)' and world.keyshuffle[item.player] and world.mode[item.player] == 'standard' else 0)
|
||||
progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)'
|
||||
and world.keyshuffle[item.player] != 'none' and world.mode[item.player] == 'standard' else 0)
|
||||
key_pool = [x for x in progitempool if x.smallkey]
|
||||
|
||||
# sort maps and compasses to the back -- this may not be viable in equitable & ambrosia
|
||||
@@ -498,7 +500,7 @@ def ensure_good_pots(world, write_skips=False):
|
||||
else:
|
||||
loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.player)
|
||||
# do the arrow retro check
|
||||
if world.retro[loc.item.player] and loc.item.name in {'Arrows (5)', 'Arrows (10)'}:
|
||||
if world.bow_mode[loc.item.player].startswith('retro') and loc.item.name in {'Arrows (5)', 'Arrows (10)'}:
|
||||
loc.item = ItemFactory('Rupees (5)', loc.item.player)
|
||||
# don't write out all pots to spoiler
|
||||
if write_skips:
|
||||
@@ -663,7 +665,7 @@ def balance_multiworld_progression(world):
|
||||
candidate_items = collections.defaultdict(set)
|
||||
while True:
|
||||
for location in balancing_sphere:
|
||||
if location.event and (world.keyshuffle[location.item.player] or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
||||
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
||||
balancing_state.collect(location.item, True, location)
|
||||
player = location.item.player
|
||||
if player in balancing_players and not location.locked and location.player != player:
|
||||
@@ -738,7 +740,7 @@ def balance_multiworld_progression(world):
|
||||
sphere_locations.add(location)
|
||||
|
||||
for location in sphere_locations:
|
||||
if location.event and (world.keyshuffle[location.item.player] or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
||||
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
||||
state.collect(location.item, True, location)
|
||||
checked_locations |= sphere_locations
|
||||
|
||||
@@ -812,7 +814,9 @@ def balance_money_progression(world):
|
||||
return True
|
||||
if item.name in ['Progressive Armor', 'Blue Mail', 'Red Mail']:
|
||||
return True
|
||||
if world.retro[player] and (item.name in ['Single Arrow', 'Small Key (Universal)']):
|
||||
if world.keyshuffle[player] == 'universal' and item.name == 'Small Key (Universal)':
|
||||
return True
|
||||
if world.bow_mode[player].startswith('retro') and item.name == 'Single Arrow':
|
||||
return True
|
||||
if location.name in pay_for_locations:
|
||||
return True
|
||||
|
||||
@@ -73,7 +73,7 @@ class InitialSram:
|
||||
if startingstate.has('Bow', player):
|
||||
equip[0x340] = 3 if startingstate.has('Silver Arrows', player) else 1
|
||||
equip[0x38E] |= 0x20 # progressive flag to get the correct hint in all cases
|
||||
if not world.retro[player]:
|
||||
if not world.bow_mode[player].startswith('retro'):
|
||||
equip[0x38E] |= 0x80
|
||||
if startingstate.has('Silver Arrows', player):
|
||||
equip[0x38E] |= 0x40
|
||||
@@ -188,7 +188,7 @@ class InitialSram:
|
||||
elif item.name in bombs:
|
||||
starting_bombs += bombs[item.name]
|
||||
elif item.name in arrows:
|
||||
if world.retro[player]:
|
||||
if world.bow_mode[player].startswith('retro'):
|
||||
equip[0x38E] |= 0x80
|
||||
starting_arrows = 1
|
||||
else:
|
||||
|
||||
179
ItemList.py
179
ItemList.py
@@ -264,10 +264,10 @@ def generate_itempool(world, player):
|
||||
(pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = make_customizer_pool(world, player)
|
||||
skip_pool_adjustments = True
|
||||
elif world.custom:
|
||||
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bombbag[player], world.customitemarray)
|
||||
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world, player, world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.bombbag[player], world.customitemarray)
|
||||
world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999)
|
||||
else:
|
||||
(pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bombbag[player], world.doorShuffle[player], world.logic[player], world.flute_mode[player] == 'active')
|
||||
(pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world, player, world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.bombbag[player], world.doorShuffle[player], world.logic[player], world.flute_mode[player] == 'active')
|
||||
|
||||
if player in world.pool_adjustment.keys() and not skip_pool_adjustments:
|
||||
amt = world.pool_adjustment[player]
|
||||
@@ -295,7 +295,8 @@ def generate_itempool(world, player):
|
||||
if not found_sword and world.swords[player] != 'swordless':
|
||||
found_sword = True
|
||||
possible_weapons.append(item)
|
||||
if item in ['Progressive Bow', 'Bow'] and not found_bow and not world.retro[player]:
|
||||
if (item in ['Progressive Bow', 'Bow'] and not found_bow
|
||||
and not world.bow_mode[player].startswith('retro')):
|
||||
found_bow = True
|
||||
possible_weapons.append(item)
|
||||
if item in ['Hammer', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']:
|
||||
@@ -349,7 +350,7 @@ def generate_itempool(world, player):
|
||||
world.treasure_hunt_icon[player] = 'Triforce Piece'
|
||||
|
||||
world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player
|
||||
and ((item.smallkey and world.keyshuffle[player])
|
||||
and ((item.smallkey and world.keyshuffle[player] != 'none')
|
||||
or (item.bigkey and world.bigkeyshuffle[player])
|
||||
or (item.map and world.mapshuffle[player])
|
||||
or (item.compass and world.compassshuffle[player]))])
|
||||
@@ -409,8 +410,9 @@ def generate_itempool(world, player):
|
||||
|
||||
set_up_shops(world, player)
|
||||
|
||||
if world.retro[player]:
|
||||
if world.take_any[player] != 'none':
|
||||
set_up_take_anys(world, player, skip_pool_adjustments)
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
if world.dropshuffle[player] and not skip_pool_adjustments:
|
||||
world.itempool += [ItemFactory('Small Key (Universal)', player)] * 13
|
||||
if world.pottery[player] not in ['none', 'cave'] and not skip_pool_adjustments:
|
||||
@@ -432,6 +434,10 @@ take_any_locations = [
|
||||
'Palace of Darkness Hint', 'East Dark World Hint', 'Archery Game', 'Dark Lake Hylia Ledge Hint',
|
||||
'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint']
|
||||
|
||||
fixed_take_anys = [
|
||||
'Desert Healer Fairy', 'Swamp Healer Fairy', 'Dark Death Mountain Healer Fairy',
|
||||
'Dark Lake Hylia Ledge Healer Fairy', 'Bonk Fairy (Dark)']
|
||||
|
||||
|
||||
def set_up_take_anys(world, player, skip_adjustments=False):
|
||||
if world.mode[player] == 'inverted':
|
||||
@@ -440,9 +446,12 @@ def set_up_take_anys(world, player, skip_adjustments=False):
|
||||
if 'Archery Game' in take_any_locations:
|
||||
take_any_locations.remove('Archery Game')
|
||||
|
||||
take_any_candidates = [x for x in take_any_locations if len(world.get_region(x, player).locations) == 0]
|
||||
|
||||
regions = random.sample(take_any_candidates, 5)
|
||||
if world.take_any[player] == 'random':
|
||||
take_any_candidates = [x for x in take_any_locations if len(world.get_region(x, player).locations) == 0]
|
||||
regions = random.sample(take_any_candidates, 5)
|
||||
elif world.take_any[player] == 'fixed':
|
||||
regions = list(fixed_take_anys)
|
||||
random.shuffle(regions)
|
||||
|
||||
old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave, 'the sword cave', player)
|
||||
world.regions.append(old_man_take_any)
|
||||
@@ -539,38 +548,47 @@ def fill_prizes(world, attempts=15):
|
||||
|
||||
|
||||
def set_up_shops(world, player):
|
||||
if world.retro[player]:
|
||||
retro_bow = world.bow_mode[player].startswith('retro')
|
||||
universal_keys = world.keyshuffle[player] == 'universal'
|
||||
if retro_bow or universal_keys:
|
||||
if world.shopsanity[player]:
|
||||
removals = [next(item for item in world.itempool if item.name == 'Arrows (10)' and item.player == player)]
|
||||
red_pots = [item for item in world.itempool if item.name == 'Red Potion' and item.player == player][:5]
|
||||
shields_n_hearts = [item for item in world.itempool if item.name in ['Blue Shield', 'Small Heart'] and item.player == player]
|
||||
removals.extend([item for item in world.itempool if item.name == 'Arrow Upgrade (+5)' and item.player == player])
|
||||
removals.extend(red_pots)
|
||||
removals.extend(random.sample(shields_n_hearts, 5))
|
||||
removals = []
|
||||
if retro_bow:
|
||||
removals = [next(item for item in world.itempool if item.name == 'Arrows (10)' and item.player == player)]
|
||||
removals.extend([item for item in world.itempool if item.name == 'Arrow Upgrade (+5)' and item.player == player])
|
||||
shields_n_hearts = [item for item in world.itempool if item.name in ['Blue Shield', 'Small Heart'] and item.player == player]
|
||||
removals.extend(random.sample(shields_n_hearts, 5))
|
||||
if universal_keys:
|
||||
red_pots = [item for item in world.itempool if item.name == 'Red Potion' and item.player == player][:5]
|
||||
removals.extend(red_pots)
|
||||
for remove in removals:
|
||||
world.itempool.remove(remove)
|
||||
for i in range(6): # replace the Arrows (10) and randomly selected hearts/blue shield
|
||||
arrow_item = ItemFactory('Single Arrow', player)
|
||||
arrow_item.advancement = True
|
||||
world.itempool.append(arrow_item)
|
||||
for i in range(5): # replace the red potions
|
||||
world.itempool.append(ItemFactory('Small Key (Universal)', player))
|
||||
world.itempool.append(ItemFactory('Rupees (50)', player)) # replaces the arrow upgrade
|
||||
if retro_bow:
|
||||
for i in range(6): # replace the Arrows (10) and randomly selected hearts/blue shield
|
||||
arrow_item = ItemFactory('Single Arrow', player)
|
||||
arrow_item.advancement = True
|
||||
world.itempool.append(arrow_item)
|
||||
world.itempool.append(ItemFactory('Rupees (50)', player)) # replaces the arrow upgrade
|
||||
if universal_keys:
|
||||
for i in range(5): # replace the red potions
|
||||
world.itempool.append(ItemFactory('Small Key (Universal)', player))
|
||||
# TODO: move hard+ mode changes for shields here, utilizing the new shops
|
||||
else:
|
||||
rss = world.get_region('Red Shield Shop', player).shop
|
||||
if not rss.locked:
|
||||
rss.custom = True
|
||||
rss.add_inventory(2, 'Single Arrow', 80)
|
||||
if retro_bow:
|
||||
rss = world.get_region('Red Shield Shop', player).shop
|
||||
if not rss.locked:
|
||||
rss.custom = True
|
||||
rss.add_inventory(2, 'Single Arrow', 80)
|
||||
rss.locked = True
|
||||
cap_shop = world.get_region('Capacity Upgrade', player).shop
|
||||
cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro
|
||||
for shop in random.sample([s for s in world.shops[player] if not s.locked and s.region.player == player], 5):
|
||||
shop.custom = True
|
||||
shop.locked = True
|
||||
shop.add_inventory(0, 'Single Arrow', 80)
|
||||
shop.add_inventory(1, 'Small Key (Universal)', 100)
|
||||
shop.add_inventory(2, 'Bombs (10)', 50)
|
||||
rss.locked = True
|
||||
cap_shop = world.get_region('Capacity Upgrade', player).shop
|
||||
cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro
|
||||
if retro_bow:
|
||||
shop.add_inventory(0, 'Single Arrow', 80)
|
||||
if universal_keys:
|
||||
shop.add_inventory(1, 'Small Key (Universal)', 100)
|
||||
if world.bombbag[player]:
|
||||
if world.shopsanity[player]:
|
||||
removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player]
|
||||
@@ -583,10 +601,11 @@ def set_up_shops(world, player):
|
||||
|
||||
|
||||
def customize_shops(world, player):
|
||||
found_bomb_upgrade, found_arrow_upgrade = False, world.retro[player]
|
||||
retro_bow = world.bow_mode[player].startswith('retro')
|
||||
found_bomb_upgrade, found_arrow_upgrade = False, retro_bow
|
||||
possible_replacements = []
|
||||
shops_to_customize = shop_to_location_table.copy()
|
||||
if world.retro[player]:
|
||||
if world.take_any[player] != 'none':
|
||||
shops_to_customize.update(retro_shops)
|
||||
for shop_name, loc_list in shops_to_customize.items():
|
||||
shop = world.get_region(shop_name, player).shop
|
||||
@@ -609,7 +628,7 @@ def customize_shops(world, player):
|
||||
price = 0
|
||||
else:
|
||||
price = 120 if shop_name == 'Potion Shop' and item.name == 'Red Potion' else item.price
|
||||
if world.retro[player] and item.name == 'Single Arrow':
|
||||
if retro_bow and item.name == 'Single Arrow':
|
||||
price = 80
|
||||
# randomize price
|
||||
shop.add_inventory(idx, item.name, randomize_price(price), max_repeat, player=item.player)
|
||||
@@ -636,7 +655,7 @@ def customize_shops(world, player):
|
||||
if not found_arrow_upgrade and len(possible_replacements) > 0:
|
||||
choices = []
|
||||
for shop, idx, loc, item in possible_replacements:
|
||||
if item.name == 'Arrows (10)' or (item.name == 'Single Arrow' and not world.retro[player]):
|
||||
if item.name == 'Arrows (10)' or (item.name == 'Single Arrow' and not retro_bow):
|
||||
choices.append((shop, idx, loc, item))
|
||||
if len(choices) > 0:
|
||||
shop, idx, loc, item = random.choice(choices)
|
||||
@@ -780,16 +799,17 @@ rupee_chart = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)'
|
||||
|
||||
|
||||
def add_pot_contents(world, player):
|
||||
retro_bow = world.bow_mode[player].startswith('retro')
|
||||
for super_tile, pot_list in vanilla_pots.items():
|
||||
for pot in pot_list:
|
||||
if pot.item not in [PotItem.Hole, PotItem.Key, PotItem.Switch]:
|
||||
if valid_pot_location(pot, world.pot_pool[player], world, player):
|
||||
item = ('Rupees (5)' if world.retro[player] and pot_items[pot.item] == 'Arrows (5)'
|
||||
item = ('Rupees (5)' if retro_bow and pot_items[pot.item] == 'Arrows (5)'
|
||||
else pot_items[pot.item])
|
||||
world.itempool.append(ItemFactory(item, player))
|
||||
|
||||
|
||||
def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bombbag,
|
||||
def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, bombbag,
|
||||
door_shuffle, logic, flute_activated):
|
||||
pool = []
|
||||
placed_items = {}
|
||||
@@ -862,7 +882,7 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
|
||||
else:
|
||||
pool.extend(diff.basicarmor)
|
||||
|
||||
if want_progressives():
|
||||
if 'silvers' not in world.bow_mode[player]:
|
||||
pool.extend(['Progressive Bow'] * 2)
|
||||
elif swords != 'swordless':
|
||||
pool.extend(diff.basicbow)
|
||||
@@ -910,13 +930,14 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
|
||||
|
||||
if goal in ['pedestal', 'trinity'] and swords != 'vanilla':
|
||||
place_item('Master Sword Pedestal', 'Triforce')
|
||||
if retro:
|
||||
pool = [item.replace('Single Arrow','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrows (10)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+5)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+10)','Rupees (5)') for item in pool]
|
||||
if world.bow_mode[player].startswith('retro'):
|
||||
pool = [item.replace('Single Arrow', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrows (10)', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+5)', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+10)', 'Rupees (5)') for item in pool]
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
pool.extend(diff.retro)
|
||||
if door_shuffle != 'vanilla': # door shuffle needs more keys for retro
|
||||
if door_shuffle != 'vanilla': # door shuffle needs more keys for universal keys
|
||||
replace = 'Rupees (20)' if difficulty == 'normal' else 'Rupees (5)'
|
||||
indices = [i for i, x in enumerate(pool) if x == replace]
|
||||
for i in range(0, min(10, len(indices))):
|
||||
@@ -932,7 +953,7 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
|
||||
return (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms)
|
||||
|
||||
|
||||
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bombbag, customitemarray):
|
||||
def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer, goal, mode, swords, bombbag, customitemarray):
|
||||
if isinstance(customitemarray,dict) and 1 in customitemarray:
|
||||
customitemarray = customitemarray[1]
|
||||
pool = []
|
||||
@@ -1014,7 +1035,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
|
||||
itemtotal = itemtotal + 1
|
||||
|
||||
if mode == 'standard':
|
||||
if retro:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
key_location = 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)')
|
||||
pool.extend(['Small Key (Universal)'] * max((customitemarray["generickeys"] - 1), 0))
|
||||
@@ -1028,7 +1049,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
|
||||
pool.extend(['Magic Mirror'] * customitemarray["mirror"])
|
||||
pool.extend(['Moon Pearl'] * customitemarray["pearl"])
|
||||
|
||||
if retro:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode
|
||||
if itemtotal < total_items_to_place:
|
||||
nothings = total_items_to_place - itemtotal
|
||||
@@ -1066,7 +1087,7 @@ def make_customizer_pool(world, player):
|
||||
pool.append(random.choice(diff.bottles))
|
||||
elif item_name.startswith('Small Key') and item_name != 'Small Key (Universal)':
|
||||
d_item = ItemFactory(item_name, player)
|
||||
if not world.keyshuffle[player]:
|
||||
if world.keyshuffle[player] == 'none':
|
||||
d_name = d_item.dungeon
|
||||
dungeon = world.get_dungeon(d_name, player)
|
||||
target_amount = max(amount, len(dungeon.small_keys))
|
||||
@@ -1121,7 +1142,7 @@ def make_customizer_pool(world, player):
|
||||
guaranteed_items = alwaysitems + ['Magic Mirror', 'Moon Pearl']
|
||||
if world.shopsanity[player]:
|
||||
guaranteed_items.extend(['Blue Potion', 'Green Potion', 'Red Potion'])
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
guaranteed_items.append('Small Key (Universal)')
|
||||
for item in guaranteed_items:
|
||||
if item not in pool:
|
||||
@@ -1199,34 +1220,34 @@ def set_default_triforce(goal, custom_goal, custom_total):
|
||||
|
||||
|
||||
# A quick test to ensure all combinations generate the correct amount of items.
|
||||
def test():
|
||||
for difficulty in ['normal', 'hard', 'expert']:
|
||||
for goal in ['ganon', 'triforcehunt', 'pedestal', 'trinity']:
|
||||
for timer in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown']:
|
||||
for mode in ['open', 'standard', 'inverted', 'retro']:
|
||||
for swords in ['random', 'assured', 'swordless', 'vanilla']:
|
||||
for progressive in ['on', 'off']:
|
||||
for shuffle in ['full']:
|
||||
for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']:
|
||||
for retro in [True, False]:
|
||||
for bombbag in [True, False]:
|
||||
for door_shuffle in ['basic', 'crossed', 'vanilla']:
|
||||
out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, bombbag, door_shuffle, logic)
|
||||
count = len(out[0]) + len(out[1])
|
||||
|
||||
correct_count = total_items_to_place
|
||||
if goal in ['pedestal', 'trinity'] and swords != 'vanilla':
|
||||
# pedestal goals generate one extra item
|
||||
correct_count += 1
|
||||
if retro:
|
||||
correct_count += 28
|
||||
try:
|
||||
assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bombbag))
|
||||
except AssertionError as e:
|
||||
print(e)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
# def test():
|
||||
# for difficulty in ['normal', 'hard', 'expert']:
|
||||
# for goal in ['ganon', 'triforcehunt', 'pedestal', 'trinity']:
|
||||
# for timer in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown']:
|
||||
# for mode in ['open', 'standard', 'inverted', 'retro']:
|
||||
# for swords in ['random', 'assured', 'swordless', 'vanilla']:
|
||||
# for progressive in ['on', 'off']:
|
||||
# for shuffle in ['full']:
|
||||
# for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']:
|
||||
# for retro in [True, False]:
|
||||
# for bombbag in [True, False]:
|
||||
# for door_shuffle in ['basic', 'crossed', 'vanilla']:
|
||||
# out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, bombbag, door_shuffle, logic)
|
||||
# count = len(out[0]) + len(out[1])
|
||||
#
|
||||
# correct_count = total_items_to_place
|
||||
# if goal in ['pedestal', 'trinity'] and swords != 'vanilla':
|
||||
# # pedestal goals generate one extra item
|
||||
# correct_count += 1
|
||||
# if retro:
|
||||
# correct_count += 28
|
||||
# try:
|
||||
# assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bombbag))
|
||||
# except AssertionError as e:
|
||||
# print(e)
|
||||
#
|
||||
# if __name__ == '__main__':
|
||||
# test()
|
||||
|
||||
|
||||
def fill_specific_items(world):
|
||||
@@ -1270,7 +1291,7 @@ def fill_specific_items(world):
|
||||
|
||||
|
||||
def is_dungeon_item(item, world, player):
|
||||
return ((item.startswith('Small Key') and not world.keyshuffle[player])
|
||||
return ((item.startswith('Small Key') and world.keyshuffle[player] == 'none')
|
||||
or (item.startswith('Big Key') and not world.bigkeyshuffle[player])
|
||||
or (item.startswith('Compass') and not world.compassshuffle[player])
|
||||
or (item.startswith('Map') and not world.mapshuffle[player]))
|
||||
|
||||
@@ -158,7 +158,7 @@ class PlacementRule(object):
|
||||
left -= rule_needed
|
||||
return False
|
||||
|
||||
def is_satisfiable(self, outside_keys, unplaced_keys, big_key_loc, prize_location, cr_count):
|
||||
def is_satisfiable(self, outside_keys, wild_keys, unplaced_keys, big_key_loc, prize_location, cr_count):
|
||||
if self.prize_relevance and prize_location:
|
||||
if self.prize_relevance == 'BigBomb':
|
||||
if prize_location.item.name not in ['Crystal 5', 'Crystal 6']:
|
||||
@@ -272,7 +272,7 @@ def analyze_dungeon(key_layout, world, player):
|
||||
key_logic.bk_chests.update(find_big_chest_locations(key_layout.all_chest_locations))
|
||||
key_logic.bk_chests.update(find_big_key_locked_locations(key_layout.all_chest_locations))
|
||||
key_logic.prize_location = dungeon_table[key_layout.sector.name].prize
|
||||
if world.retro[player] and world.mode[player] != 'standard':
|
||||
if world.keyshuffle[player] == 'universal' and world.mode[player] != 'standard':
|
||||
return
|
||||
|
||||
original_key_counter = find_counter({}, False, key_layout, False)
|
||||
@@ -923,7 +923,7 @@ def self_lock_possible(counter):
|
||||
|
||||
|
||||
def available_chest_small_keys(key_counter, world, player):
|
||||
if not world.keyshuffle[player] and not world.retro[player]:
|
||||
if world.keyshuffle[player] == 'none':
|
||||
cnt = 0
|
||||
for loc in key_counter.free_locations:
|
||||
if key_counter.big_key_opened or '- Big Chest' not in loc.name:
|
||||
@@ -934,7 +934,7 @@ def available_chest_small_keys(key_counter, world, player):
|
||||
|
||||
|
||||
def available_chest_small_keys_logic(key_counter, world, player, sm_restricted):
|
||||
if not world.keyshuffle[player] and not world.retro[player]:
|
||||
if world.keyshuffle[player] == 'none':
|
||||
cnt = 0
|
||||
for loc in key_counter.free_locations:
|
||||
if loc not in sm_restricted and (key_counter.big_key_opened or '- Big Chest' not in loc.name):
|
||||
@@ -1446,8 +1446,9 @@ def validate_bk_layout(proposal, builder, start_regions, world, player):
|
||||
|
||||
# Soft lock stuff
|
||||
def validate_key_layout(key_layout, world, player):
|
||||
# retro is all good - except for hyrule castle in standard mode
|
||||
if (world.retro[player] and (world.mode[player] != 'standard' or key_layout.sector.name != 'Hyrule Castle')) or world.logic[player] == 'nologic':
|
||||
# universal key is all good - except for hyrule castle in standard mode
|
||||
if world.logic[player] == 'nologic' or (world.keyshuffle[player] == 'universal' and
|
||||
(world.mode[player] != 'standard' or key_layout.sector.name != 'Hyrule Castle')):
|
||||
return True
|
||||
flat_proposal = key_layout.flat_prop
|
||||
state = ExplorationState(dungeon=key_layout.sector.name)
|
||||
@@ -1575,8 +1576,8 @@ def enough_small_locations(state, avail_small_loc):
|
||||
|
||||
|
||||
def determine_prize_lock(key_layout, world, player):
|
||||
if ((world.retro[player] and (world.mode[player] != 'standard' or key_layout.sector.name != 'Hyrule Castle'))
|
||||
or world.logic[player] == 'nologic'):
|
||||
if world.logic[player] == 'nologic' or (world.keyshuffle[player] == 'universal' and
|
||||
(world.mode[player] != 'standard' or key_layout.sector.name != 'Hyrule Castle')):
|
||||
return # done, doesn't matter what
|
||||
flat_proposal = key_layout.flat_prop
|
||||
state = ExplorationState(dungeon=key_layout.sector.name)
|
||||
@@ -1608,7 +1609,7 @@ def determine_prize_lock(key_layout, world, player):
|
||||
|
||||
|
||||
def cnt_avail_small_locations(free_locations, key_only, state, world, player):
|
||||
if not world.keyshuffle[player] and not world.retro[player]:
|
||||
if world.keyshuffle[player] == 'none':
|
||||
bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0
|
||||
avail_chest_keys = min(free_locations - bk_adj, state.key_locations - key_only)
|
||||
return max(0, avail_chest_keys + key_only - state.used_smalls)
|
||||
@@ -1616,7 +1617,7 @@ def cnt_avail_small_locations(free_locations, key_only, state, world, player):
|
||||
|
||||
|
||||
def cnt_avail_small_locations_by_ctr(free_locations, counter, layout, world, player):
|
||||
if not world.keyshuffle[player] and not world.retro[player]:
|
||||
if world.keyshuffle[player] == 'none':
|
||||
bk_adj = 1 if counter.big_key_opened and not layout.big_key_special else 0
|
||||
avail_chest_keys = min(free_locations - bk_adj, layout.max_chests)
|
||||
return max(0, avail_chest_keys + len(counter.key_only_locations) - counter.used_keys)
|
||||
@@ -2059,14 +2060,14 @@ def val_rule(rule, skn, allow=False, loc=None, askn=None, setCheck=None):
|
||||
|
||||
# Soft lock stuff
|
||||
def validate_key_placement(key_layout, world, player):
|
||||
if world.retro[player] or world.accessibility[player] == 'none':
|
||||
if world.keyshuffle[player] == 'universal' or world.accessibility[player] == 'none':
|
||||
return True # Can't keylock in retro. Expected if beatable only.
|
||||
max_counter = find_max_counter(key_layout)
|
||||
keys_outside = 0
|
||||
big_key_outside = False
|
||||
smallkey_name = dungeon_keys[key_layout.sector.name]
|
||||
bigkey_name = dungeon_bigs[key_layout.sector.name]
|
||||
if world.keyshuffle[player]:
|
||||
if world.keyshuffle[player] != 'none':
|
||||
keys_outside = key_layout.max_chests - sum(1 for i in max_counter.free_locations if i.item is not None and i.item.name == smallkey_name and i.item.player == player)
|
||||
if world.bigkeyshuffle[player]:
|
||||
max_counter = find_max_counter(key_layout)
|
||||
|
||||
9
Main.py
9
Main.py
@@ -75,7 +75,7 @@ def main(args, seed=None, fish=None):
|
||||
customized.adjust_args(args)
|
||||
world = World(args.multi, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords,
|
||||
args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm,
|
||||
args.accessibility, args.shuffleganon, args.retro, args.custom, args.customitemarray, args.hints)
|
||||
args.accessibility, args.shuffleganon, args.custom, args.customitemarray, args.hints)
|
||||
world.customizer = customized if customized else None
|
||||
logger = logging.getLogger('')
|
||||
if seed is None:
|
||||
@@ -96,6 +96,7 @@ def main(args, seed=None, fish=None):
|
||||
world.bigkeyshuffle = args.bigkeyshuffle.copy()
|
||||
world.bombbag = args.bombbag.copy()
|
||||
world.flute_mode = args.flute_mode.copy()
|
||||
world.bow_mode = args.bow_mode.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_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)}
|
||||
world.crystals_ganon_orig = args.crystals_ganon.copy()
|
||||
@@ -124,11 +125,13 @@ def main(args, seed=None, fish=None):
|
||||
world.shuffletavern = args.shuffletavern.copy()
|
||||
world.pseudoboots = args.pseudoboots.copy()
|
||||
world.overworld_map = args.overworld_map.copy()
|
||||
world.take_any = args.take_any.copy()
|
||||
world.restrict_boss_items = args.restrict_boss_items.copy()
|
||||
world.collection_rate = args.collection_rate.copy()
|
||||
world.colorizepots = args.colorizepots.copy()
|
||||
|
||||
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
|
||||
world.finish_init()
|
||||
|
||||
logger.info(
|
||||
world.fish.translate("cli","cli","app.title") + "\n",
|
||||
@@ -247,7 +250,7 @@ def main(args, seed=None, fish=None):
|
||||
for player in range(1, world.players + 1):
|
||||
if world.shopsanity[player]:
|
||||
sell_potions(world, player)
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
sell_keys(world, player)
|
||||
else:
|
||||
lock_shop_locations(world, player)
|
||||
@@ -425,7 +428,7 @@ def copy_world(world):
|
||||
# ToDo: Not good yet
|
||||
ret = World(world.players, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords,
|
||||
world.difficulty, world.difficulty_adjustments, world.timer, world.progressive, world.goal, world.algorithm,
|
||||
world.accessibility, world.shuffle_ganon, world.retro, world.custom, world.customitemarray, world.hints)
|
||||
world.accessibility, world.shuffle_ganon, world.custom, world.customitemarray, world.hints)
|
||||
ret.teams = world.teams
|
||||
ret.player_names = copy.deepcopy(world.player_names)
|
||||
ret.remote_items = world.remote_items.copy()
|
||||
|
||||
@@ -879,7 +879,8 @@ def shuffle_pots(world, player):
|
||||
elif old_pot.item == PotItem.Switch:
|
||||
available_pots = (pot for pot in new_pots if (pot.room == old_pot.room or pot.room in movable_switch_rooms[old_pot.room]) and not (pot.flags & PotFlags.NoSwitch))
|
||||
elif old_pot.item == PotItem.Key:
|
||||
if world.doorShuffle[player] == 'vanilla' and not world.retro[player] and world.pottery[player] == 'none' and world.logic[player] != 'nologic':
|
||||
if (world.doorShuffle[player] == 'vanilla' and world.keyshuffle[player] != 'universal'
|
||||
and world.pottery[player] == 'none' and world.logic[player] != 'nologic'):
|
||||
available_pots = (pot for pot in new_pots if pot.room not in invalid_key_rooms)
|
||||
else:
|
||||
available_pots = new_pots
|
||||
@@ -890,7 +891,7 @@ def shuffle_pots(world, player):
|
||||
|
||||
new_pot = random.choice(available_pots)
|
||||
new_pot.item = old_pot.item
|
||||
if world.retro[player] and new_pot.item == PotItem.FiveArrows:
|
||||
if world.bow_mode[player].startswith('retro') and new_pot.item == PotItem.FiveArrows:
|
||||
new_pot.item = PotItem.FiveRupees
|
||||
|
||||
if new_pot.item == PotItem.Key:
|
||||
@@ -938,7 +939,7 @@ def shuffle_pot_switches(world, player):
|
||||
|
||||
new_pot = random.choice(available_pots)
|
||||
new_pot.item, old_pot.item = old_pot.item, new_pot.item
|
||||
if world.retro[player] and new_pot.item == PotItem.FiveArrows:
|
||||
if world.bow_mode[player].startswith('retro') and new_pot.item == PotItem.FiveArrows:
|
||||
new_pot.item = PotItem.FiveRupees
|
||||
|
||||
if new_pot.item == PotItem.Switch and (new_pot.flags & PotFlags.SwitchLogicChange):
|
||||
|
||||
@@ -1029,7 +1029,7 @@ def adjust_locations(world, player):
|
||||
loc.event = False
|
||||
item_dungeon = key_item.dungeon
|
||||
dungeon = world.get_dungeon(item_dungeon, player)
|
||||
if key_item.smallkey and not world.retro[player]:
|
||||
if key_item.smallkey and world.keyshuffle[player] != 'universal':
|
||||
dungeon.small_keys.append(key_item)
|
||||
elif key_item.bigkey:
|
||||
dungeon.big_key = key_item
|
||||
|
||||
36
Rom.py
36
Rom.py
@@ -797,7 +797,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x138002, 2)
|
||||
for name, layout in world.key_layout[player].items():
|
||||
offset = compass_data[name][4]//2
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
rom.write_byte(0x13f030+offset, layout.max_chests + layout.max_drops)
|
||||
else:
|
||||
rom.write_byte(0x13f020+offset, layout.max_chests + layout.max_drops) # not currently used
|
||||
@@ -898,7 +898,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x142A50, 1) # StandingItemsOn
|
||||
multiClientFlags = ((0x1 if world.dropshuffle[player] else 0)
|
||||
| (0x2 if world.shopsanity[player] else 0)
|
||||
| (0x4 if world.retro[player] else 0)
|
||||
| (0x4 if world.take_any[player] != 'none' else 0)
|
||||
| (0x8 if world.pottery[player] != 'none' else 0)
|
||||
| (0x10 if is_mystery else 0))
|
||||
rom.write_byte(0x142A51, multiClientFlags)
|
||||
@@ -1112,7 +1112,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
prizes = [prize_replacements.get(prize, prize) for prize in prizes]
|
||||
dig_prizes = [prize_replacements.get(prize, prize) for prize in dig_prizes]
|
||||
|
||||
if world.retro[player]:
|
||||
if world.bow_mode[player].startswith('retro'):
|
||||
prize_replacements = {0xE1: 0xDA, #5 Arrows -> Blue Rupee
|
||||
0xE2: 0xDB} #10 Arrows -> Red Rupee
|
||||
prizes = [prize_replacements.get(prize, prize) for prize in prizes]
|
||||
@@ -1155,7 +1155,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
||||
0x51, 0x00 if world.bombbag[player] else 0x06, 0x31 if world.bombbag[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bombbag -> turns into Bombs (10)
|
||||
0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade
|
||||
0x58, 0x01, 0x36 if world.retro[player] else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode)
|
||||
0x58, 0x01, 0x36 if world.bow_mode[player].startswith('retro') else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode)
|
||||
0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20
|
||||
0x17, difficulty.heart_piece_limit, 0x47, 0xff, # piece of heart -> green 20
|
||||
0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel
|
||||
@@ -1204,7 +1204,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
ERtimeincrease = 10
|
||||
else:
|
||||
ERtimeincrease = 20
|
||||
if world.keyshuffle[player] or world.bigkeyshuffle[player] or world.mapshuffle[player]:
|
||||
if world.keyshuffle[player] != 'none' or world.bigkeyshuffle[player] or world.mapshuffle[player]:
|
||||
ERtimeincrease = ERtimeincrease + 15
|
||||
if world.clock_mode == 'none':
|
||||
rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode
|
||||
@@ -1337,7 +1337,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
# m - enabled for inside maps
|
||||
# c - enabled for inside compasses
|
||||
# s - enabled for inside small keys
|
||||
rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle[player] else 0x00)
|
||||
rom.write_byte(0x18016A, 0x10 | ((0x01 if world.keyshuffle[player] == 'wild' else 0x00)
|
||||
| (0x02 if world.compassshuffle[player] else 0x00)
|
||||
| (0x04 if world.mapshuffle[player] else 0x00)
|
||||
| (0x08 if world.bigkeyshuffle[player] else 0x00))) # free roaming item text boxes
|
||||
@@ -1403,7 +1403,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
# a - Small Key
|
||||
#
|
||||
enable_menu_map_check = world.overworld_map[player] != 'default' and world.shuffle[player] != 'none'
|
||||
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] else 0x00)
|
||||
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] == 'wild' else 0x00)
|
||||
| (0x02 if world.bigkeyshuffle[player] else 0x00)
|
||||
| (0x04 if world.mapshuffle[player] or enable_menu_map_check else 0x00)
|
||||
| (0x08 if world.compassshuffle[player] else 0x00))) # free roaming items in menu
|
||||
@@ -1434,17 +1434,17 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
write_int16(rom, 0x18017A, get_reveal_bytes('Green Pendant') if world.mapshuffle[player] else 0x0000) # Sahasrahla reveal
|
||||
write_int16(rom, 0x18017C, get_reveal_bytes('Crystal 5')|get_reveal_bytes('Crystal 6') if world.mapshuffle[player] else 0x0000) # Bomb Shop Reveal
|
||||
|
||||
rom.write_byte(0x180172, 0x01 if world.retro[player] else 0x00) # universal keys
|
||||
rom.write_byte(0x180175, 0x01 if world.retro[player] else 0x00) # rupee bow
|
||||
rom.write_byte(0x180176, 0x0A if world.retro[player] else 0x00) # wood arrow cost
|
||||
rom.write_byte(0x180178, 0x32 if world.retro[player] else 0x00) # silver arrow cost
|
||||
rom.write_byte(0x301FC, 0xDA if world.retro[player] else 0xE1) # rupees replace arrows under pots
|
||||
rom.write_byte(0x180172, 0x01 if world.keyshuffle[player] == 'universal' else 0x00) # universal keys
|
||||
rom.write_byte(0x180175, 0x01 if world.bow_mode[player].startswith('retro') else 0x00) # rupee bow
|
||||
rom.write_byte(0x180176, 0x0A if world.bow_mode[player].startswith('retro') else 0x00) # wood arrow cost
|
||||
rom.write_byte(0x180178, 0x32 if world.bow_mode[player].startswith('retro') else 0x00) # silver arrow cost
|
||||
rom.write_byte(0x301FC, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) # rupees replace arrows under pots
|
||||
if enemized:
|
||||
rom.write_byte(0x1B152e, 0xDA if world.retro[player] else 0xE1)
|
||||
rom.write_byte(0x30052, 0xDB if world.retro[player] else 0xE2) # replace arrows in fish prize from bottle merchant
|
||||
rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, 0x7E]) # Thief steals rupees instead of arrows
|
||||
rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, 0x7E]) # Pikit steals rupees instead of arrows
|
||||
rom.write_bytes(0xEDA5, [0x35, 0x41] if world.retro[player] else [0x43, 0x44]) # Chest game gives rupees instead of arrows
|
||||
rom.write_byte(0x1B152e, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1)
|
||||
rom.write_byte(0x30052, 0xDB if world.bow_mode[player].startswith('retro') else 0xE2) # replace arrows in fish prize from bottle merchant
|
||||
rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Thief steals rupees instead of arrows
|
||||
rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Pikit steals rupees instead of arrows
|
||||
rom.write_bytes(0xEDA5, [0x35, 0x41] if world.bow_mode[player].startswith('retro') else [0x43, 0x44]) # Chest game gives rupees instead of arrows
|
||||
digging_game_rng = random.randint(1, 30) # set rng for digging game
|
||||
rom.write_byte(0x180020, digging_game_rng)
|
||||
rom.write_byte(0xEFD95, digging_game_rng)
|
||||
@@ -2151,7 +2151,7 @@ def write_strings(rom, world, player, team):
|
||||
# It is done the way it is to re-use the silver code and also to give one hint per each type of item regardless
|
||||
# of how many exist. This supports many settings well.
|
||||
items_to_hint = RelevantItems.copy()
|
||||
if world.keyshuffle[player]:
|
||||
if world.keyshuffle[player] == 'wild':
|
||||
items_to_hint.extend(SmallKeys)
|
||||
if world.bigkeyshuffle[player]:
|
||||
items_to_hint.extend(BigKeys)
|
||||
|
||||
2
Rules.py
2
Rules.py
@@ -2072,7 +2072,7 @@ def add_key_logic_rules(world, player):
|
||||
add_rule(big_chest, create_rule(d_logic.bk_name, player))
|
||||
if len(d_logic.bk_doors) == 0 and len(d_logic.bk_chests) <= 1:
|
||||
set_always_allow(big_chest, allow_big_key_in_big_chest(d_logic.bk_name, player))
|
||||
if world.retro[player]:
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
for d_name, layout in world.key_layout[player].items():
|
||||
for door in layout.flat_prop:
|
||||
if world.mode[player] != 'standard' or not retro_in_hc(door.entrance):
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
flute_mode:
|
||||
normal: 3
|
||||
active: 1
|
||||
bow_mode:
|
||||
progressive: 5
|
||||
silvers: 5
|
||||
retro: 1
|
||||
retro_silvers: 1
|
||||
entrance_shuffle:
|
||||
none: 15
|
||||
dungeonssimple: 3
|
||||
@@ -66,9 +71,10 @@
|
||||
open: 1
|
||||
inverted: 1
|
||||
retro: 0
|
||||
retro:
|
||||
on: 1
|
||||
off: 4
|
||||
take_any:
|
||||
random: 1
|
||||
fixed: 3
|
||||
none: 16
|
||||
goals:
|
||||
ganon: 2
|
||||
fast_ganon: 2
|
||||
@@ -86,6 +92,12 @@
|
||||
mc: 3
|
||||
mcs: 2
|
||||
full: 5
|
||||
mcu: 1 # map, compass, universal smalls
|
||||
# for use when you aren't using the dungeon_items above
|
||||
# smallkey_shuffle:
|
||||
# standard: 5
|
||||
# wild: 1
|
||||
# universal: 1
|
||||
dungeon_counters:
|
||||
on: 5
|
||||
off: 0
|
||||
|
||||
@@ -50,7 +50,6 @@ world_state:
|
||||
standard: 1
|
||||
open: 1
|
||||
inverted: 1
|
||||
retro: 0
|
||||
retro:
|
||||
on: 1
|
||||
off: 1
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
"active"
|
||||
]
|
||||
},
|
||||
"bow_mode": {
|
||||
"choices": [
|
||||
"progressive",
|
||||
"silvers",
|
||||
"retro",
|
||||
"retro_silvers"
|
||||
]
|
||||
},
|
||||
"goal": {
|
||||
"choices": [
|
||||
"ganon",
|
||||
@@ -266,8 +274,11 @@
|
||||
"type": "bool"
|
||||
},
|
||||
"keyshuffle": {
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
"choices": [
|
||||
"none",
|
||||
"wild",
|
||||
"universal"
|
||||
]
|
||||
},
|
||||
"bigkeyshuffle": {
|
||||
"action": "store_true",
|
||||
@@ -286,6 +297,13 @@
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
},
|
||||
"take_any": {
|
||||
"choices": [
|
||||
"none",
|
||||
"random",
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
"startinventory": {},
|
||||
"usestartinventory": {
|
||||
"type": "bool"
|
||||
|
||||
@@ -122,10 +122,17 @@
|
||||
"Expert: Greatly reduced functionality."
|
||||
],
|
||||
"flute_mode": [
|
||||
"Determine if you need to wake up the bird or not on flute pickup (default: %(default)s)",
|
||||
"Determines if you need to wake up the bird or not on flute pickup (default: %(default)s)",
|
||||
"Normal: Normal functionality.",
|
||||
"Active: Flute is activated on pickup."
|
||||
],
|
||||
"bow_mode": [
|
||||
"Determines how the bow acts in the pool (default: %(default)s)",
|
||||
"Progressive: Two progressive bows placed. First picked up is the bow. Second is silvers.",
|
||||
"Silvers Separate: Bow and silvers are completely separate items.",
|
||||
"Retro: Z1 Bow where arrows cost money and the Single Arrow must be bought or found to shoot",
|
||||
"Retro + Silvers: Bow and silvers are completely separate items."
|
||||
],
|
||||
"timer": [
|
||||
"Select game timer setting. Affects available itempool. (default: %(default)s)",
|
||||
"None: No timer.",
|
||||
@@ -300,6 +307,12 @@
|
||||
"Keys are universal, shooting arrows costs rupees,",
|
||||
"and a few other little things make this more like Zelda-1. (default: %(default)s)"
|
||||
],
|
||||
"take_any": [
|
||||
"Take Any caves from Zelda 1 (default: %(default)s)",
|
||||
"None: No take any caves",
|
||||
"Random: Take any caves can replace a random set of un-interesting caves. See documentation for full list",
|
||||
"Fixed: Take any caves will replace certain location. See documentation for full list"
|
||||
],
|
||||
"pseudoboots": [ " Players starts with pseudo boots that allow dashing but no item checks (default: %(default)s"],
|
||||
"bombbag": ["Start with 0 bomb capacity. Two capacity upgrades (+10) are added to the pool (default: %(default)s)" ],
|
||||
"startinventory": [ "Specifies a list of items that will be in your starting inventory (separated by commas). (default: %(default)s)" ],
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
"randomizer.dungeon.mapshuffle": "Maps",
|
||||
"randomizer.dungeon.compassshuffle": "Compasses",
|
||||
"randomizer.dungeon.smallkeyshuffle": "Small Keys",
|
||||
"randomizer.dungeon.smallkeyshuffle.standard": "In Dungeon",
|
||||
"randomizer.dungeon.smallkeyshuffle.wild": "Randomized",
|
||||
"randomizer.dungeon.smallkeyshuffle.universal": "Universal",
|
||||
"randomizer.dungeon.bigkeyshuffle": "Big Keys",
|
||||
"randomizer.dungeon.keydropshuffle": "Key Drop Shuffle (Legacy)",
|
||||
"randomizer.dungeon.decoupledoors": "Decouple Doors",
|
||||
@@ -155,7 +158,10 @@
|
||||
"randomizer.entrance.entranceshuffle.dungeonsfull": "Dungeons + Full",
|
||||
"randomizer.entrance.entranceshuffle.dungeonssimple": "Dungeons + Simple",
|
||||
|
||||
|
||||
"randomizer.entrance.take_any": "Take Any Caves",
|
||||
"randomizer.entrance.take_any.none": "None",
|
||||
"randomizer.entrance.take_any.random": "Random",
|
||||
"randomizer.entrance.take_any.fixed": "Fixed",
|
||||
|
||||
"randomizer.gameoptions.nobgm": "Disable Music & MSU-1",
|
||||
"randomizer.gameoptions.quickswap": "L/R Quickswapping",
|
||||
@@ -219,7 +225,7 @@
|
||||
"randomizer.generation.rom.dialog.allfiles": "All Files",
|
||||
|
||||
"randomizer.item.hints": "Include Helpful Hints",
|
||||
"randomizer.item.retro": "Retro mode (universal keys)",
|
||||
"randomizer.item.retro": "Retro mode",
|
||||
"randomizer.item.pseudoboots": "Start with Pseudo Boots",
|
||||
"randomizer.item.bombbag": "Bombbag",
|
||||
|
||||
@@ -289,6 +295,12 @@
|
||||
"randomizer.item.flute_mode.normal": "Normal",
|
||||
"randomizer.item.flute_mode.active": "Pre-Activated",
|
||||
|
||||
"randomizer.item.bow_mode": "Bow Mode",
|
||||
"randomizer.item.bow_mode.progressive": "Progressive",
|
||||
"randomizer.item.bow_mode.silvers": "Silvers Separate",
|
||||
"randomizer.item.bow_mode.retro": "Retro (Progressive)",
|
||||
"randomizer.item.bow_mode.retro_silvers": "Retro + Silvers",
|
||||
|
||||
"randomizer.item.timer": "Timer Setting",
|
||||
"randomizer.item.timer.none": "No Timer",
|
||||
"randomizer.item.timer.display": "Stopwatch",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"keysanity": {
|
||||
"mapshuffle": { "type": "checkbox" },
|
||||
"compassshuffle": { "type": "checkbox" },
|
||||
"smallkeyshuffle": { "type": "checkbox" },
|
||||
"bigkeyshuffle": { "type": "checkbox" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"widgets": {
|
||||
"keyshuffle": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"standard",
|
||||
"wild",
|
||||
"universal"
|
||||
]
|
||||
},
|
||||
"dungeondoorshuffle": {
|
||||
"type": "selectbox",
|
||||
"default": "basic",
|
||||
|
||||
@@ -29,6 +29,14 @@
|
||||
"config": {
|
||||
"width": 45
|
||||
}
|
||||
},
|
||||
"take_any": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"random",
|
||||
"fixed"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,15 @@
|
||||
"active"
|
||||
]
|
||||
},
|
||||
"bow_mode": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"progressive",
|
||||
"silvers",
|
||||
"retro",
|
||||
"retro_silvers"
|
||||
]
|
||||
},
|
||||
"timer": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
|
||||
@@ -69,11 +69,13 @@ class CustomSettings(object):
|
||||
args.mode[p] = get_setting(settings['mode'], args.mode[p])
|
||||
args.swords[p] = get_setting(settings['swords'], args.swords[p])
|
||||
args.flute_mode[p] = get_setting(settings['flute_mode'], args.flute_mode[p])
|
||||
args.bow_mode[p] = get_setting(settings['bow_mode'], args.bow_mode[p])
|
||||
args.item_functionality[p] = get_setting(settings['item_functionality'], args.item_functionality[p])
|
||||
args.goal[p] = get_setting(settings['goal'], args.goal[p])
|
||||
args.difficulty[p] = get_setting(settings['difficulty'], args.difficulty[p])
|
||||
args.accessibility[p] = get_setting(settings['accessibility'], args.accessibility[p])
|
||||
args.retro[p] = get_setting(settings['retro'], args.retro[p])
|
||||
args.take_any[p] = get_setting(settings['take_any'], args.take_any[p])
|
||||
args.hints[p] = get_setting(settings['hints'], args.hints[p])
|
||||
args.shopsanity[p] = get_setting(settings['shopsanity'], args.shopsanity[p])
|
||||
args.dropshuffle[p] = get_setting(settings['dropshuffle'], args.dropshuffle[p])
|
||||
@@ -191,11 +193,12 @@ class CustomSettings(object):
|
||||
settings_dict[p]['mode'] = world.mode[p]
|
||||
settings_dict[p]['swords'] = world.swords[p]
|
||||
settings_dict[p]['flute_mode'] = world.flute_mode[p]
|
||||
settings_dict[p]['bow_mode'] = world.bow_mode[p]
|
||||
settings_dict[p]['difficulty'] = world.difficulty[p]
|
||||
settings_dict[p]['goal'] = world.goal[p]
|
||||
settings_dict[p]['accessibility'] = world.accessibility[p]
|
||||
settings_dict[p]['item_functionality'] = world.difficulty_adjustments[p]
|
||||
settings_dict[p]['retro'] = world.retro[p]
|
||||
settings_dict[p]['take_any'] = world.take_any[p]
|
||||
settings_dict[p]['hints'] = world.hints[p]
|
||||
settings_dict[p]['shopsanity'] = world.shopsanity[p]
|
||||
settings_dict[p]['dropshuffle'] = world.dropshuffle[p]
|
||||
|
||||
@@ -68,6 +68,7 @@ SETTINGSTOPROCESS = {
|
||||
"weapons": "swords",
|
||||
"itempool": "difficulty",
|
||||
"flute_mode": "flute_mode",
|
||||
"bow_mode": "bow_mode",
|
||||
"timer": "timer",
|
||||
"accessibility": "accessibility",
|
||||
"sortingalgo": "algorithm",
|
||||
@@ -81,6 +82,7 @@ SETTINGSTOPROCESS = {
|
||||
"shuffletavern": "shuffletavern",
|
||||
"entranceshuffle": "shuffle",
|
||||
"overworld_map": "overworld_map",
|
||||
"take_any": "take_any",
|
||||
},
|
||||
"enemizer": {
|
||||
"enemyshuffle": "shuffleenemies",
|
||||
|
||||
@@ -285,4 +285,12 @@ def create_guiargs(parent):
|
||||
guiargs.dropshuffle = 1
|
||||
guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery
|
||||
|
||||
if guiargs.retro or guiargs.mode == 'retro':
|
||||
if guiargs.bow_mode == 'progressive':
|
||||
guiargs.bow_mode = 'retro'
|
||||
elif guiargs.bow_mode == 'silvers':
|
||||
guiargs.bow_mode = 'retro_silvers'
|
||||
guiargs.take_any = 'random' if guiargs.take_any == 'none' else guiargs.take_any
|
||||
guiargs.keyshuffle = 'universal'
|
||||
|
||||
return guiargs
|
||||
|
||||
@@ -82,10 +82,11 @@ def create_item_pool_config(world):
|
||||
if world.shopsanity[player]:
|
||||
for item, locs in shop_vanilla_mapping.items():
|
||||
config.static_placement[player][item].extend(locs)
|
||||
if world.retro[player]:
|
||||
if world.take_any[player] != 'none':
|
||||
for item, locs in retro_vanilla_mapping.items():
|
||||
config.static_placement[player][item].extend(locs)
|
||||
# universal keys
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
universal_key_locations = []
|
||||
for item, locs in vanilla_mapping.items():
|
||||
if 'Small Key' in item:
|
||||
@@ -98,12 +99,13 @@ def create_item_pool_config(world):
|
||||
for item, locs in potkeys_vanilla_mapping.items():
|
||||
universal_key_locations.extend(locs)
|
||||
if world.shopsanity[player]:
|
||||
single_arrow_placement = list(shop_vanilla_mapping['Red Potion'])
|
||||
single_arrow_placement.append('Red Shield Shop - Right')
|
||||
config.static_placement[player]['Single Arrow'] = single_arrow_placement
|
||||
universal_key_locations.extend(shop_vanilla_mapping['Small Heart'])
|
||||
universal_key_locations.extend(shop_vanilla_mapping['Blue Shield'])
|
||||
config.static_placement[player]['Small Key (Universal)'] = universal_key_locations
|
||||
if world.bow_mode[player].startswith('retro') and world.shopsanity[player]:
|
||||
single_arrow_placement = list(shop_vanilla_mapping['Red Potion'])
|
||||
single_arrow_placement.append('Red Shield Shop - Right')
|
||||
config.static_placement[player]['Single Arrow'] = single_arrow_placement
|
||||
config.location_groups[player] = [
|
||||
LocationGroup('Major').locs(mode_grouping['Overworld Major'] + mode_grouping['Big Chests'] + mode_grouping['Heart Containers']),
|
||||
LocationGroup('bkhp').locs(mode_grouping['Heart Pieces']),
|
||||
@@ -124,7 +126,7 @@ def create_item_pool_config(world):
|
||||
groups.locations.extend(mode_grouping['Big Keys'])
|
||||
if world.dropshuffle[player] != 'none':
|
||||
groups.locations.extend(mode_grouping['Big Key Drops'])
|
||||
if world.keyshuffle[player]:
|
||||
if world.keyshuffle[player] != 'none':
|
||||
groups.locations.extend(mode_grouping['Small Keys'])
|
||||
if world.dropshuffle[player] != 'none':
|
||||
groups.locations.extend(mode_grouping['Key Drops'])
|
||||
@@ -137,7 +139,7 @@ def create_item_pool_config(world):
|
||||
if world.shopsanity[player]:
|
||||
groups.locations.append('Capacity Upgrade - Left')
|
||||
groups.locations.append('Capacity Upgrade - Right')
|
||||
if world.retro[player]:
|
||||
if world.take_any[player] != 'none':
|
||||
if world.shopsanity[player]:
|
||||
groups.locations.extend(retro_vanilla_mapping['Heart Container'])
|
||||
groups.locations.append('Old Man Sword Cave Item 1')
|
||||
@@ -249,7 +251,7 @@ def previously_reserved(location, world, player):
|
||||
if world.restrict_boss_items[player] == 'dungeon' and (not world.compassshuffle[player]
|
||||
or not world.mapshuffle[player]
|
||||
or not world.bigkeyshuffle[player]
|
||||
or not (world.keyshuffle[player] or world.retro[player])):
|
||||
or world.keyshuffle[player] == 'standard'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -335,7 +337,7 @@ def determine_major_items(world, player):
|
||||
pass # now what?
|
||||
if world.bigkeyshuffle[player]:
|
||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'BigKey'})
|
||||
if world.keyshuffle[player]:
|
||||
if world.keyshuffle[player] != 'none':
|
||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'SmallKey'})
|
||||
if world.compassshuffle[player]:
|
||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Compass'})
|
||||
@@ -344,8 +346,9 @@ def determine_major_items(world, player):
|
||||
if world.shopsanity[player]:
|
||||
major_item_set.add('Bomb Upgrade (+5)')
|
||||
major_item_set.add('Arrow Upgrade (+5)')
|
||||
if world.retro[player]:
|
||||
if world.bow_mode[player].startswith('retro'):
|
||||
major_item_set.add('Single Arrow')
|
||||
if world.keyshuffle[player] == 'universal':
|
||||
major_item_set.add('Small Key (Universal)')
|
||||
if world.goal == 'triforcehunt':
|
||||
major_item_set.add('Triforce Piece')
|
||||
|
||||
@@ -64,7 +64,13 @@ def roll_settings(weights):
|
||||
dungeon_items = 'mcsb' if dungeon_items == 'full' else dungeon_items
|
||||
ret.mapshuffle = get_choice('map_shuffle') == 'on' if 'map_shuffle' in weights else 'm' in dungeon_items
|
||||
ret.compassshuffle = get_choice('compass_shuffle') == 'on' if 'compass_shuffle' in weights else 'c' in dungeon_items
|
||||
ret.keyshuffle = get_choice('smallkey_shuffle') == 'on' if 'smallkey_shuffle' in weights else 's' in dungeon_items
|
||||
if 'smallkey_shuffle' in weights:
|
||||
ret.keyshuffle = get_choice('smallkey_shuffle')
|
||||
else:
|
||||
if 's' in dungeon_items:
|
||||
ret.keyshuffle = 'wild'
|
||||
if 'u' in dungeon_items:
|
||||
ret.keyshuffle = 'universal'
|
||||
ret.bigkeyshuffle = get_choice('bigkey_shuffle') == 'on' if 'bigkey_shuffle' in weights else 'b' in dungeon_items
|
||||
|
||||
ret.accessibility = get_choice('accessibility')
|
||||
@@ -130,6 +136,7 @@ def roll_settings(weights):
|
||||
ret.mode = 'open'
|
||||
ret.retro = True
|
||||
ret.retro = get_choice('retro') == 'on' # this overrides world_state if used
|
||||
ret.take_any = get_choice_default('take_any', default='none')
|
||||
|
||||
ret.bombbag = get_choice('bombbag') == 'on'
|
||||
|
||||
@@ -145,6 +152,7 @@ def roll_settings(weights):
|
||||
|
||||
ret.difficulty = get_choice('item_pool')
|
||||
ret.flute_mode = get_choice_default('flute_mode', default='normal')
|
||||
ret.bow_mode = get_choice_default('bow_mode', default='progressive')
|
||||
|
||||
ret.item_functionality = get_choice('item_functionality')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user