Remove starhunt, replaced by triforce hunt. Change to match VT normal settings (collect 20 out of 30 pieces). Rename restrictive algorithm to vt25. Add crystals goal, which removes aga2 requirement for hurting ganon. No noticeable difference without --shuffleganon enabled.

This commit is contained in:
LLCoolDave 2017-08-01 19:07:44 +02:00
parent 93dea89b8c
commit abff299f25
6 changed files with 29 additions and 29 deletions

View File

@ -32,7 +32,7 @@ class World(object):
self.light_world_light_cone = False
self.dark_world_light_cone = False
self.treasure_hunt_count = 0
self.treasure_hunt_icon = 'Power Star'
self.treasure_hunt_icon = 'Triforce Piece'
self.clock_mode = 'off'
self.aga_randomness = True
self.lock_aga_door_in_escape = False
@ -186,7 +186,7 @@ class World(object):
return True
elif location.item.name in ['Triforce Piece', 'Power Star']:
treasure_pieces_collected += 1
if self.goal in ['starhunt', 'triforcehunt'] and treasure_pieces_collected >= self.treasure_hunt_count:
if self.goal in ['triforcehunt'] and treasure_pieces_collected >= self.treasure_hunt_count:
return True
sphere.append(location)
@ -205,10 +205,10 @@ class World(object):
logic = 0 if self.logic == 'noglitches' else 1
mode = ['standard', 'open', 'swordless'].index(self.mode)
dungeonitems = 0 if self.place_dungeon_items else 1
goal = ['ganon', 'pedestal', 'dungeons', 'starhunt', 'triforcehunt'].index(self.goal)
goal = ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'].index(self.goal)
shuffle = ['vanilla', 'simple', 'restricted', 'full', 'madness', 'insanity', 'dungeonsfull', 'dungeonssimple'].index(self.shuffle)
difficulty = ['normal', 'timed', 'timed-ohko', 'timed-countdown'].index(self.difficulty)
algorithm = ['freshness', 'flood', 'vt21', 'vt22', 'restrictive'].index(self.algorithm)
algorithm = ['freshness', 'flood', 'vt21', 'vt22', 'vt25'].index(self.algorithm)
beatableonly = 1 if self.check_beatable_only else 0
shuffleganon = 1 if self.shuffle_ganon else 0
return logic | (beatableonly << 1) | (dungeonitems << 2) | (shuffleganon << 3) | (goal << 4) | (shuffle << 7) | (difficulty << 11) | (algorithm << 13) | (mode << 16)

View File

@ -39,18 +39,17 @@ if __name__ == '__main__':
Bombos Tablet are unreachable but contain trash items
always.
''')
parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'starhunt', 'triforcehunt'],
parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'],
help='''\
Select completion goal. (default: %(default)s)
Ganon: Collect all crystals, beat Agahnim 2 then
defeat Ganon.
Crystals: Collect all crystals then defeat Ganon.
Pedestal: Places the Triforce at the Master Sword Pedestal.
All Dungeons: Collect all crystals, pendants, beat both
Agahnim fights and then defeat Ganon.
Star Hunt: Places 15 Power Stars in the world, collect 10 of
them to beat the game.
Triforce Hunt: Places 3 Triforce Pieces in the world, collect
them all to beat the game.
Triforce Hunt: Places 30 Triforce Pieces in the world, collect
20 of them to beat the game.
''')
parser.add_argument('--difficulty', default='normal', const='normal', nargs='?', choices=['normal', 'timed', 'timed-ohko', 'timed-countdown'],
help='''\
@ -72,10 +71,10 @@ if __name__ == '__main__':
Timed mode. If time runs out, you lose (but can
still keep playing).
''')
parser.add_argument('--algorithm', default='restrictive', const='restrictive', nargs='?', choices=['freshness', 'flood', 'vt21', 'vt22', 'restrictive'],
parser.add_argument('--algorithm', default='vt25', const='vt25', nargs='?', choices=['freshness', 'flood', 'vt21', 'vt22', 'vt25'],
help='''\
Select item filling algorithm. (default: %(default)s)
Restrictive: Shuffle items and place them in a random location
vt25: Shuffle items and place them in a random location
that it is not impossible to be in.
vt21: Unbiased in its selection, but has tendency to put
Ice Rod in Turtle Rock.

