Merge remote-tracking branch 'origin/OverworldShuffle' into OverworldShuffle
This commit is contained in:
157
BaseClasses.py
157
BaseClasses.py
@@ -70,6 +70,7 @@ class World(object):
|
||||
self.customitemarray = customitemarray
|
||||
self.can_take_damage = True
|
||||
self.hints = hints.copy()
|
||||
self.prizes = {}
|
||||
self.dynamic_regions = []
|
||||
self.dynamic_locations = []
|
||||
self.spoiler = Spoiler(self)
|
||||
@@ -122,6 +123,7 @@ class World(object):
|
||||
set_player_attr('compassshuffle', False)
|
||||
set_player_attr('keyshuffle', False)
|
||||
set_player_attr('bigkeyshuffle', False)
|
||||
set_player_attr('bomblogic', False)
|
||||
set_player_attr('difficulty_requirements', None)
|
||||
set_player_attr('boss_shuffle', 'none')
|
||||
set_player_attr('enemy_shuffle', 'none')
|
||||
@@ -149,6 +151,7 @@ class World(object):
|
||||
set_player_attr('standardize_palettes', 'standardize')
|
||||
set_player_attr('force_fix', {'gt': False, 'sw': False, 'pod': False, 'tr': False})
|
||||
set_player_attr('owswaps', [[],[],[]])
|
||||
set_player_attr('prizes', {'pull': [0, 0, 0], 'crab': [0, 0], 'stun': 0, 'fish': 0})
|
||||
|
||||
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)})'
|
||||
@@ -687,6 +690,140 @@ class CollectionState(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_farm_rupees(self, player):
|
||||
tree_pulls = ['Lost Woods East Area',
|
||||
'Snitch Lady (East)',
|
||||
'Turtle Rock Area',
|
||||
'Pyramid Area',
|
||||
'Hype Cave Area',
|
||||
'Dark South Pass Area',
|
||||
'Bumper Cave Area']
|
||||
pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area']
|
||||
post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area']
|
||||
|
||||
rupee_farms = ['Archery Game', '50 Rupee Cave', '20 Rupee Cave']
|
||||
|
||||
def can_reach_non_bunny(regionname):
|
||||
region = self.world.get_region(regionname, player)
|
||||
return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player))
|
||||
|
||||
for region in rupee_farms:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
if any(i in [0xda, 0xdb] for i in self.world.prizes[player]['pull']):
|
||||
for region in tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
if not self.has('Beat Agahnim 1', player):
|
||||
for region in pre_aga_tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
else:
|
||||
for region in post_aga_tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_farm_bombs(self, player):
|
||||
if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player):
|
||||
return True
|
||||
|
||||
bush_bombs = ['Flute Boy Approach Area',
|
||||
'Kakariko Area',
|
||||
'Village of Outcasts Area',
|
||||
'Forgotten Forest Area',
|
||||
'Bat Cave Ledge',
|
||||
'East Dark Death Mountain (Bottom)']
|
||||
rock_bombs = ['Links House Area',
|
||||
'Dark Chapel Area',
|
||||
'Wooden Bridge Area',
|
||||
'Ice Cave Area',
|
||||
'Eastern Nook Area',
|
||||
'West Death Mountain (Bottom)',
|
||||
'Kakariko Fortune Area',
|
||||
'Skull Woods Forest',
|
||||
'Catfish Area',
|
||||
'Dark Fortune Area',
|
||||
'Qirn Jump Area',
|
||||
'Shield Shop Area',
|
||||
'Palace of Darkness Nook Area',
|
||||
'Swamp Nook Area',
|
||||
'Dark South Pass Area']
|
||||
bonk_bombs = ['Kakariko Fortune Area', 'Dark Graveyard Area'] #TODO: Flute Boy Approach Area and Bonk Rock Ledge are available post-Aga
|
||||
bomb_caves = ['Graveyard Cave', 'Light World Bomb Hut']
|
||||
|
||||
tree_pulls = ['Lost Woods East Area',
|
||||
'Snitch Lady (East)',
|
||||
'Turtle Rock Area',
|
||||
'Pyramid Area',
|
||||
'Hype Cave Area',
|
||||
'Dark South Pass Area',
|
||||
'Bumper Cave Area']
|
||||
pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area']
|
||||
post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area']
|
||||
|
||||
bush_crabs = ['Lost Woods East Area', 'Mountain Entry Area']
|
||||
pre_aga_bush_crabs = ['Lumberjack Area', 'South Pass Area']
|
||||
rock_crabs = ['Desert Pass Area']
|
||||
|
||||
def can_reach_non_bunny(regionname):
|
||||
region = self.world.get_region(regionname, player)
|
||||
return region.can_reach(self) and ((self.world.mode[player] != 'inverted' and region.is_light_world) or (self.world.mode[player] == 'inverted' and region.is_dark_world) or self.has('Pearl', player))
|
||||
|
||||
# bomb pickups
|
||||
for region in bush_bombs + bomb_caves:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
if self.can_lift_rocks(player):
|
||||
for region in rock_bombs:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
if self.has_Boots(player):
|
||||
for region in bonk_bombs:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
# tree pulls
|
||||
if any(i in [0xdc, 0xdd, 0xde] for i in self.world.prizes[player]['pull']):
|
||||
for region in tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
if not self.has('Beat Agahnim 1', player):
|
||||
for region in pre_aga_tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
else:
|
||||
for region in post_aga_tree_pulls:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
# bush crabs (final item isn't considered)
|
||||
if self.world.enemy_shuffle[player] != 'none':
|
||||
if self.world.prizes[player]['crab'][0] in [0xdc, 0xdd, 0xde]:
|
||||
for region in bush_crabs:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
if not self.has('Beat Agahnim 1', player):
|
||||
for region in pre_aga_bush_crabs:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
if self.can_lift_rocks(player) and self.world.prizes[player]['crab'][0] in [0xdc, 0xdd, 0xde]:
|
||||
for region in rock_crabs:
|
||||
if can_reach_non_bunny(region):
|
||||
return True
|
||||
|
||||
# stun prize
|
||||
if self.can_stun_enemies(player) and self.world.prizes[player]['stun'] in [0xdc, 0xdd, 0xde]:
|
||||
return True
|
||||
|
||||
# bomb purchases
|
||||
if self.can_farm_rupees(player) and (self.can_buy_unlimited('Bombs (10)', player) or self.can_reach('Big Bomb Shop', None, player)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def item_count(self, item, player):
|
||||
return self.prog_items[item, player]
|
||||
|
||||
@@ -743,10 +880,21 @@ class CollectionState(object):
|
||||
or self.can_shoot_arrows(player)
|
||||
or self.has('Fire Rod', player)))
|
||||
|
||||
# Check if the player starts without bombs
|
||||
def can_stun_enemies(self, player):
|
||||
if self.world.difficulty_adjustments[player] == 'expert':
|
||||
return False
|
||||
elif self.world.difficulty_adjustments[player] == 'hard':
|
||||
return self.has('Hookshot', player)
|
||||
else:
|
||||
return self.has('Hookshot', player) \
|
||||
or self.has('Blue Boomerang', player) \
|
||||
or self.has('Red Boomerang', player)
|
||||
|
||||
# In the future, this can be used to check if the player starts without bombs
|
||||
def can_use_bombs(self, player):
|
||||
StartingBombs = True
|
||||
return (self.bomb_mode_check(player, 1) and (StartingBombs or self.has('Bomb Upgrade (+10)', player)))
|
||||
if self.world.swords[player] == 'bombs':
|
||||
return self.has_bomb_level(player, 1)
|
||||
return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) and self.can_farm_bombs(player)
|
||||
|
||||
def can_hit_crystal(self, player):
|
||||
return (self.can_use_bombs(player)
|
||||
@@ -778,6 +926,7 @@ class CollectionState(object):
|
||||
def can_get_good_bee(self, player):
|
||||
cave = self.world.get_region('Good Bee Cave', player)
|
||||
return (
|
||||
self.can_use_bombs(player) and
|
||||
self.has_bottle(player) and
|
||||
self.has('Bug Catching Net', player) and
|
||||
(self.has_Boots(player) or (self.can_use_medallions(player) and self.has('Quake', player))) and
|
||||
@@ -2273,6 +2422,7 @@ class Spoiler(object):
|
||||
'logic': self.world.logic,
|
||||
'mode': self.world.mode,
|
||||
'retro': self.world.retro,
|
||||
'bomblogic': self.world.bomblogic,
|
||||
'weapons': self.world.swords,
|
||||
'goal': self.world.goal,
|
||||
'ow_shuffle': self.world.owShuffle,
|
||||
@@ -2388,6 +2538,7 @@ class Spoiler(object):
|
||||
outfile.write('Experimental:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['experimental'][player] else 'No'))
|
||||
outfile.write('Key Drops shuffled:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No'))
|
||||
outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['shopsanity'][player] else 'No'))
|
||||
outfile.write('Bomblogic:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['bomblogic'][player] else 'No'))
|
||||
if self.doors:
|
||||
outfile.write('\n\nDoors:\n\n')
|
||||
outfile.write('\n'.join(
|
||||
|
||||
Reference in New Issue
Block a user