Skip to content

Commit

Permalink
0.6.2 Release
Browse files Browse the repository at this point in the history
0.6.2 Release
  • Loading branch information
AmazingAmpharos authored Apr 30, 2019
2 parents 33e0762 + 428862e commit 390bd1f
Show file tree
Hide file tree
Showing 80 changed files with 2,714 additions and 845 deletions.
11 changes: 6 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
*.pyc
dist
build
.idea
*.sfc
.vscode
*_Spoiler.txt
bundle/components.wxs
*.pyc
*.sfc
*.wixobj
build
bundle/components.wxs
dist
README.html
4 changes: 2 additions & 2 deletions Adjuster.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ def main():
''')
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'],
parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['double', 'normal', 'half', 'quarter', 'off'],
help='''\
Select the rate at which the heart beep sound is played at
low health. (default: %(default)s)
''')
parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow'],
parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow', 'random'],
help='Select the color of Link\'s heart meter. (default: %(default)s)')
parser.add_argument('--sprite', help='''\
Path to a sprite sheet to use for Link. Needs to be in
Expand Down
115 changes: 96 additions & 19 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class World(object):

def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, retro, custom, customitemarray):
def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, retro, custom, customitemarray, boss_shuffle, hints):
self.shuffle = shuffle
self.logic = logic
self.mode = mode
Expand All @@ -23,6 +23,7 @@ def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, a
self.seed = None
self.state = CollectionState(self)
self.required_medallions = ['Ether', 'Quake']
self._cached_entrances = None
self._cached_locations = None
self._entrance_cache = {}
self._region_cache = {}
Expand All @@ -45,14 +46,17 @@ def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, a
self.aga_randomness = True
self.lock_aga_door_in_escape = False
self.fix_trock_doors = self.shuffle != 'vanilla'
self.save_and_quit_from_boss = False
self.save_and_quit_from_boss = True
self.check_beatable_only = check_beatable_only
self.fix_skullwoods_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
self.fix_palaceofdarkness_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
self.fix_trock_exit = self.shuffle not in ['vanilla', 'simple', 'restricted', 'dungeonssimple']
self.shuffle_ganon = shuffle_ganon
self.fix_gtower_exit = self.shuffle_ganon
self.can_access_trock_eyebridge = None
self.can_access_trock_front = None
self.can_access_trock_big_chest = None
self.can_access_trock_middle = None
self.quickswap = quickswap
self.fastmenu = fastmenu
self.disable_music = disable_music
Expand All @@ -63,6 +67,8 @@ def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, a
self.can_take_damage = True
self.difficulty_requirements = None
self.fix_fake_world = True
self.boss_shuffle = boss_shuffle
self.hints = hints
self.dynamic_regions = []
self.dynamic_locations = []
self.spoiler = Spoiler(self)
Expand Down Expand Up @@ -110,6 +116,15 @@ def get_location(self, location):
return r_location
raise RuntimeError('No such location %s' % location)

def get_dungeon(self, dungeonname):
if isinstance(dungeonname, Dungeon):
return dungeonname

for dungeon in self.dungeons:
if dungeon.name == dungeonname:
return dungeon
raise RuntimeError('No such dungeon %s' % dungeonname)

def get_all_state(self, keys=False):
ret = CollectionState(self)

Expand Down Expand Up @@ -180,6 +195,16 @@ def push_item(self, location, item, collect=True):
else:
raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))

def get_entrances(self):
if self._cached_entrances is None:
self._cached_entrances = []
for region in self.regions:
self._cached_entrances.extend(region.entrances)
return self._cached_entrances

def clear_entrance_cache(self):
self._cached_entrances = None

def get_locations(self):
if self._cached_locations is None:
self._cached_locations = []
Expand Down Expand Up @@ -409,11 +434,11 @@ def bottle_count(self):
return len([pritem for pritem in self.prog_items if pritem.startswith('Bottle')])

def has_hearts(self, count):
# Warning: This oncly considers items that are marked as advancement items
# Warning: This only considers items that are marked as advancement items
return self.heart_count() >= count