6
Gui.py
View File

@ -90,7 +90,7 @@ def guiMain(args=None):
goalFrame = Frame(drowDownFrame)
goalVar = StringVar()
goalVar.set('ganon')
goalOptionMenu = OptionMenu(goalFrame, goalVar, 'ganon', 'pedestal', 'dungeons', 'starhunt', 'triforcehunt')
goalOptionMenu = OptionMenu(goalFrame, goalVar, 'ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals')
goalOptionMenu.pack(side=RIGHT)
goalLabel = Label(goalFrame, text='Game goal')
goalLabel.pack(side=LEFT)
@ -105,8 +105,8 @@ def guiMain(args=None):
algorithmFrame = Frame(drowDownFrame)
algorithmVar = StringVar()
algorithmVar.set('restrictive')
algorithmOptionMenu = OptionMenu(algorithmFrame, algorithmVar, 'freshness', 'flood', 'vt21', 'vt22', 'restrictive')
algorithmVar.set('vt25')
algorithmOptionMenu = OptionMenu(algorithmFrame, algorithmVar, 'freshness', 'flood', 'vt21', 'vt22', 'vt25')
algorithmOptionMenu.pack(side=RIGHT)
algorithmLabel = Label(algorithmFrame, text='Item distribution algorithm')
algorithmLabel.pack(side=LEFT)

14
Main.py
View File

