Fix random weapons for Standard Mode

Now works roughly like VT, except that swords are somwhat more common
and bombs-only escape is not supported (because I don't want to make
'Bombs (10)' an advancement item)

Swordless Standard Mode should also work now

Assured and Vanilla weapons still need to be implemented.
This commit is contained in:
Kevin Cathcart 2019-08-06 21:36:45 -04:00
parent ef7c3d4f06
commit b8ea2eb4b1
3 changed files with 72 additions and 45 deletions

View File

@ -387,13 +387,6 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
if swords == 'swordless':
pool.extend(diff.swordless)
elif mode == 'standard':
if want_progressives():
placed_items.append(('Link\'s Uncle', 'Progressive Sword'))
pool.extend(diff.progressivesword)
else:
placed_items.append(('Link\'s Uncle', 'Fighter Sword'))
pool.extend(diff.basicsword)
else:
if want_progressives():
pool.extend(diff.progressivesword)
@ -557,14 +550,6 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
itemtotal = itemtotal + 1
if mode == 'standard':
if progressive == 'off':
placed_items.append(('Link\'s Uncle', 'Fighter Sword'))
pool.extend(['Fighter Sword'] * max((customitemarray[32] - 1), 0))
pool.extend(['Progressive Sword'] * customitemarray[36])
else:
placed_items.append(('Link\'s Uncle', 'Progressive Sword'))
pool.extend(['Fighter Sword'] * customitemarray[32])
pool.extend(['Progressive Sword'] * max((customitemarray[36] - 1), 0))
if retro:
key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
placed_items.append((key_location, 'Small Key (Universal)'))
@ -572,10 +557,11 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
else:
pool.extend(['Small Key (Universal)'] * customitemarray[68])
else:
pool.extend(['Fighter Sword'] * customitemarray[32])
pool.extend(['Progressive Sword'] * customitemarray[36])
pool.extend(['Small Key (Universal)'] * customitemarray[68])
pool.extend(['Fighter Sword'] * customitemarray[32])
pool.extend(['Progressive Sword'] * customitemarray[36])
if shuffle == 'insanity_legacy':
placed_items.append(('Link\'s House', 'Magic Mirror'))
placed_items.append(('Sanctuary', 'Moon Pearl'))

34
Rom.py
View File

@ -551,7 +551,13 @@ def patch_rom(world, player, rom):
# set open mode:
if world.mode in ['open', 'inverted']:
rom.write_byte(0x180032, 0x01) # open mode
if world.mode == 'inverted':
set_inverted_mode(world, rom)
elif world.mode == 'standard':
rom.write_byte(0x180032, 0x00) # standard mode
uncle_location = world.get_location('Link\'s Uncle', player)
if uncle_location.item is None or uncle_location.item.name not in ['Master Sword', 'Tempered Sword', 'Fighter Sword', 'Golden Sword', 'Progressive Sword']:
# disable sword sprite from uncle
rom.write_bytes(0x6D263, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E])
rom.write_bytes(0x6D26B, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E])
@ -563,10 +569,6 @@ def patch_rom(world, player, rom):
rom.write_bytes(0x6D2EB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E])
rom.write_bytes(0x6D31B, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
rom.write_bytes(0x6D323, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
if world.mode == 'inverted':
set_inverted_mode(world, rom)
elif world.mode == 'standard':
rom.write_byte(0x180032, 0x00) # standard mode
# set light cones
rom.write_byte(0x180038, 0x01 if world.sewer_light_cone else 0x00)
@ -866,12 +868,6 @@ def patch_rom(world, player, rom):
rom.write_bytes(0x180080, [50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10)
rom.write_byte(0x18004D, 0x00) # Escape assist (off)
rom.write_byte(0x18004E, 0x00) # escape fills
rom.write_int16(0x180183, 0) # rupee fill (for bow if rupee arrows enabled)
rom.write_bytes(0x180185, [0x00, 0x00, 0x00]) # uncle item refills
rom.write_bytes(0x180188, [0x00, 0x00, 0x00]) # zelda item refills
rom.write_bytes(0x18018B, [0x00, 0x00, 0x00]) # uncle item refills
if world.goal in ['pedestal', 'triforcehunt']:
rom.write_byte(0x18003E, 0x01) # make ganon invincible
@ -950,6 +946,24 @@ def patch_rom(world, player, rom):
rom.write_bytes(0x6D2FB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E])
rom.write_bytes(0x6D313, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E])
rom.write_byte(0x18004E, 0) # Escape Fill (nothing)
rom.write_int16(0x180183, 300) # Escape fill rupee bow
rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows)
rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows)
rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows)
if world.mode == 'standard':
if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']:
rom.write_byte(0x18004E, 1) # Escape Fill (arrows)
rom.write_int16(0x180183, 300) # Escape fill rupee bow
rom.write_bytes(0x180185, [0,0,70]) # Uncle respawn refills (magic, bombs, arrows)
rom.write_bytes(0x180188, [0,0,10]) # Zelda respawn refills (magic, bombs, arrows)
rom.write_bytes(0x18018B, [0,0,10]) # Mantle respawn refills (magic, bombs, arrows)
elif uncle_location.item is not None and uncle_location.item.name in ['Cane of Somaria', 'Cane of Byrna', 'Fire Rod']:
rom.write_byte(0x18004E, 4) # Escape Fill (magic)
rom.write_bytes(0x180185, [0x80,0,0]) # Uncle respawn refills (magic, bombs, arrows)
rom.write_bytes(0x180188, [0x20,0,0]) # Zelda respawn refills (magic, bombs, arrows)
rom.write_bytes(0x18018B, [0x20,0,0]) # Mantle respawn refills (magic, bombs, arrows)
# patch swamp: Need to enable permanent drain of water as dam or swamp were moved
rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required[player] else 0x00)