def heart_count(self):
# Warning: This oncly considers items that are marked as advancement items
# Warning: This only considers items that are marked as advancement items
return (
self.item_count('Boss Heart Container')
+ self.item_count('Sanctuary Heart Container')
Expand All @@ -424,26 +449,27 @@ def heart_count(self):
def can_lift_heavy_rocks(self):
return self.has('Titans Mitts')

def can_extend_magic(self, smallmagic=8, fullrefill=False): #This reflects the total magic Link has, not the total extra he has.
def can_extend_magic(self, smallmagic=16, fullrefill=False): #This reflects the total magic Link has, not the total extra he has.
basemagic = 8
if self.has('Quarter Magic'):
basemagic = 32
elif self.has('Half Magic'):
basemagic = 16
if self.world.difficulty == 'hard' and not fullrefill:
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count())
elif self.world.difficulty == 'expert' and not fullrefill:
basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count())
elif self.world.difficulty == 'insane' and not fullrefill:
basemagic = basemagic
elif self.can_buy_unlimited('Green Potion') or self.can_buy_unlimited('Red Potion'):
basemagic = basemagic + basemagic * self.bottle_count()
if self.can_buy_unlimited('Green Potion') or self.can_buy_unlimited('Blue Potion'):
if self.world.difficulty == 'hard' and not fullrefill:
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count())
elif self.world.difficulty == 'expert' and not fullrefill:
basemagic = basemagic + int(basemagic * 0.25 * self.bottle_count())
elif self.world.difficulty == 'insane' and not fullrefill:
basemagic = basemagic
else:
basemagic = basemagic + basemagic * self.bottle_count()
return basemagic >= smallmagic

def can_kill_most_things(self, enemies=5):
return (self.has_blunt_weapon()
or self.has('Cane of Somaria')
or (self.has('Cane of Byrna') and (enemies < 6 or self.can_extend_Magic()))
or (self.has('Cane of Byrna') and (enemies < 6 or self.can_extend_magic()))
or self.can_shoot_arrows()
or self.has('Fire Rod')
)
Expand All @@ -455,6 +481,16 @@ def can_shoot_arrows(self):
return self.has('Bow') and (self.has('Silver Arrows') or self.can_buy_unlimited('Single Arrow'))
return self.has('Bow')

def can_get_good_bee(self):
cave = self.world.get_region('Good Bee Cave')
return (
self.has_bottle() and
self.has('Bug Catching Net') and
(self.has_Boots() or (self.has_sword() and self.has('Quake'))) and
cave.can_reach(self) and
(cave.is_light_world or self.has_Pearl())
)

def has_sword(self):
return self.has('Fighter Sword') or self.has('Master Sword') or self.has('Tempered Sword') or self.has('Golden Sword')

Expand Down Expand Up @@ -595,7 +631,7 @@ def is_indoors(self):

class Region(object):

def __init__(self, name, type):
def __init__(self, name, type, hint):
self.name = name
self.type = type
self.entrances = []
Expand All @@ -607,7 +643,7 @@ def __init__(self, name, type):
self.is_light_world = False # will be set aftermaking connections.
self.is_dark_world = False
self.spot_type = 'Region'
self.hint_text = 'Hyrule'
self.hint_text = hint
self.recursion_count = 0

def can_reach(self, state):
Expand Down Expand Up @@ -676,6 +712,15 @@ def __init__(self, name, regions, big_key, small_keys, dungeon_items):
self.big_key = big_key
self.small_keys = small_keys
self.dungeon_items = dungeon_items
self.bosses = dict()

@property
def boss(self):
return self.bosses.get(None, None)

@boss.setter
def boss(self, value):
self.bosses[None] = value

@property
def keys(self):
Expand All @@ -694,9 +739,16 @@ def __str__(self):
def __unicode__(self):
return '%s' % self.name

class Boss(object):
def __init__(self, name, enemizer_name, defeat_rule):
self.name = name
self.enemizer_name = enemizer_name
self.defeat_rule = defeat_rule

def can_defeat(self, state):
return self.defeat_rule(state)

class Location(object):

def __init__(self, name='', address=None, crystal=False, hint_text=None, parent=None):
self.name = name
self.parent_region = parent
Expand All @@ -713,7 +765,7 @@ def __init__(self, name='', address=None, crystal=False, hint_text=None, parent=
self.item_rule = lambda item: True

def can_fill(self, state, item, check_access=True):
return self.always_allow(item, self) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state)))
return self.always_allow(state, item) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state)))

