make world-local items available as a general option

This commit is contained in:
Fabian Dill 2020-06-03 22:13:58 +02:00
parent 38cbcc662f
commit e55726efca
7 changed files with 53 additions and 7 deletions

View File

@ -113,6 +113,7 @@ class World(object):
set_player_attr('can_take_damage', True)
set_player_attr('glitch_boots', True)
set_player_attr('progression_balancing', True)
set_player_attr('local_items', set())
def get_name_string_for_object(self, obj) -> str:
return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})'

View File

@ -236,7 +236,10 @@ def parse_arguments(argv, no_defaults=False):
Keys are universal, shooting arrows costs rupees,
and a few other little things make this more like Zelda-1.
''', action='store_true')
parser.add_argument('--startinventory', default=defval(''), help='Specifies a list of items that will be in your starting inventory (separated by commas)')
parser.add_argument('--startinventory', default=defval(''),
help='Specifies a list of items that will be in your starting inventory (separated by commas)')
parser.add_argument('--local_items', default=defval(''),
help='Specifies a list of items that will not spread across the multiworld (separated by commas)')
parser.add_argument('--custom', default=defval(False), help='Not supported.')
parser.add_argument('--customitemarray', default=defval(False), help='Not supported.')
parser.add_argument('--accessibility', default=defval('items'), const='items', nargs='?', choices=['items', 'locations', 'none'], help='''\
@ -323,7 +326,7 @@ def parse_arguments(argv, no_defaults=False):
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality',
'shuffle', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'timer',
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
'retro', 'accessibility', 'hints', 'beemizer',
'local_items', 'retro', 'accessibility', 'hints', 'beemizer',
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'heartbeep', "skip_progression_balancing",

View File

@ -128,11 +128,11 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
'Compass (Escape)': (False, True, 'Compass', 0x8F, 'Now you can find no boss!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Hyrule Castle'),
'Map (Escape)': (False, True, 'Map', 0x7F, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Hyrule Castle'),
'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'),
# doors-specific items, baserom will not be able to understand these
# doors-specific items, baserom will not be able to understand these
'Big Key (Agahnims Tower)': (False, False, 'BigKey', 0x9B, 'A big key to Agahnim', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Castle Tower'),
'Compass (Agahnims Tower)': (False, True, 'Compass', 0x8B, 'Now you can find Aga1!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Castle Tower'),
'Map (Agahnims Tower)': (False, True, 'Map', 0x7B, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Castle Tower'),
# end of doors-specific items
# end of doors-specific items
'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'),
'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'),
'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'),
@ -183,4 +183,25 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
lookup_id_to_name = {data[3]: name for name, data in item_table.items()}
hint_blacklist = {"Triforce"}
hint_blacklist = {"Triforce"}
item_name_groups = {"Bows": {"Bow", "Silver Arrows", "Progressive Bow (Alt)", "Progressive Bow"}}
# generic groups, (Name, substring)
_simple_groups = {("Swords", "Sword"),
("Small Keys", "Small Key"),
("Big Keys", "Big Key"),
("Compasses", "Compass"),
("Maps", "Map"),
("Bottles", "Bottle"),
("Potions", "Potion"),
("Rupees", "Rupee")
}
for basename, substring in _simple_groups:
tempset = item_name_groups[basename] = set()
for itemname in item_table:
if substring in itemname:
tempset.add(itemname)
del (_simple_groups)

View File

@ -85,6 +85,7 @@ def main(args, seed=None):
item = ItemFactory(tok.strip(), player)
if item:
world.push_precollected(item)
world.local_items[player] = {item.strip() for item in args.local_items[player].split(',')}
if world.mode[player] != 'inverted':
create_regions(world, player)

View File

@ -14,6 +14,7 @@ from Utils import parse_yaml
from Rom import get_sprite_from_name
from EntranceRandomizer import parse_arguments
from Main import main as ERmain
from Items import item_name_groups, item_table
@ -355,11 +356,22 @@ def roll_settings(weights):
startitems.append(item)
elif itemvalue:
startitems.append(item)
ret.glitch_boots = get_choice('glitch_boots', weights) if 'glitch_boots' in weights else True
ret.startinventory = ','.join(startitems)
ret.glitch_boots = get_choice('glitch_boots', weights) if 'glitch_boots' in weights else True
ret.remote_items = get_choice('remote_items', weights) if 'remote_items' in weights else False
ret.local_items = set()
for item_name in weights.get('local_items', []):
items = item_name_groups.get(item_name, {item_name})
for item in items:
if item in item_table:
ret.local_items.add(item)
else:
logging.warning(f"Could not force item {item} to be world-local, as it was not recognized.")
ret.local_items = ",".join(ret.local_items)
if 'rom' in weights:
romweights = weights['rom']
ret.sprite = get_choice('sprite', romweights)

View File

@ -138,9 +138,12 @@ def global_rules(world, player):
# ganon can only carry triforce
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
if world.goal[player] == "localtriforcehunt":
world.local_items[player].add('Triforce Piece')
if world.local_items[player]:
for location in world.get_locations():
if location.player != player:
forbid_item(location, 'Triforce Piece', player)
for item in world.local_items[player]:
forbid_item(location, item, player)
# determines which S&Q locations are available - hide from paths since it isn't an in-game location
world.get_region('Menu', player).can_reach_private = lambda state: True
for exit in world.get_region('Menu', player).exits:

View File

@ -151,6 +151,11 @@ timer:
ohko: 0
timed_countdown: 0
display: 0
#can be uncommented to use it
#local_items: #force certain items to appear in your world only, not across the multiworld. Recognizes some group names, like "Swords"
# - "Moon Pearl"
# - "Small Keys"
# - "Big Keys"
glitch_boots:
on: 1 # enables that you start with Pegasus Boots in any glitched logic mode
off: 0