@ -67,7 +67,7 @@ def main(args, seed=None):
distribute_items_cutoff(world, 0.66)
elif args.algorithm == 'freshness':
distribute_items_staleness(world)
elif args.algorithm == 'restrictive':
elif args.algorithm == 'vt25':
distribute_items_restrictive(world, 0)
logger.info('Calculating playthrough.')
@ -398,7 +398,7 @@ def flood_items(world):
def generate_itempool(world):
if world.difficulty not in ['normal', 'timed', 'timed-ohko', 'timed-countdown'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'starhunt', 'triforcehunt'] or world.mode not in ['open', 'standard', 'swordless']:
if world.difficulty not in ['normal', 'timed', 'timed-ohko', 'timed-countdown'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'] or world.mode not in ['open', 'standard', 'swordless']:
raise NotImplementedError('Not supported yet')
world.push_item('Ganon', ItemFactory('Triforce'), False)
@ -463,14 +463,10 @@ def generate_itempool(world):
if world.goal == 'pedestal':
world.push_item('Altar', ItemFactory('Triforce'), False)
elif world.goal == 'starhunt':
world.treasure_hunt_count = 10
world.treasure_hunt_icon = 'Power Star'
world.itempool.extend(ItemFactory(['Power Star'] * 15))
elif world.goal == 'triforcehunt':
world.treasure_hunt_count = 3
world.treasure_hunt_count = 20
world.treasure_hunt_icon = 'Triforce Piece'
world.itempool.extend(ItemFactory(['Triforce Piece'] * 3))
world.itempool.extend(ItemFactory(['Triforce Piece'] * 30))
if random.randint(0, 3) == 0:
world.itempool.append(ItemFactory('Magic Upgrade (1/4)'))
@ -568,7 +564,7 @@ def create_playthrough(world):
world = copy_world(world)
# in treasure hunt and pedestal goals, ganon is invincible
if world.goal in ['pedestal', 'starhunt', 'triforcehunt']:
if world.goal in ['pedestal', 'triforcehunt']:
world.get_location('Ganon').item = None
# if we only check for beatable, we can do this sanity check first before writing down spheres

8
Rom.py
View File

@ -285,11 +285,13 @@ def patch_rom(world, rom, hashtable, quickswap=False, beep='normal', sprite=None
rom.write_byte(0x180086, 0x00 if world.aga_randomness else 0x01) # set blue ball and ganon warp randomness
rom.write_byte(0x1800A1, 0x01) # enable overworld screen transition draining for water level inside swamp
if world.goal in ['ganon']:
rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals are collected
elif world.goal in ['pedestal', 'starhunt', 'triforcehunt']:
rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals and aga 2 are collected
elif world.goal in ['pedestal', 'triforcehunt']:
rom.write_byte(0x18003E, 0x01) # make ganon invincible
elif world.goal in ['dungeons']:
rom.write_byte(0x18003E, 0x02) # make ganon invincible until all dungeons are beat
elif world.goal in ['crystals']:
rom.write_byte(0x18003E, 0x04) # make ganon invincible until all crystals
rom.write_byte(0x18016A, 0x00) # disable free roaming item text boxes
rom.write_byte(0x18003B, 0x00) # disable maps showing crystals on overworld
rom.write_byte(0x18003C, 0x00) # disable compasses showing dungeon count
@ -425,7 +427,7 @@ def write_strings(rom, world):
write_string_to_rom(rom, 'PyramidFairy', PyramidFairy_texts[random.randint(0, len(PyramidFairy_texts) - 1)])
write_string_to_rom(rom, 'Sahasrahla2', Sahasrahla2_texts[random.randint(0, len(Sahasrahla2_texts) - 1)])
write_string_to_rom(rom, 'Blind', Blind_texts[random.randint(0, len(Blind_texts) - 1)])
if world.goal in ['pedestal', 'starhunt', 'triforcehunt']:
if world.goal in ['pedestal', 'triforcehunt']:
write_string_to_rom(rom, 'Ganon1Invincible', 'Why are you even here?\n You can\'t even hurt me!')
write_string_to_rom(rom, 'Ganon2Invincible', 'Seriously? Go Away, I will not Die.')
else:

View File

@ -22,7 +22,10 @@ def set_rules(world):
if world.goal == 'dungeons':
# require all dungeons to beat ganon
add_rule(world.get_location('Ganon'), lambda state: state.can_reach('Altar', 'Location') and state.has('Beat Agahnim 1'))
add_rule(world.get_location('Ganon'), lambda state: state.can_reach('Altar', 'Location') and state.has('Beat Agahnim 1') and state.has('Beat Agahnim 2'))
elif world.goal == 'ganon':
# require aga2 to beat ganon
add_rule(world.get_location('Ganon'), lambda state: state.has('Beat Agahnim 2'))
set_big_bomb_rules(world)
@ -306,7 +309,7 @@ def global_rules(world):
'[dungeon-A2-6F] Ganons Tower - Room before Moldorm', '[dungeon-A2-6F] Ganons Tower - Moldorm Room']:
forbid_item(world.get_location(location), 'Big Key (Ganons Tower)')
set_rule(world.get_location('Ganon'), lambda state: state.has_beam_sword() and state.has_fire_source() and state.has('Beat Agahnim 2') and state.has('Crystal 1') and state.has('Crystal 2')
set_rule(world.get_location('Ganon'), lambda state: state.has_beam_sword() and state.has_fire_source() and state.has('Crystal 1') and state.has('Crystal 2')
and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7')
and (state.has('Tempered Sword') or state.has('Golden Sword') or (state.has('Silver Arrows') and state.has('Bow')) or state.has('Lamp') or state.has('Bottle') or state.has('Half Magic') or state.has('Quarter Magic'))) # need to light torch a sufficient amount of times
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has_beam_sword()) # need to damage ganon to get tiles to drop
@ -383,7 +386,7 @@ def swordless_rules(world):
set_rule(world.get_entrance('Turtle Rock'), lambda state: state.has_Pearl() and state.has_turtle_rock_medallion() and state.can_reach('Turtle Rock (Top)', 'Region')) # sword not required to use medallion for opening in swordless (!)
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has('Small Key (Skull Woods)', 3) and state.has('Fire Rod')) # no curtain
set_rule(world.get_location('Agahnim 2'), lambda state: state.has('Hammer') or state.has('Bug Catching Net'))
set_rule(world.get_location('Ganon'), lambda state: state.has('Hammer') and state.has_fire_source() and state.has('Silver Arrows') and state.has('Bow') and state.has('Beat Agahnim 2') and state.has('Crystal 1') and state.has('Crystal 2')
set_rule(world.get_location('Ganon'), lambda state: state.has('Hammer') and state.has_fire_source() and state.has('Silver Arrows') and state.has('Bow') and state.has('Crystal 1') and state.has('Crystal 2')
and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7'))
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has('Hammer')) # need to damage ganon to get tiles to drop