def can_reach(self, state):
if self.access_rule(state) and state.can_reach(self.parent_region):
Expand All @@ -729,7 +781,7 @@ def __unicode__(self):

class Item(object):

def __init__(self, name='', advancement=False, priority=False, type=None, code=None, pedestal_hint=None, pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None):
def __init__(self, name='', advancement=False, priority=False, type=None, code=None, pedestal_hint=None, pedestal_credit=None, sickkid_credit=None, zora_credit=None, witch_credit=None, fluteboy_credit=None, hint_text=None):
self.name = name
self.advancement = advancement
self.priority = priority
Expand All @@ -740,6 +792,7 @@ def __init__(self, name='', advancement=False, priority=False, type=None, code=N
self.zora_credit_text = zora_credit
self.magicshop_credit_text = witch_credit
self.fluteboy_credit_text = fluteboy_credit
self.hint_text = hint_text
self.code = code
self.location = None

Expand Down Expand Up @@ -774,6 +827,7 @@ class Crystal(Item):
class ShopType(Enum):
Shop = 0
TakeAny = 1
UpgradeShop = 2

class Shop(object):
def __init__(self, region, room_id, type, shopkeeper_config, replaceable):
Expand Down Expand Up @@ -803,6 +857,8 @@ def get_bytes(self):
config |= 0x40 # ignore door id
if self.type == ShopType.TakeAny:
config |= 0x80
if self.type == ShopType.UpgradeShop:
config |= 0x10 # Alt. VRAM
return [0x00]+int16_as_bytes(self.room_id)+[door_id, 0x00, config, self.shopkeeper_config, 0x00]

def has_unlimited(self, item):
Expand Down Expand Up @@ -840,6 +896,7 @@ def __init__(self, world):
self.paths = {}
self.metadata = {}
self.shops = []
self.bosses = OrderedDict()

def set_entrance(self, entrance, exit, direction):
self.entrances[(entrance, direction)] = OrderedDict([('entrance', entrance), ('exit', exit), ('direction', direction)])
Expand Down Expand Up @@ -884,6 +941,23 @@ def parse_data(self):
shopdata['item_{}'.format(index)] = "{} — {}".format(item['item'], item['price']) if item['price'] else item['item']
self.shops.append(shopdata)

self.bosses["Eastern Palace"] = self.world.get_dungeon("Eastern Palace").boss.name
self.bosses["Desert Palace"] = self.world.get_dungeon("Desert Palace").boss.name
self.bosses["Tower Of Hera"] = self.world.get_dungeon("Tower of Hera").boss.name
self.bosses["Hyrule Castle"] = "Agahnim"
self.bosses["Palace Of Darkness"] = self.world.get_dungeon("Palace of Darkness").boss.name
self.bosses["Swamp Palace"] = self.world.get_dungeon("Swamp Palace").boss.name
self.bosses["Skull Woods"] = self.world.get_dungeon("Skull Woods").boss.name
self.bosses["Thieves Town"] = self.world.get_dungeon("Thieves Town").boss.name
self.bosses["Ice Palace"] = self.world.get_dungeon("Ice Palace").boss.name
self.bosses["Misery Mire"] = self.world.get_dungeon("Misery Mire").boss.name
self.bosses["Turtle Rock"] = self.world.get_dungeon("Turtle Rock").boss.name
self.bosses["Ganons Tower Basement"] = self.world.get_dungeon('Ganons Tower').bosses['bottom'].name
self.bosses["Ganons Tower Middle"] = self.world.get_dungeon('Ganons Tower').bosses['middle'].name
self.bosses["Ganons Tower Top"] = self.world.get_dungeon('Ganons Tower').bosses['top'].name
self.bosses["Ganons Tower"] = "Agahnim 2"
self.bosses["Ganon"] = "Ganon"


from Main import __version__ as ERVersion
self.metadata = {'version': ERVersion,
Expand Down Expand Up @@ -913,7 +987,10 @@ def to_json(self):
out['Shops'] = self.shops
out['playthrough'] = self.playthrough
out['paths'] = self.paths
if self.world.boss_shuffle != 'none':
out['Bosses'] = self.bosses
out['meta'] = self.metadata

return json.dumps(out)

def to_file(self, filename):
Expand Down
Loading

0 comments on commit 390bd1f

Please sign in to comment.