View File

@ -1,5 +1,6 @@
import collections
import logging
from BaseClasses import CollectionState
def set_rules(world, player):
@ -7,17 +8,17 @@ def set_rules(world, player):
if world.logic == 'nologic':
logging.getLogger('').info('WARNING! Seeds generated under this logic often require major glitches and may be impossible!')
if world.mode != 'inverted':
world.get_region('Links House', player).can_reach = lambda state: True
world.get_region('Sanctuary', player).can_reach = lambda state: True
world.get_region('Links House', player).can_reach_private = lambda state: True
world.get_region('Sanctuary', player).can_reach_private = lambda state: True
old_rule = world.get_region('Old Man House', player).can_reach
world.get_region('Old Man House', player).can_reach = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
return
else:
world.get_region('Inverted Links House', player).can_reach = lambda state: True
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach = lambda state: True
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach_private = lambda state: True
if world.shuffle != 'vanilla':
old_rule = world.get_region('Old Man House', player).can_reach
world.get_region('Old Man House', player).can_reach = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
return
if world.mode != 'inverted':
global_rules(world, player)
@ -90,6 +91,9 @@ def forbid_item(location, item, player):
old_rule = location.item_rule
location.item_rule = lambda i: (i.name != item or i.player != player) and old_rule(i)
def add_item_rule(location, rule):
old_rule = location.item_rule
location.item_rule = lambda item: rule(item) and old_rule(item)
def item_in_locations(state, item, player, locations):
for location in locations:
@ -111,15 +115,20 @@ def global_rules(world, player):
forbid_item(location, 'Triforce Piece', player)
# ganon can only carry triforce
world.get_location('Ganon', player).item_rule = lambda item: item.name == 'Triforce' and item.player == player
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
# these are default save&quit points and always accessible
world.get_region('Links House', player).can_reach = lambda state: True
world.get_region('Sanctuary', player).can_reach = lambda state: True
if world.mode == 'standard':
world.get_region('Hyrule Castle Secret Entrance', player).can_reach_private = lambda state: True
old_rule = world.get_region('Links House', player).can_reach
world.get_region('Links House', player).can_reach_private = lambda state: state.can_reach('Sanctuary', 'Region', player) or old_rule(state)
else:
# these are default save&quit points and always accessible
world.get_region('Links House', player).can_reach_private = lambda state: True
world.get_region('Sanctuary', player).can_reach_private = lambda state: True
# we can s&q to the old man house after we rescue him. This may be somewhere completely different if caves are shuffled!
old_rule = world.get_region('Old Man House', player).can_reach
world.get_region('Old Man House', player).can_reach = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
# overworld requirements
set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player))
@ -454,14 +463,20 @@ def global_rules(world, player):
set_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt, player))
def inverted_rules(world, player):
world.get_location('Ganon', player).item_rule = lambda item: item.name == 'Triforce' and item.player == player
world.get_region('Inverted Links House', player).can_reach = lambda state: True
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach = lambda state: True
if world.goal == 'triforcehunt':
for location in world.get_locations():
if location.player != player:
forbid_item(location, 'Triforce Piece', player)
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach_private = lambda state: True
# we can s&q to the old man house after we rescue him. This may be somewhere completely different if caves are shuffled!
if world.shuffle != 'vanilla':
old_rule = world.get_region('Old Man House', player).can_reach
world.get_region('Old Man House', player).can_reach = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
# overworld requirements
set_rule(world.get_location('Maze Race', player), lambda state: state.has_Pearl(player))
set_rule(world.get_entrance('Mini Moldorm Cave', player), lambda state: state.has_Pearl(player))
@ -930,9 +945,21 @@ def swordless_rules(world, player):
def standard_rules(world, player):
for loc in ['Sanctuary', 'Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle',
'Sewers - Secret Room - Right']:
add_rule(world.get_location(loc, player), lambda state: state.can_kill_most_things(player) and state.has_key('Small Key (Escape)', player))
add_rule(world.get_entrance('Sewers Door', player), lambda state: state.can_kill_most_things(player))
set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
set_rule(world.get_entrance('Hyrule Castle Exit (West)', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
# ensures the required weapon for escape lands on uncle (unless player has it pre-equipped)
add_rule(world.get_location('Secret Passage', player), lambda state: state.can_kill_most_things(player))
add_rule(world.get_location('Hyrule Castle - Map Chest', player), lambda state: state.can_kill_most_things(player))
def uncle_item_rule(item):
copy_state = CollectionState(world)
copy_state.collect(item)
return copy_state.can_reach('Sanctuary', 'Region', player)
add_item_rule(world.get_location('Link\'s Uncle', player), uncle_item_rule)
# easiest way to enforce key placement not relevant for open
set_rule(world.get_location('Sewers - Dark Cross', player), lambda state: state.can_kill_most_things(player))