Merge branch 'main' of https://github.com/ArchipelagoMW/Archipelago into main
This commit is contained in:
commit
3ee88fd8fe
152
Mystery.py
152
Mystery.py
|
@ -23,7 +23,9 @@ from worlds.alttp.Items import item_name_groups, item_table
|
|||
from worlds.alttp import Bosses
|
||||
from worlds.alttp.Text import TextTable
|
||||
from worlds.alttp.Regions import location_table, key_drop_data
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
|
||||
categories = set(AutoWorldRegister.world_types)
|
||||
|
||||
def mystery_argparse():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
|
@ -61,9 +63,11 @@ def mystery_argparse():
|
|||
args.plando: typing.Set[str] = {arg.strip().lower() for arg in args.plando.split(",")}
|
||||
return args
|
||||
|
||||
|
||||
def get_seed_name(random):
|
||||
return f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)
|
||||
|
||||
|
||||
def main(args=None, callback=ERmain):
|
||||
if not args:
|
||||
args = mystery_argparse()
|
||||
|
@ -79,14 +83,14 @@ def main(args=None, callback=ERmain):
|
|||
weights_cache = {}
|
||||
if args.weights:
|
||||
try:
|
||||
weights_cache[args.weights] = get_weights(args.weights)
|
||||
weights_cache[args.weights] = read_weights_yaml(args.weights)
|
||||
except Exception as e:
|
||||
raise ValueError(f"File {args.weights} is destroyed. Please fix your yaml.") from e
|
||||
print(f"Weights: {args.weights} >> "
|
||||
f"{get_choice('description', weights_cache[args.weights], 'No description specified')}")
|
||||
if args.meta:
|
||||
try:
|
||||
weights_cache[args.meta] = get_weights(args.meta)
|
||||
weights_cache[args.meta] = read_weights_yaml(args.meta)
|
||||
except Exception as e:
|
||||
raise ValueError(f"File {args.meta} is destroyed. Please fix your yaml.") from e
|
||||
meta_weights = weights_cache[args.meta]
|
||||
|
@ -99,7 +103,7 @@ def main(args=None, callback=ERmain):
|
|||
if path:
|
||||
try:
|
||||
if path not in weights_cache:
|
||||
weights_cache[path] = get_weights(path)
|
||||
weights_cache[path] = read_weights_yaml(path)
|
||||
print(f"P{player} Weights: {path} >> "
|
||||
f"{get_choice('description', weights_cache[path], 'No description specified')}")
|
||||
|
||||
|
@ -254,7 +258,7 @@ def main(args=None, callback=ERmain):
|
|||
callback(erargs, seed)
|
||||
|
||||
|
||||
def get_weights(path):
|
||||
def read_weights_yaml(path):
|
||||
try:
|
||||
if urllib.parse.urlparse(path).scheme:
|
||||
yaml = str(urllib.request.urlopen(path).read(), "utf-8")
|
||||
|
@ -342,19 +346,6 @@ goals = {
|
|||
'ice_rod_hunt': 'icerodhunt',
|
||||
}
|
||||
|
||||
# remove sometime before 1.0.0, warn before
|
||||
legacy_boss_shuffle_options = {
|
||||
# legacy, will go away:
|
||||
'simple': 'basic',
|
||||
'random': 'full',
|
||||
'normal': 'full'
|
||||
}
|
||||
|
||||
legacy_goals = {
|
||||
'dungeons': 'bosses',
|
||||
'fast_ganon': 'crystals',
|
||||
}
|
||||
|
||||
|
||||
def roll_percentage(percentage: typing.Union[int, float]) -> bool:
|
||||
"""Roll a percentage chance.
|
||||
|
@ -382,13 +373,12 @@ def roll_linked_options(weights: dict) -> dict:
|
|||
try:
|
||||
if roll_percentage(option_set["percentage"]):
|
||||
logging.debug(f"Linked option {option_set['name']} triggered.")
|
||||
if "options" in option_set:
|
||||
weights = update_weights(weights, option_set["options"], "Linked", option_set["name"])
|
||||
if "rom_options" in option_set:
|
||||
rom_weights = weights.get("rom", dict())
|
||||
rom_weights = update_weights(rom_weights, option_set["rom_options"], "Linked Rom",
|
||||
option_set["name"])
|
||||
weights["rom"] = rom_weights
|
||||
new_options = option_set["options"]
|
||||
for category_name, category_options in new_options.items():
|
||||
currently_targeted_weights = weights
|
||||
if category_name:
|
||||
currently_targeted_weights = currently_targeted_weights[category_name]
|
||||
update_weights(currently_targeted_weights, category_options, "Linked", option_set["name"])
|
||||
else:
|
||||
logging.debug(f"linked option {option_set['name']} skipped.")
|
||||
except Exception as e:
|
||||
|
@ -402,23 +392,24 @@ def roll_triggers(weights: dict) -> dict:
|
|||
weights["_Generator_Version"] = "Archipelago" # Some means for triggers to know if the seed is on main or doors.
|
||||
for i, option_set in enumerate(weights["triggers"]):
|
||||
try:
|
||||
currently_targeted_weights = weights
|
||||
category = option_set.get("option_category", None)
|
||||
if category:
|
||||
currently_targeted_weights = currently_targeted_weights[category]
|
||||
key = get_choice("option_name", option_set)
|
||||
if key not in weights:
|
||||
if key not in currently_targeted_weights:
|
||||
logging.warning(f'Specified option name {option_set["option_name"]} did not '
|
||||
f'match with a root option. '
|
||||
f'This is probably in error.')
|
||||
trigger_result = get_choice("option_result", option_set)
|
||||
result = get_choice(key, weights)
|
||||
weights[key] = result
|
||||
result = get_choice(key, currently_targeted_weights)
|
||||
currently_targeted_weights[key] = result
|
||||
if result == trigger_result and roll_percentage(get_choice("percentage", option_set, 100)):
|
||||
if "options" in option_set:
|
||||
weights = update_weights(weights, option_set["options"], "Triggered", option_set["option_name"])
|
||||
|
||||
if "rom_options" in option_set:
|
||||
rom_weights = weights.get("rom", dict())
|
||||
rom_weights = update_weights(rom_weights, option_set["rom_options"], "Triggered Rom",
|
||||
option_set["option_name"])
|
||||
weights["rom"] = rom_weights
|
||||
for category_name, category_options in option_set["options"].items():
|
||||
currently_targeted_weights = weights
|
||||
if category_name:
|
||||
currently_targeted_weights = currently_targeted_weights[category_name]
|
||||
update_weights(currently_targeted_weights, category_options, "Triggered", option_set["option_name"])
|
||||
|
||||
except Exception as e:
|
||||
raise ValueError(f"Your trigger number {i + 1} is destroyed. "
|
||||
|
@ -427,11 +418,6 @@ def roll_triggers(weights: dict) -> dict:
|
|||
|
||||
|
||||
def get_plando_bosses(boss_shuffle: str, plando_options: typing.Set[str]) -> str:
|
||||
if boss_shuffle in legacy_boss_shuffle_options:
|
||||
new_boss_shuffle = legacy_boss_shuffle_options[boss_shuffle]
|
||||
logging.warning(f"Boss shuffle {boss_shuffle} is deprecated, "
|
||||
f"please use {new_boss_shuffle} instead")
|
||||
return new_boss_shuffle
|
||||
if boss_shuffle in boss_shuffle_options:
|
||||
return boss_shuffle_options[boss_shuffle]
|
||||
elif "bosses" in plando_options:
|
||||
|
@ -439,10 +425,6 @@ def get_plando_bosses(boss_shuffle: str, plando_options: typing.Set[str]) -> str
|
|||
remainder_shuffle = "none" # vanilla
|
||||
bosses = []
|
||||
for boss in options:
|
||||
if boss in legacy_boss_shuffle_options:
|
||||
remainder_shuffle = legacy_boss_shuffle_options[boss_shuffle]
|
||||
logging.warning(f"Boss shuffle {boss} is deprecated, "
|
||||
f"please use {remainder_shuffle} instead")
|
||||
if boss in boss_shuffle_options:
|
||||
remainder_shuffle = boss_shuffle_options[boss]
|
||||
elif "-" in boss:
|
||||
|
@ -512,10 +494,12 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
|
|||
ret.name = get_choice('name', weights)
|
||||
ret.accessibility = get_choice('accessibility', weights)
|
||||
ret.progression_balancing = get_choice('progression_balancing', weights, True)
|
||||
ret.game = get_choice("game", weights, "A Link to the Past")
|
||||
|
||||
ret.game = get_choice("game", weights)
|
||||
if ret.game not in weights:
|
||||
raise Exception(f"No game options for selected game \"{ret.game}\" found.")
|
||||
game_weights = weights[ret.game]
|
||||
ret.local_items = set()
|
||||
for item_name in weights.get('local_items', []):
|
||||
for item_name in game_weights.get('local_items', []):
|
||||
items = item_name_groups.get(item_name, {item_name})
|
||||
for item in items:
|
||||
if item in lookup_any_item_name_to_id:
|
||||
|
@ -524,7 +508,7 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
|
|||
raise Exception(f"Could not force item {item} to be world-local, as it was not recognized.")
|
||||
|
||||
ret.non_local_items = set()
|
||||
for item_name in weights.get('non_local_items', []):
|
||||
for item_name in game_weights.get('non_local_items', []):
|
||||
items = item_name_groups.get(item_name, {item_name})
|
||||
for item in items:
|
||||
if item in lookup_any_item_name_to_id:
|
||||
|
@ -532,7 +516,7 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
|
|||
else:
|
||||
raise Exception(f"Could not force item {item} to be world-non-local, as it was not recognized.")
|
||||
|
||||
inventoryweights = weights.get('startinventory', {})
|
||||
inventoryweights = game_weights.get('start_inventory', {})
|
||||
startitems = []
|
||||
for item in inventoryweights.keys():
|
||||
itemvalue = get_choice(item, inventoryweights)
|
||||
|
@ -542,33 +526,32 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
|
|||
elif itemvalue:
|
||||
startitems.append(item)
|
||||
ret.startinventory = startitems
|
||||
ret.start_hints = set(weights.get('start_hints', []))
|
||||
|
||||
ret.start_hints = set(game_weights.get('start_hints', []))
|
||||
|
||||
if ret.game == "A Link to the Past":
|
||||
roll_alttp_settings(ret, weights, plando_options)
|
||||
roll_alttp_settings(ret, game_weights, plando_options)
|
||||
elif ret.game == "Hollow Knight":
|
||||
for option_name, option in Options.hollow_knight_options.items():
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, weights, True)))
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights, True)))
|
||||
elif ret.game == "Factorio":
|
||||
for option_name, option in Options.factorio_options.items():
|
||||
if option_name in weights:
|
||||
if option_name in game_weights:
|
||||
if issubclass(option, Options.OptionDict): # get_choice should probably land in the Option class
|
||||
setattr(ret, option_name, option.from_any(weights[option_name]))
|
||||
setattr(ret, option_name, option.from_any(game_weights[option_name]))
|
||||
else:
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, weights)))
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights)))
|
||||
else:
|
||||
setattr(ret, option_name, option(option.default))
|
||||
elif ret.game == "Minecraft":
|
||||
for option_name, option in Options.minecraft_options.items():
|
||||
if option_name in weights:
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, weights)))
|
||||
if option_name in game_weights:
|
||||
setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights)))
|
||||
else:
|
||||
setattr(ret, option_name, option(option.default))
|
||||
# bad hardcoded behavior to make this work for now
|
||||
ret.plando_connections = []
|
||||
if "connections" in plando_options:
|
||||
options = weights.get("plando_connections", [])
|
||||
options = game_weights.get("plando_connections", [])
|
||||
for placement in options:
|
||||
if roll_percentage(get_choice("percentage", placement, 100)):
|
||||
ret.plando_connections.append(PlandoConnection(
|
||||
|
@ -630,9 +613,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
|||
|
||||
goal = get_choice('goals', weights, 'ganon')
|
||||
|
||||
if goal in legacy_goals:
|
||||
logging.warning(f"Goal {goal} is depcrecated, please use {legacy_goals[goal]} instead.")
|
||||
goal = legacy_goals[goal]
|
||||
ret.goal = goals[goal]
|
||||
|
||||
# TODO consider moving open_pyramid to an automatic variable in the core roller, set to True when
|
||||
|
@ -649,7 +629,8 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
|||
ret.triforce_pieces_available = int(round(ret.triforce_pieces_required * percentage, 0))
|
||||
# vanilla mode (specify how many pieces are)
|
||||
elif extra_pieces == 'available':
|
||||
ret.triforce_pieces_available = Options.TriforcePieces.from_any(get_choice('triforce_pieces_available', weights, 30))
|
||||
ret.triforce_pieces_available = Options.TriforcePieces.from_any(
|
||||
get_choice('triforce_pieces_available', weights, 30))
|
||||
# required pieces + fixed extra
|
||||
elif extra_pieces == 'extra':
|
||||
extra_pieces = max(0, int(get_choice('triforce_pieces_extra', weights, 10)))
|
||||
|
@ -678,7 +659,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
|||
|
||||
ret.enemy_shuffle = bool(get_choice('enemy_shuffle', weights, False))
|
||||
|
||||
|
||||
ret.killable_thieves = get_choice('killable_thieves', weights, False)
|
||||
ret.tile_shuffle = get_choice('tile_shuffle', weights, False)
|
||||
ret.bush_shuffle = get_choice('bush_shuffle', weights, False)
|
||||
|
@ -790,13 +770,11 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
|||
get_choice("direction", placement, "both")
|
||||
))
|
||||
|
||||
if 'rom' in weights:
|
||||
romweights = weights['rom']
|
||||
|
||||
ret.sprite_pool = romweights['sprite_pool'] if 'sprite_pool' in romweights else []
|
||||
ret.sprite = get_choice('sprite', romweights, "Link")
|
||||
if 'random_sprite_on_event' in romweights:
|
||||
randomoneventweights = romweights['random_sprite_on_event']
|
||||
ret.sprite_pool = weights.get('sprite_pool', [])
|
||||
ret.sprite = get_choice('sprite', weights, "Link")
|
||||
if 'random_sprite_on_event' in weights:
|
||||
randomoneventweights = weights['random_sprite_on_event']
|
||||
if get_choice('enabled', randomoneventweights, False):
|
||||
ret.sprite = 'randomon'
|
||||
ret.sprite += '-hit' if get_choice('on_hit', randomoneventweights, True) else ''
|
||||
|
@ -809,30 +787,26 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
|||
ret.sprite = 'randomonnone' if ret.sprite == 'randomon' else ret.sprite
|
||||
|
||||
if (not ret.sprite_pool or get_choice('use_weighted_sprite_pool', randomoneventweights, False)) \
|
||||
and 'sprite' in romweights: # Use sprite as a weighted sprite pool, if a sprite pool is not already defined.
|
||||
for key, value in romweights['sprite'].items():
|
||||
and 'sprite' in weights: # Use sprite as a weighted sprite pool, if a sprite pool is not already defined.
|
||||
for key, value in weights['sprite'].items():
|
||||
if key.startswith('random'):
|
||||
ret.sprite_pool += ['random'] * int(value)
|
||||
else:
|
||||
ret.sprite_pool += [key] * int(value)
|
||||
|
||||
ret.disablemusic = get_choice('disablemusic', romweights, False)
|
||||
ret.triforcehud = get_choice('triforcehud', romweights, 'hide_goal')
|
||||
ret.quickswap = get_choice('quickswap', romweights, True)
|
||||
ret.fastmenu = get_choice('menuspeed', romweights, "normal")
|
||||
ret.reduceflashing = get_choice('reduceflashing', romweights, False)
|
||||
ret.heartcolor = get_choice('heartcolor', romweights, "red")
|
||||
ret.heartbeep = convert_to_on_off(get_choice('heartbeep', romweights, "normal"))
|
||||
ret.ow_palettes = get_choice('ow_palettes', romweights, "default")
|
||||
ret.uw_palettes = get_choice('uw_palettes', romweights, "default")
|
||||
ret.hud_palettes = get_choice('hud_palettes', romweights, "default")
|
||||
ret.sword_palettes = get_choice('sword_palettes', romweights, "default")
|
||||
ret.shield_palettes = get_choice('shield_palettes', romweights, "default")
|
||||
ret.link_palettes = get_choice('link_palettes', romweights, "default")
|
||||
|
||||
else:
|
||||
ret.quickswap = True
|
||||
ret.sprite = "Link"
|
||||
ret.disablemusic = get_choice('disablemusic', weights, False)
|
||||
ret.triforcehud = get_choice('triforcehud', weights, 'hide_goal')
|
||||
ret.quickswap = get_choice('quickswap', weights, True)
|
||||
ret.fastmenu = get_choice('menuspeed', weights, "normal")
|
||||
ret.reduceflashing = get_choice('reduceflashing', weights, False)
|
||||
ret.heartcolor = get_choice('heartcolor', weights, "red")
|
||||
ret.heartbeep = convert_to_on_off(get_choice('heartbeep', weights, "normal"))
|
||||
ret.ow_palettes = get_choice('ow_palettes', weights, "default")
|
||||
ret.uw_palettes = get_choice('uw_palettes', weights, "default")
|
||||
ret.hud_palettes = get_choice('hud_palettes', weights, "default")
|
||||
ret.sword_palettes = get_choice('sword_palettes', weights, "default")
|
||||
ret.shield_palettes = get_choice('shield_palettes', weights, "default")
|
||||
ret.link_palettes = get_choice('link_palettes', weights, "default")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -66,7 +66,7 @@ original_tech = technologies["{{original_tech_name}}"]
|
|||
new_tree_copy = table.deepcopy(template_tech)
|
||||
new_tree_copy.name = "ap-{{ tech_table[original_tech_name] }}-"{# use AP ID #}
|
||||
prep_copy(new_tree_copy, original_tech)
|
||||
{% if tech_cost != 1 %}
|
||||
{% if tech_cost_scale != 1 %}
|
||||
new_tree_copy.unit.count = math.max(1, math.floor(new_tree_copy.unit.count * {{ tech_cost_scale }}))
|
||||
{% endif %}
|
||||
{%- if item_name in tech_table and visibility -%}
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
# inverted
|
||||
# This means, if mode is meta-rolled and the result happens to be inverted, then defer to the player's yaml instead.
|
||||
meta_description: Meta-Mystery file with the intention of having similar-length completion times for a hopefully better experience
|
||||
null:
|
||||
progression_balancing: # Progression balancing tries to make sure that the player has *something* towards any players goal in each "sphere"
|
||||
on: 0 # Force every player into progression balancing
|
||||
off: 0 # Force every player out of progression balancing, then prepare for a lot of logical BK
|
||||
null: 1 # Let players decide via their own progression_balancing flag in their yaml, defaulting to on
|
||||
A Link to the Past:
|
||||
goals:
|
||||
ganon: 100 # Climb GT, defeat Agahnim 2, and then kill Ganon
|
||||
fast_ganon: 250 # Only killing Ganon is required. The hole is always open. However, items may still be placed in GT
|
||||
|
@ -61,4 +63,3 @@ triforce_pieces_available: # Set to how many triforces pieces are available to c
|
|||
triforce_pieces_required: # Set to how many out of X triforce pieces you need to win the game in a triforce hunt. Default is 20. Max is 90, Min is 1
|
||||
# Format "pieces: chance"
|
||||
25: 50
|
||||
# Do not use meta rom options at this time
|
|
@ -35,8 +35,8 @@ accessibility:
|
|||
progression_balancing:
|
||||
on: 50 # A system to reduce BK, as in times during which you can't do anything by moving your items into an earlier access sphere to make it likely you have stuff to do
|
||||
off: 0 # Turn this off if you don't mind a longer multiworld, or can glitch/sequence break around missing items.
|
||||
# Can be uncommented to use it
|
||||
# startinventory: # Begin the file with the listed items/upgrades
|
||||
# The following 4 options can be uncommented and moved into a game's section they should affect
|
||||
# start_inventory: # Begin the file with the listed items/upgrades
|
||||
# Please only use items for the correct game, use triggers if need to be have seperated lists.
|
||||
# Pegasus Boots: on
|
||||
# Bomb Upgrade (+10): 4
|
||||
|
@ -50,7 +50,7 @@ progression_balancing:
|
|||
# non_local_items: # Force certain items to appear outside your world only, unless in single-player. Recognizes some group names, like "Swords"
|
||||
# - "Progressive Weapons"
|
||||
|
||||
# Factorio options:
|
||||
Factorio:
|
||||
tech_tree_layout:
|
||||
single: 1
|
||||
small_diamonds: 1
|
||||
|
@ -98,7 +98,7 @@ random_tech_ingredients:
|
|||
starting_items:
|
||||
burner-mining-drill: 19
|
||||
stone-furnace: 19
|
||||
# Minecraft options:
|
||||
Minecraft:
|
||||
advancement_goal: # Number of advancements required (out of 92 total) to spawn the Ender Dragon and complete the game.
|
||||
few: 0 # 30 advancements
|
||||
normal: 1 # 50
|
||||
|
@ -119,9 +119,8 @@ include_postgame_advancements: # Some advancements require defeating the Ender D
|
|||
shuffle_structures: # CURRENTLY DISABLED; enables shuffling of villages, outposts, fortresses, bastions, and end cities.
|
||||
on: 0
|
||||
off: 1
|
||||
# A Link to the Past options:
|
||||
A Link to the Past:
|
||||
### Logic Section ###
|
||||
# Warning: overworld_glitches is not available and minor_glitches is only partially implemented on the door-rando version
|
||||
glitches_required: # Determine the logic required to complete the seed
|
||||
none: 50 # No glitches required
|
||||
minor_glitches: 0 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic
|
||||
|
@ -293,7 +292,7 @@ turtle_rock_medallion: # required medallion to open Turtle Rock front entrance
|
|||
boss_shuffle:
|
||||
none: 50 # Vanilla bosses
|
||||
basic: 0 # Existing bosses except Ganon and Agahnim are shuffled throughout dungeons
|
||||
normal: 0 # 3 bosses can occur twice
|
||||
full: 0 # 3 bosses can occur twice
|
||||
chaos: 0 # Any boss can appear any amount of times
|
||||
singularity: 0 # Picks a boss, tries to put it everywhere that works, if there's spaces remaining it picks a boss to fill those
|
||||
enemy_shuffle: # Randomize enemy placement
|
||||
|
@ -376,115 +375,7 @@ green_clock_time: # For all timer modes, the amount of time in minutes to gain o
|
|||
glitch_boots:
|
||||
on: 50 # Start with Pegasus Boots in any glitched logic mode that makes use of them
|
||||
off: 0
|
||||
# meta_ignore, linked_options and triggers work for any game
|
||||
meta_ignore: # Nullify options specified in the meta.yaml file. Adding an option here guarantees it will not occur in your seed, even if the .yaml file specifies it
|
||||
mode:
|
||||
- inverted # Never play inverted seeds
|
||||
retro:
|
||||
- on # Never play retro seeds
|
||||
swordless:
|
||||
- on # Never play a swordless seed
|
||||
linked_options:
|
||||
- name: crosskeys
|
||||
options: # These overwrite earlier options if the percentage chance triggers
|
||||
entrance_shuffle: crossed
|
||||
bigkey_shuffle: true
|
||||
compass_shuffle: true
|
||||
map_shuffle: true
|
||||
smallkey_shuffle: true
|
||||
percentage: 0 # Set this to the percentage chance you want crosskeys
|
||||
- name: localcrosskeys
|
||||
options: # These overwrite earlier options if the percentage chance triggers
|
||||
entrance_shuffle: crossed
|
||||
bigkey_shuffle: true
|
||||
compass_shuffle: true
|
||||
map_shuffle: true
|
||||
smallkey_shuffle: true
|
||||
local_items: # Forces keys to be local to your own world
|
||||
- "Small Keys"
|
||||
- "Big Keys"
|
||||
percentage: 0 # Set this to the percentage chance you want local crosskeys
|
||||
- name: enemizer
|
||||
options:
|
||||
boss_shuffle: # Subchances can be injected too, which then get rolled
|
||||
basic: 1
|
||||
full: 1
|
||||
chaos: 1
|
||||
singularity: 1
|
||||
enemy_damage:
|
||||
shuffled: 1
|
||||
random: 1
|
||||
enemy_health:
|
||||
easy: 1
|
||||
hard: 1
|
||||
expert: 1
|
||||
percentage: 0 # Set this to the percentage chance you want enemizer
|
||||
# triggers that replace options upon rolling certain options
|
||||
legacy_weapons: # this is not an actual option, just a set of weights to trigger from
|
||||
trigger_disabled: 50
|
||||
randomized: 0 # Swords are placed randomly throughout the world
|
||||
assured: 0 # Begin with a sword, the rest are placed randomly throughout the world
|
||||
vanilla: 0 # Swords are placed in vanilla locations in your own game (Uncle, Pyramid Fairy, Smiths, Pedestal)
|
||||
swordless: 0 # swordless mode
|
||||
triggers:
|
||||
# trigger block for legacy weapons mode, to enable these add weights to legacy_weapons
|
||||
- option_name: legacy_weapons
|
||||
option_result: randomized
|
||||
options:
|
||||
swordless: off
|
||||
- option_name: legacy_weapons
|
||||
option_result: assured
|
||||
options:
|
||||
swordless: off
|
||||
startinventory:
|
||||
Progressive Sword: 1
|
||||
- option_name: legacy_weapons
|
||||
option_result: vanilla
|
||||
options:
|
||||
swordless: off
|
||||
plando_items:
|
||||
- items:
|
||||
Progressive Sword: 4
|
||||
locations:
|
||||
- Master Sword Pedestal
|
||||
- Pyramid Fairy - Left
|
||||
- Blacksmith
|
||||
- Link's Uncle
|
||||
- option_name: legacy_weapons
|
||||
option_result: swordless
|
||||
options:
|
||||
swordless: on
|
||||
# end of legacy weapons block
|
||||
- option_name: enemy_damage # targets enemy_damage
|
||||
option_result: shuffled # if it rolls shuffled
|
||||
percentage: 0 # AND has a 0 percent chance (meaning this is default disabled, just to show how it works)
|
||||
options: # then inserts these options
|
||||
swordless: off
|
||||
### door rando only options (not supported at all yet on this branch) ###
|
||||
door_shuffle: # Only available if the host uses the doors branch, it is ignored otherwise
|
||||
vanilla: 50 # Everything should be like in vanilla
|
||||
basic: 0 # Dungeons are shuffled within themselves
|
||||
crossed: 0 # Dungeons are shuffled across each other
|
||||
# you can also define door shuffle seed, like so:
|
||||
crossed-1000: 0 # using this method, you can have the same dungeon layout as another player and share dungeon layout information.
|
||||
# however, other settings like intensity, universal keys, etc. may affect the shuffle result as well.
|
||||
crossed-group-myfriends: 0 # using this method, everyone with "group-myfriends" will share the same seed
|
||||
intensity: # Only available if the host uses the doors branch, it is ignored otherwise
|
||||
1: 50 # Shuffles normal doors and spiral staircases
|
||||
2: 0 # And shuffles open edges and straight staircases
|
||||
3: 0 # And shuffles dungeon lobbies
|
||||
random: 0 # Picks one of those at random
|
||||
key_drop_shuffle: # Only available if the host uses the doors branch, it is ignored otherwise
|
||||
on: 0 # Enables the small keys dropped by enemies or under pots, and the big key dropped by the Ball & Chain guard to be shuffled into the pool. This extends the number of checks to 249.
|
||||
off: 50
|
||||
experimental: # Only available if the host uses the doors branch, it is ignored otherwise
|
||||
on: 0 # Enables experimental features.
|
||||
off: 50
|
||||
debug: # Only available if the host uses the doors branch, it is ignored otherwise
|
||||
on: 0 # Enables debugging features. Currently, these are the Item collection counter. (overwrites total triforce pieces) and Castle Gate closed indicator.
|
||||
off: 50
|
||||
### end of door rando only options ###
|
||||
rom:
|
||||
# rom options section
|
||||
random_sprite_on_event: # An alternative to specifying randomonhit / randomonexit / etc... in sprite down below.
|
||||
enabled: # If enabled, sprite down below is ignored completely, (although it may become the sprite pool)
|
||||
on: 0
|
||||
|
@ -612,3 +503,102 @@ rom:
|
|||
dizzy: 0
|
||||
sick: 0
|
||||
puke: 0
|
||||
|
||||
# triggers that replace options upon rolling certain options
|
||||
legacy_weapons: # this is not an actual option, just a set of weights to trigger from
|
||||
trigger_disabled: 50
|
||||
randomized: 0 # Swords are placed randomly throughout the world
|
||||
assured: 0 # Begin with a sword, the rest are placed randomly throughout the world
|
||||
vanilla: 0 # Swords are placed in vanilla locations in your own game (Uncle, Pyramid Fairy, Smiths, Pedestal)
|
||||
swordless: 0 # swordless mode
|
||||
# meta_ignore, linked_options and triggers work for any game
|
||||
meta_ignore: # Nullify options specified in the meta.yaml file. Adding an option here guarantees it will not occur in your seed, even if the .yaml file specifies it
|
||||
mode:
|
||||
- inverted # Never play inverted seeds
|
||||
retro:
|
||||
- on # Never play retro seeds
|
||||
swordless:
|
||||
- on # Never play a swordless seed
|
||||
|
||||
linked_options:
|
||||
- name: crosskeys
|
||||
options: # These overwrite earlier options if the percentage chance triggers
|
||||
A Link to the Past:
|
||||
entrance_shuffle: crossed
|
||||
bigkey_shuffle: true
|
||||
compass_shuffle: true
|
||||
map_shuffle: true
|
||||
smallkey_shuffle: true
|
||||
percentage: 0 # Set this to the percentage chance you want crosskeys
|
||||
- name: localcrosskeys
|
||||
options: # These overwrite earlier options if the percentage chance triggers
|
||||
A Link to the Past:
|
||||
entrance_shuffle: crossed
|
||||
bigkey_shuffle: true
|
||||
compass_shuffle: true
|
||||
map_shuffle: true
|
||||
smallkey_shuffle: true
|
||||
local_items: # Forces keys to be local to your own world
|
||||
- "Small Keys"
|
||||
- "Big Keys"
|
||||
percentage: 0 # Set this to the percentage chance you want local crosskeys
|
||||
- name: enemizer
|
||||
options:
|
||||
A Link to the Past:
|
||||
boss_shuffle: # Subchances can be injected too, which then get rolled
|
||||
basic: 1
|
||||
full: 1
|
||||
chaos: 1
|
||||
singularity: 1
|
||||
enemy_damage:
|
||||
shuffled: 1
|
||||
random: 1
|
||||
enemy_health:
|
||||
easy: 1
|
||||
hard: 1
|
||||
expert: 1
|
||||
percentage: 0 # Set this to the percentage chance you want enemizer
|
||||
triggers:
|
||||
# trigger block for legacy weapons mode, to enable these add weights to legacy_weapons
|
||||
- option_name: legacy_weapons
|
||||
option_result: randomized
|
||||
option_category: A Link to the Past
|
||||
options:
|
||||
A Link to the Past:
|
||||
swordless: off
|
||||
- option_name: legacy_weapons
|
||||
option_result: assured
|
||||
option_category: A Link to the Past
|
||||
options:
|
||||
A Link to the Past:
|
||||
swordless: off
|
||||
start_inventory:
|
||||
Progressive Sword: 1
|
||||
- option_name: legacy_weapons
|
||||
option_result: vanilla
|
||||
option_category: A Link to the Past
|
||||
options:
|
||||
A Link to the Past:
|
||||
swordless: off
|
||||
plando_items:
|
||||
- items:
|
||||
Progressive Sword: 4
|
||||
locations:
|
||||
- Master Sword Pedestal
|
||||
- Pyramid Fairy - Left
|
||||
- Blacksmith
|
||||
- Link's Uncle
|
||||
- option_name: legacy_weapons
|
||||
option_result: swordless
|
||||
option_category: A Link to the Past
|
||||
options:
|
||||
A Link to the Past:
|
||||
swordless: on
|
||||
# end of legacy weapons block
|
||||
- option_name: enemy_damage # targets enemy_damage
|
||||
option_category: A Link to the Past
|
||||
option_result: shuffled # if it rolls shuffled
|
||||
percentage: 0 # AND has a 0 percent chance (meaning this is default disabled, just to show how it works)
|
||||
options: # then inserts these options
|
||||
A Link to the Past:
|
||||
swordless: off
|
|
@ -60,16 +60,17 @@ def generate_mod(world: MultiWorld, player: int):
|
|||
if location.address:
|
||||
locations.append((location.name, location.item.name, location.item.player, location.item.advancement))
|
||||
mod_name = f"AP-{world.seed_name}-P{player}-{world.player_names[player][0]}"
|
||||
tech_cost = {0: 0.1,
|
||||
tech_cost_scale = {0: 0.1,
|
||||
1: 0.25,
|
||||
2: 0.5,
|
||||
3: 1,
|
||||
4: 2,
|
||||
5: 5,
|
||||
6: 10}[world.tech_cost[player].value]
|
||||
|
||||
template_data = {"locations": locations, "player_names": player_names, "tech_table": tech_table,
|
||||
"mod_name": mod_name, "allowed_science_packs": world.max_science_pack[player].get_allowed_packs(),
|
||||
"tech_cost_scale": tech_cost, "custom_technologies": world.worlds[player].custom_technologies,
|
||||
"tech_cost_scale": tech_cost_scale, "custom_technologies": world.worlds[player].custom_technologies,
|
||||
"tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites[player],
|
||||
"rocket_recipe": rocket_recipes[world.max_science_pack[player].value],
|
||||
"slot_name": world.player_names[player][0], "seed_name": world.seed_name,
|
||||
|
|
|
@ -66,7 +66,7 @@ class CustomTechnology(Technology):
|
|||
def __init__(self, origin: Technology, world, allowed_packs: Set[str], player: int):
|
||||
ingredients = origin.ingredients & allowed_packs
|
||||
self.player = player
|
||||
if world.random_tech_ingredients[player]:
|
||||
if world.random_tech_ingredients[player] and origin.name not in world.worlds[player].static_nodes:
|
||||
ingredients = list(ingredients)
|
||||
ingredients.sort() # deterministic sample
|
||||
ingredients = world.random.sample(ingredients, world.random.randint(1, len(ingredients)))
|
||||
|
|
|
@ -9,11 +9,12 @@ from .Mod import generate_mod
|
|||
|
||||
class Factorio(World):
|
||||
game: str = "Factorio"
|
||||
static_nodes = {"automation", "logistics"}
|
||||
static_nodes = {"automation", "logistics", "rocket-silo"}
|
||||
|
||||
def generate_basic(self):
|
||||
victory_tech_names = get_rocket_requirements(
|
||||
frozenset(rocket_recipes[self.world.max_science_pack[self.player].value]))
|
||||
|
||||
for tech_name, tech_id in tech_table.items():
|
||||
tech_item = Item(tech_name, tech_name in advancement_technologies or tech_name in victory_tech_names,
|
||||
tech_id, self.player)
|
||||
|
|
Loading…
Reference in New Issue