Add support for swordless mode.

This commit is contained in:
LLCoolDave 2017-06-24 18:48:03 +02:00
parent acd54cbbff
commit 7bef9f6aaa
4 changed files with 36 additions and 14 deletions

View File

@ -195,14 +195,14 @@ class World(object):
@property
def option_identifier(self):
logic = 0 if self.logic == 'noglitches' else 1
mode = 0 if self.mode == 'open' 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)
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)
beatableonly = 1 if self.check_beatable_only else 0
return logic | (mode << 1) | (dungeonitems << 2) | (goal << 3) | (shuffle << 6) | (difficulty << 10) | (algorithm << 12) | (beatableonly << 15)
return logic | (beatableonly << 1) | (dungeonitems << 2) | (goal << 3) | (shuffle << 6) | (difficulty << 10) | (algorithm << 12) | (mode << 15)
class CollectionState(object):

23
Main.py
View File

@ -400,7 +400,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']:
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']:
raise NotImplementedError('Not supported yet')
world.push_item('Ganon', ItemFactory('Triforce'), False)
@ -412,7 +412,7 @@ def generate_itempool(world):
# set up item pool
if world.difficulty in ['timed', 'timed-countdown']:
world.itempool = ItemFactory(['Arrow Upgrade (+5)'] * 2 + ['Bomb Upgrade (+5)'] * 2 + ['Arrow Upgrade (+10)'] * 3 + ['Bomb Upgrade (+10)'] * 3 +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Sword'] * 3 + ['Progressive Glove'] * 2 +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Glove'] * 2 +
['Bottle'] * 4 +
['Bombos', 'Book of Mudora', 'Blue Boomerang', 'Bow', 'Bug Catching Net', 'Cane of Byrna', 'Cane of Somaria',
'Ether', 'Fire Rod', 'Flippers', 'Ocarina', 'Hammer', 'Hookshot', 'Ice Rod', 'Lamp', 'Cape', 'Magic Powder',
@ -423,7 +423,7 @@ def generate_itempool(world):
world.clock_mode = 'stopwatch' if world.difficulty == 'timed' else 'countdown'
elif world.difficulty == 'timed-ohko':
world.itempool = ItemFactory(['Arrow Upgrade (+5)'] * 6 + ['Bomb Upgrade (+5)'] * 6 + ['Arrow Upgrade (+10)', 'Bomb Upgrade (+10)'] +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Sword'] * 3 + ['Progressive Glove'] * 2 +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Glove'] * 2 +
['Bottle'] * 4 +
['Bombos', 'Book of Mudora', 'Blue Boomerang', 'Bow', 'Bug Catching Net', 'Cane of Byrna', 'Cane of Somaria',
'Ether', 'Fire Rod', 'Flippers', 'Ocarina', 'Hammer', 'Hookshot', 'Ice Rod', 'Lamp', 'Cape', 'Magic Powder',
@ -434,7 +434,7 @@ def generate_itempool(world):
world.clock_mode = 'ohko'
else:
world.itempool = ItemFactory(['Arrow Upgrade (+5)'] * 6 + ['Bomb Upgrade (+5)'] * 6 + ['Arrow Upgrade (+10)', 'Bomb Upgrade (+10)'] +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Sword'] * 3 + ['Progressive Glove'] * 2 +
['Progressive Armor'] * 2 + ['Progressive Shield'] * 3 + ['Progressive Glove'] * 2 +
['Bottle'] * 4 +
['Bombos', 'Book of Mudora', 'Blue Boomerang', 'Bow', 'Bug Catching Net', 'Cane of Byrna', 'Cane of Somaria',
'Ether', 'Fire Rod', 'Flippers', 'Ocarina', 'Hammer', 'Hookshot', 'Ice Rod', 'Lamp', 'Cape', 'Magic Powder',
@ -443,11 +443,16 @@ def generate_itempool(world):
['Rupees (50)'] * 7 + ['Rupees (5)'] * 4 + ['Rupee (1)'] * 2 + ['Rupees (300)'] * 4 + ['Rupees (20)'] * 28 +
['Arrows (10)'] * 4 + ['Bombs (3)'] * 10)
if world.mode == 'standard':
if world.mode == 'swordless':
world.push_item('Ether Tablet', ItemFactory('Rupees (20)'), False)
world.push_item('Bombos Tablet', ItemFactory('Rupees (20)'), False)
world.itempool.extend(ItemFactory(['Rupees (20)', 'Rupees (20)']))
elif world.mode == 'standard':
world.push_item('Uncle', ItemFactory('Progressive Sword'), False)
world.get_location('Uncle').event = True
world.itempool.extend(ItemFactory(['Progressive Sword'] * 3))
else:
world.itempool.append(ItemFactory('Progressive Sword'))
world.itempool.extend(ItemFactory(['Progressive Sword'] * 4))
# provide mirror and pearl so you can avoid fake DW/LW and do dark world exploration as intended by algorithm, for now
if world.shuffle == 'insanity':
@ -614,8 +619,10 @@ if __name__ == '__main__':
parser.add_argument('--create_spoiler', help='Output a Spoiler File', action='store_true')
parser.add_argument('--logic', default='noglitches', const='noglitches', nargs='?', choices=['noglitches', 'minorglitches'],
help='Select Enforcement of Item Requirements. Minor Glitches may require Fake Flippers, Bunny Revival and Dark Room Navigation.')
parser.add_argument('--mode', default='open', const='open', nargs='?', choices=['standard', 'open'],
help='Select game mode. Standard fixes Hyrule Castle Secret Entrance and Front Door, but may lead to weird rain state issues if you exit through the Hyrule Castle side exits before rescuing Zelda in a full shuffle.')
parser.add_argument('--mode', default='open', const='open', nargs='?', choices=['standard', 'open', 'swordless'],
help='Select game mode. Standard fixes Hyrule Castle Secret Entrance and Front Door, but may lead to weird rain state issues if you exit through the Hyrule Castle side exits before rescuing Zelda in a full shuffle.\n'
'Swordless mode is like open, but with no swords. Curtains in Skull Woods and Agahnims Tower are removed, Agahnims Tower barrier can be destroyed with hammer. Misery Mire and Turtle Rock can be opened without a sword.\n'
'Hammer damages Ganon. Ether and Bombos Tablet are unreachable but contain trash items always.')
parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'starhunt', 'triforcehunt'],
help='Select completion goal. Pedestal places the Triforce at the Master Sword Pedestal. All dungeons is not enforced ingame but considered in the playthrough. \n'
'Star Hunt places 15 Power Stars pieces in the world, collect 10 of them to beat the game.\n'

2
Rom.py
View File

@ -74,7 +74,7 @@ def patch_rom(world, rom, hashtable, quickswap=False, beep='normal', sprite=None
write_byte(rom, 0x51DE, 0x00)
# set open mode:
if world.mode == 'open':
if world.mode in ['open', 'swordless']:
write_byte(rom, 0x180032, 0x01) # open mode
# disable sword sprite from uncle

View File

@ -15,12 +15,14 @@ def set_rules(world):
open_rules(world)
elif world.mode == 'standard':
standard_rules(world)
elif world.mode == 'swordless':
swordless_rules(world)
else:
raise NotImplementedError('Not implemented yet')
if world.goal == 'dungeons':
# require altar for ganon to enforce getting everything
add_rule(world.get_location('Ganon'), lambda state: state.can_reach('Altar', 'Location'))
add_rule(world.get_location('Ganon'), lambda state: state.can_reach('Altar', 'Location') and state.has('Beat Agahnim 1'))
set_big_bomb_rules(world)
@ -97,10 +99,10 @@ def global_rules(world):
set_rule(world.get_entrance('Checkerboard Cave'), lambda state: state.can_lift_rocks())
set_rule(world.get_location('Altar'), lambda state: state.has('Red Pendant') and state.has('Blue Pendant') and state.has('Green Pendant'))
set_rule(world.get_location('Sahasrahla'), lambda state: state.has('Green Pendant'))
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.can_reach('Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword())
set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1'))
set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False) # drop cannott be climbed up
set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False) # drop cannot be climbed up
set_rule(world.get_entrance('Broken Bridge (West)'), lambda state: state.has('Hookshot'))
set_rule(world.get_entrance('Broken Bridge (East)'), lambda state: state.has('Hookshot'))
set_rule(world.get_entrance('East Death Mountain Teleporter'), lambda state: state.can_lift_heavy_rocks())
@ -366,6 +368,19 @@ def open_rules(world):
pass
def swordless_rules(world):
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has('Hammer') or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has('Hammer') or state.has('Bug Catching Net'))
set_rule(world.get_location('Ether Tablet'), lambda state: True) # will have fixed rupee drop, unobtainable
set_rule(world.get_location('Bombos Tablet'), lambda state: True) # will have fixed rupee drop, unobtainable
set_rule(world.get_entrance('Misery Mire'), lambda state: state.has_Pearl() and state.has_misery_mire_medallion()) # sword not required to use medallion for opening in swordless (!)
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'))
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has('Hammer')) # need to damage ganon to get tiles to drop
def standard_rules(world):
# easiest way to enforce key placement not relevant for open
forbid_item(world.get_location('[dungeon-C-B1] Escape - Final Basement Room [left chest]'), 'Small Key (Escape)')