Merge branch 'main' into main
This commit is contained in:
commit
ac915d00fc
|
@ -213,9 +213,8 @@ class MultiWorld():
|
|||
except KeyError as e:
|
||||
raise KeyError('No such dungeon %s for player %d' % (dungeonname, player)) from e
|
||||
|
||||
def get_all_state(self, keys=False) -> CollectionState:
|
||||
key = f"_all_state_{keys}"
|
||||
cached = getattr(self, key, None)
|
||||
def get_all_state(self) -> CollectionState:
|
||||
cached = getattr(self, "_all_state", None)
|
||||
if cached:
|
||||
return cached.copy()
|
||||
|
||||
|
@ -223,27 +222,12 @@ class MultiWorld():
|
|||
|
||||
for item in self.itempool:
|
||||
self.worlds[item.player].collect(ret, item)
|
||||
|
||||
if keys:
|
||||
for p in self.get_game_players("A Link to the Past"):
|
||||
world = self.worlds[p]
|
||||
from worlds.alttp.Items import ItemFactory
|
||||
for item in ItemFactory(
|
||||
['Small Key (Hyrule Castle)', 'Big Key (Eastern Palace)', 'Big Key (Desert Palace)',
|
||||
'Small Key (Desert Palace)', 'Big Key (Tower of Hera)', 'Small Key (Tower of Hera)',
|
||||
'Small Key (Agahnims Tower)', 'Small Key (Agahnims Tower)',
|
||||
'Big Key (Palace of Darkness)'] + ['Small Key (Palace of Darkness)'] * 6 + [
|
||||
'Big Key (Thieves Town)', 'Small Key (Thieves Town)', 'Big Key (Skull Woods)'] + [
|
||||
'Small Key (Skull Woods)'] * 3 + ['Big Key (Swamp Palace)',
|
||||
'Small Key (Swamp Palace)', 'Big Key (Ice Palace)'] + [
|
||||
'Small Key (Ice Palace)'] * 2 + ['Big Key (Misery Mire)', 'Big Key (Turtle Rock)',
|
||||
'Big Key (Ganons Tower)'] + [
|
||||
'Small Key (Misery Mire)'] * 3 + ['Small Key (Turtle Rock)'] * 4 + [
|
||||
'Small Key (Ganons Tower)'] * 4,
|
||||
p):
|
||||
world.collect(ret, item)
|
||||
from worlds.alttp.Dungeons import get_dungeon_item_pool
|
||||
for item in get_dungeon_item_pool(self):
|
||||
subworld = self.worlds[item.player]
|
||||
if item.name in subworld.dungeon_local_item_names:
|
||||
subworld.collect(ret, item)
|
||||
ret.sweep_for_events()
|
||||
setattr(self, key, ret)
|
||||
return ret
|
||||
|
||||
def get_items(self) -> list:
|
||||
|
|
12
Options.py
12
Options.py
|
@ -57,11 +57,12 @@ class Option(metaclass=AssembleOptions):
|
|||
"""For display purposes."""
|
||||
return self.get_option_name(self.value)
|
||||
|
||||
def get_option_name(self, value: typing.Any) -> str:
|
||||
if self.autodisplayname:
|
||||
return self.name_lookup[self.value].replace("_", " ").title()
|
||||
@classmethod
|
||||
def get_option_name(cls, value: typing.Any) -> str:
|
||||
if cls.autodisplayname:
|
||||
return cls.name_lookup[value].replace("_", " ").title()
|
||||
else:
|
||||
return self.name_lookup[self.value]
|
||||
return cls.name_lookup[value]
|
||||
|
||||
def __int__(self) -> int:
|
||||
return self.value
|
||||
|
@ -114,7 +115,8 @@ class Toggle(Option):
|
|||
def __int__(self):
|
||||
return int(self.value)
|
||||
|
||||
def get_option_name(self, value):
|
||||
@classmethod
|
||||
def get_option_name(cls, value):
|
||||
return ["No", "Yes"][int(value)]
|
||||
|
||||
class DefaultOnToggle(Toggle):
|
||||
|
|
|
@ -8,6 +8,7 @@ from pony.flask import Pony
|
|||
from flask import Flask, request, redirect, url_for, render_template, Response, session, abort, send_from_directory
|
||||
from flask_caching import Cache
|
||||
from flask_compress import Compress
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
|
||||
from .models import *
|
||||
|
||||
|
@ -81,54 +82,6 @@ def page_not_found(err):
|
|||
return render_template('404.html'), 404
|
||||
|
||||
|
||||
games_list = {
|
||||
"A Link to the Past": ("The Legend of Zelda: A Link to the Past",
|
||||
"""
|
||||
The Legend of Zelda: A Link to the Past is an action/adventure game. Take on the role of
|
||||
Link, a boy who is destined to save the land of Hyrule. Delve through three palaces and nine
|
||||
dungeons on your quest to rescue the descendents of the seven wise men and defeat the evil
|
||||
Ganon!"""),
|
||||
"Factorio": ("Factorio",
|
||||
"""
|
||||
Factorio is a game about automation. You play as an engineer who has crash landed on the planet
|
||||
Nauvis, an inhospitable world filled with dangerous creatures called biters. Build a factory,
|
||||
research new technologies, and become more efficient in your quest to build a rocket and return home.
|
||||
"""),
|
||||
"Minecraft": ("Minecraft",
|
||||
"""
|
||||
Minecraft is a game about creativity. In a world made entirely of cubes, you explore, discover, mine,
|
||||
craft, and try not to explode. Delve deep into the earth and discover abandoned mines, ancient
|
||||
structures, and materials to create a portal to another world. Defeat the Ender Dragon, and claim
|
||||
victory!"""),
|
||||
"Subnautica": ("Subnautica",
|
||||
"""
|
||||
Subnautica is an undersea exploration game. Stranded on an alien world, you become infected by
|
||||
an unknown bacteria. The planet's automatic quarantine will shoot you down if you try to leave.
|
||||
You must find a cure for yourself, build an escape rocket, and leave the planet.
|
||||
"""),
|
||||
"Ocarina of Time": ("The Legend of Zelda: Ocarina of Time",
|
||||
"""
|
||||
The Legend of Zelda: Ocarina of Time was the first three dimensional Zelda game. Journey as
|
||||
Link as he quests to fulfil his destiny. Journey across Hyrule and defeat the evil masters of
|
||||
corrupted temples or seek out the pieces of the Triforce. Defeat the evil Ganondorf to become
|
||||
the Hero of Time and save Hyrule!
|
||||
"""),
|
||||
"Super Metroid": ("Super Metroid",
|
||||
"""
|
||||
Samus is back in her first 16 bit adventure! Space pirates have attacked Ceres station and stolen
|
||||
the last living Metroid. Go to planet Zebes and search out the abilities you will need to power
|
||||
up your suit and defeat the villainous leader of the space pirates, Mother Brain.
|
||||
"""),
|
||||
"Risk of Rain 2": ("Risk of Rain 2",
|
||||
"""
|
||||
Escape a chaotic alien planet by fighting through hordes of frenzied monsters – with your friends
|
||||
, or on your own. Combine loot in surprising ways and master each character until you become the
|
||||
havoc you feared upon your first crash landing.
|
||||
""")
|
||||
# "Ori and the Blind Forest": ("Ori and the Blind Forest", "Coming Soon™"),
|
||||
# "Hollow Knight": ("Hollow Knight", "Coming Soon™"),
|
||||
}
|
||||
|
||||
|
||||
# Player settings pages
|
||||
@app.route('/games/<string:game>/player-settings')
|
||||
|
@ -151,7 +104,11 @@ def game_page(game):
|
|||
# List of supported games
|
||||
@app.route('/games')
|
||||
def games():
|
||||
return render_template("games/games.html", games_list=games_list)
|
||||
worlds = {}
|
||||
for game, world in AutoWorldRegister.world_types.items():
|
||||
if not world.hidden:
|
||||
worlds[game] = world.__doc__ if world.__doc__ else "No description provided."
|
||||
return render_template("games/games.html", worlds=worlds)
|
||||
|
||||
|
||||
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from flask import send_file, Response
|
||||
from flask import send_file, Response, render_template
|
||||
from pony.orm import select
|
||||
|
||||
from Patch import update_patch_data
|
||||
from WebHostLib import app, Slot, Room, Seed
|
||||
from WebHostLib import app, Slot, Room, Seed, cache
|
||||
import zipfile
|
||||
|
||||
@app.route("/dl_patch/<suuid:room_id>/<int:patch_id>")
|
||||
|
@ -68,4 +68,14 @@ def download_slot_file(room_id, player_id: int):
|
|||
fname = name.rsplit("/", 1)[0]+".zip"
|
||||
else:
|
||||
return "Game download not supported."
|
||||
return send_file(io.BytesIO(slot_data.data), as_attachment=True, attachment_filename=fname)
|
||||
return send_file(io.BytesIO(slot_data.data), as_attachment=True, attachment_filename=fname)
|
||||
|
||||
@app.route("/templates")
|
||||
@cache.cached()
|
||||
def list_yaml_templates():
|
||||
files = []
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
for world_name, world in AutoWorldRegister.world_types.items():
|
||||
if not world.hidden:
|
||||
files.append(world_name)
|
||||
return render_template("templates.html", files=files)
|
|
@ -10,9 +10,18 @@ target_folder = os.path.join("WebHostLib", "static", "generated")
|
|||
|
||||
|
||||
def create():
|
||||
def dictify_range(option):
|
||||
data = {option.range_start: 0, option.range_end: 0, "random": 0, "random-low": 0, "random-high": 0,
|
||||
option.default: 50}
|
||||
notes = {
|
||||
option.range_start: "minimum value",
|
||||
option.range_end: "maximum value"
|
||||
}
|
||||
return data, notes
|
||||
for game_name, world in AutoWorldRegister.world_types.items():
|
||||
res = Template(open(os.path.join("WebHostLib", "templates", "options.yaml")).read()).render(
|
||||
options=world.options, __version__=__version__, game=game_name, yaml_dump=yaml.dump
|
||||
options=world.options, __version__=__version__, game=game_name, yaml_dump=yaml.dump,
|
||||
dictify_range=dictify_range
|
||||
)
|
||||
|
||||
with open(os.path.join(target_folder, game_name + ".yaml"), "w") as f:
|
||||
|
@ -39,7 +48,7 @@ def create():
|
|||
|
||||
for sub_option_name, sub_option_id in option.options.items():
|
||||
this_option["options"].append({
|
||||
"name": sub_option_name,
|
||||
"name": option.get_option_name(sub_option_id),
|
||||
"value": sub_option_name,
|
||||
})
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
{% include 'header/grassHeader.html' %}
|
||||
<div id="games">
|
||||
<h1>Currently Supported Games</h1>
|
||||
{% for game, (display_name, description) in games_list.items() %}
|
||||
<h3><a href="{{ url_for("game_page", game=game) }}">{{ display_name}}</a></h3>
|
||||
<p>{{ description}}</p>
|
||||
{% for game, description in worlds.items() %}
|
||||
<h3><a href="{{ url_for("game_page", game=game) }}">{{ game }}</a></h3>
|
||||
<p>{{ description }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
# http://www.yamllint.com/
|
||||
|
||||
description: Default {{ game }} Template # Used to describe your yaml. Useful if you have multiple files
|
||||
name: YourName{number} # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit
|
||||
# Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit
|
||||
name: YourName{number}
|
||||
#{player} will be replaced with the player's slot number.
|
||||
#{PLAYER} will be replaced with the player's slot number if that slot number is greater than 1.
|
||||
#{number} will be replaced with the counter value of the name.
|
||||
|
@ -51,16 +52,18 @@ progression_balancing:
|
|||
# - "Progressive Weapons"
|
||||
# exclude_locations: # Force certain locations to never contain progression items, and always be filled with junk.
|
||||
# - "Master Sword Pedestal"
|
||||
{%- macro range_option(option) %}
|
||||
# you can add additional values between minimum and maximum
|
||||
{%- set data, notes = dictify_range(option) %}
|
||||
{%- for entry, default in data.items() %}
|
||||
{{ entry }}: {{ default }}{% if notes[entry] %} # {{ notes[entry] }}{% endif %}
|
||||
{%- endfor -%}
|
||||
{% endmacro %}
|
||||
{{ game }}:
|
||||
{%- for option_key, option in options.items() %}
|
||||
{{ option_key }}:{% if option.__doc__ %} # {{ option.__doc__ | replace('\n', '\n#') | indent(4, first=False) }}{% endif %}
|
||||
{%- if option.range_start is defined %}
|
||||
# you can add additional values between minimum and maximum
|
||||
{{ option.range_start }}: 0 # minimum value
|
||||
{{ option.range_end }}: 0 # maximum value
|
||||
random: 50
|
||||
random-low: 0
|
||||
random-high: 0
|
||||
{{- range_option(option) -}}
|
||||
{%- elif option.options -%}
|
||||
{%- for suboption_option_id, sub_option_name in option.name_lookup.items() %}
|
||||
{{ sub_option_name }}: {% if suboption_option_id == option.default %}50{% else %}0{% endif %}
|
||||
|
@ -68,4 +71,5 @@ progression_balancing:
|
|||
{%- else %}
|
||||
{{ yaml_dump(option.default) | indent(4, first=False) }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor %}
|
||||
{% if not options %}{}{% endif %}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{% extends 'pageWrapper.html' %}
|
||||
|
||||
{% block head %}
|
||||
{% include 'header/grassHeader.html' %}
|
||||
<title>Option Templates (YAML)</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/markdown.css") }}" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
|
||||
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
|
||||
crossorigin="anonymous"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div>
|
||||
<h1>Option Templates (YAML)</h1>
|
||||
<ul>
|
||||
{% for file in files %}
|
||||
<li><a href="{{ url_for('static', filename="generated/"+file+".yaml") }}">{{ file }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -157,6 +157,8 @@ def fill_dungeons_restrictive(autoworld, world):
|
|||
in_dungeon_items.sort(
|
||||
key=lambda item: sort_order.get(item.type, 1) +
|
||||
(5 if (item.player, item.name) in dungeon_specific else 0))
|
||||
for item in in_dungeon_items:
|
||||
all_state_base.remove(item)
|
||||
fill_restrictive(world, all_state_base, locations, in_dungeon_items, True, True)
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# ToDo: With shuffle_ganon option, prevent gtower from linking to an exit only location through a 2 entrance cave.
|
||||
from collections import defaultdict
|
||||
from worlds.alttp.OverworldGlitchRules import overworld_glitch_connections
|
||||
from worlds.alttp.UnderworldGlitchRules import underworld_glitch_connections
|
||||
|
||||
def link_entrances(world, player):
|
||||
|
@ -1066,9 +1067,11 @@ def link_entrances(world, player):
|
|||
raise NotImplementedError(
|
||||
f'{world.shuffle[player]} Shuffling not supported yet. Player {world.get_player_name(player)}')
|
||||
|
||||
# mandatory hybrid major glitches connections
|
||||
if world.logic[player] in ['hybridglitches', 'nologic']:
|
||||
underworld_glitch_connections(world, player)
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
overworld_glitch_connections(world, player)
|
||||
# mandatory hybrid major glitches connections
|
||||
if world.logic[player] in ['hybridglitches', 'nologic']:
|
||||
underworld_glitch_connections(world, player)
|
||||
|
||||
# check for swamp palace fix
|
||||
if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Palace (Entrance)':
|
||||
|
@ -1771,9 +1774,11 @@ def link_inverted_entrances(world, player):
|
|||
else:
|
||||
raise NotImplementedError('Shuffling not supported yet')
|
||||
|
||||
# mandatory hybrid major glitches connections
|
||||
if world.logic[player] in ['hybridglitches', 'nologic']:
|
||||
underworld_glitch_connections(world, player)
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
overworld_glitch_connections(world, player)
|
||||
# mandatory hybrid major glitches connections
|
||||
if world.logic[player] in ['hybridglitches', 'nologic']:
|
||||
underworld_glitch_connections(world, player)
|
||||
|
||||
# patch swamp drain
|
||||
if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Palace (Entrance)':
|
||||
|
|
|
@ -235,24 +235,41 @@ def no_logic_rules(world, player):
|
|||
create_no_logic_connections(player, world, get_mirror_offset_spots_lw(player))
|
||||
|
||||
|
||||
def overworld_glitch_connections(world, player):
|
||||
|
||||
# Boots-accessible locations.
|
||||
create_owg_connections(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'))
|
||||
create_owg_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player))
|
||||
|
||||
# Glitched speed drops.
|
||||
create_owg_connections(player, world, get_glitched_speed_drops_dw(world.mode[player] == 'inverted'))
|
||||
|
||||
# Mirror clip spots.
|
||||
if world.mode[player] != 'inverted':
|
||||
create_owg_connections(player, world, get_mirror_clip_spots_dw())
|
||||
create_owg_connections(player, world, get_mirror_offset_spots_dw())
|
||||
else:
|
||||
create_owg_connections(player, world, get_mirror_offset_spots_lw(player))
|
||||
|
||||
|
||||
def overworld_glitches_rules(world, player):
|
||||
|
||||
# Boots-accessible locations.
|
||||
create_owg_connections(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'), lambda state: state.can_boots_clip_lw(player))
|
||||
create_owg_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player), lambda state: state.can_boots_clip_dw(player))
|
||||
set_owg_connection_rules(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'), lambda state: state.can_boots_clip_lw(player))
|
||||
set_owg_connection_rules(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player), lambda state: state.can_boots_clip_dw(player))
|
||||
|
||||
# Glitched speed drops.
|
||||
create_owg_connections(player, world, get_glitched_speed_drops_dw(world.mode[player] == 'inverted'), lambda state: state.can_get_glitched_speed_dw(player))
|
||||
set_owg_connection_rules(player, world, get_glitched_speed_drops_dw(world.mode[player] == 'inverted'), lambda state: state.can_get_glitched_speed_dw(player))
|
||||
# Dark Death Mountain Ledge Clip Spot also accessible with mirror.
|
||||
if world.mode[player] != 'inverted':
|
||||
add_alternate_rule(world.get_entrance('Dark Death Mountain Ledge Clip Spot', player), lambda state: state.has('Magic Mirror', player))
|
||||
|
||||
# Mirror clip spots.
|
||||
if world.mode[player] != 'inverted':
|
||||
create_owg_connections(player, world, get_mirror_clip_spots_dw(), lambda state: state.has('Magic Mirror', player))
|
||||
create_owg_connections(player, world, get_mirror_offset_spots_dw(), lambda state: state.has('Magic Mirror', player) and state.can_boots_clip_lw(player))
|
||||
set_owg_connection_rules(player, world, get_mirror_clip_spots_dw(), lambda state: state.has('Magic Mirror', player))
|
||||
set_owg_connection_rules(player, world, get_mirror_offset_spots_dw(), lambda state: state.has('Magic Mirror', player) and state.can_boots_clip_lw(player))
|
||||
else:
|
||||
create_owg_connections(player, world, get_mirror_offset_spots_lw(player), lambda state: state.has('Magic Mirror', player) and state.can_boots_clip_dw(player))
|
||||
set_owg_connection_rules(player, world, get_mirror_offset_spots_lw(player), lambda state: state.has('Magic Mirror', player) and state.can_boots_clip_dw(player))
|
||||
|
||||
# Regions that require the boots and some other stuff.
|
||||
if world.mode[player] != 'inverted':
|
||||
|
@ -282,12 +299,16 @@ def create_no_logic_connections(player, world, connections):
|
|||
parent.exits.append(connection)
|
||||
connection.connect(target)
|
||||
|
||||
def create_owg_connections(player, world, connections, default_rule):
|
||||
def create_owg_connections(player, world, connections):
|
||||
for entrance, parent_region, target_region, *rule_override in connections:
|
||||
parent = world.get_region(parent_region, player)
|
||||
target = world.get_region(target_region, player)
|
||||
connection = Entrance(player, entrance, parent)
|
||||
parent.exits.append(connection)
|
||||
connection.connect(target)
|
||||
|
||||
def set_owg_connection_rules(player, world, connections, default_rule):
|
||||
for entrance, _, _, *rule_override in connections:
|
||||
connection = world.get_entrance(entrance, player)
|
||||
rule = rule_override[0] if len(rule_override) > 0 else default_rule
|
||||
connection.access_rule = rule
|
||||
|
|
|
@ -853,7 +853,9 @@ def set_trock_key_rules(world, player):
|
|||
for entrance in ['Turtle Rock Dark Room Staircase', 'Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)', 'Turtle Rock Pokey Room', 'Turtle Rock Big Key Door']:
|
||||
set_rule(world.get_entrance(entrance, player), lambda state: False)
|
||||
|
||||
all_state = world.get_all_state(True)
|
||||
all_state = world.get_all_state()
|
||||
all_state.reachable_regions[player] = set() # wipe reachable regions so that the locked doors actually work
|
||||
all_state.stale[player] = True
|
||||
|
||||
# Check if each of the four main regions of the dungoen can be reached. The previous code section prevents key-costing moves within the dungeon.
|
||||
can_reach_back = all_state.can_reach(world.get_region('Turtle Rock (Eye Bridge)', player)) if world.can_access_trock_eyebridge[player] is None else world.can_access_trock_eyebridge[player]
|
||||
|
|
|
@ -24,6 +24,12 @@ lttp_logger = logging.getLogger("A Link to the Past")
|
|||
|
||||
|
||||
class ALTTPWorld(World):
|
||||
"""
|
||||
The Legend of Zelda: A Link to the Past is an action/adventure game. Take on the role of
|
||||
Link, a boy who is destined to save the land of Hyrule. Delve through three palaces and nine
|
||||
dungeons on your quest to rescue the descendents of the seven wise men and defeat the evil
|
||||
Ganon!
|
||||
"""
|
||||
game: str = "A Link to the Past"
|
||||
options = alttp_options
|
||||
topology_present = True
|
||||
|
@ -192,8 +198,8 @@ class ALTTPWorld(World):
|
|||
elif 'Bow' in item_name:
|
||||
if state.has('Silver Bow', item.player):
|
||||
return
|
||||
elif state.has('Bow', item.player) and (self.world.difficulty_requirements[item.player].progressive_bow_limit >= 2
|
||||
or self.world.logic[item.player] == 'noglitches'
|
||||
elif state.has('Bow', item.player) and (self.world.difficulty_requirements[item.player].progressive_bow_limit >= 2
|
||||
or self.world.logic[item.player] == 'noglitches'
|
||||
or self.world.swordless[item.player]): # modes where silver bow is always required for ganon
|
||||
return 'Silver Bow'
|
||||
elif self.world.difficulty_requirements[item.player].progressive_bow_limit >= 1:
|
||||
|
@ -206,7 +212,7 @@ class ALTTPWorld(World):
|
|||
attempts = 5
|
||||
world = self.world
|
||||
player = self.player
|
||||
all_state = world.get_all_state(keys=True)
|
||||
all_state = world.get_all_state()
|
||||
crystals = [self.create_item(name) for name in ['Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5', 'Crystal 6']]
|
||||
crystal_locations = [world.get_location('Turtle Rock - Prize', player),
|
||||
world.get_location('Eastern Palace - Prize', player),
|
||||
|
@ -401,4 +407,4 @@ class ALttPLogic(LogicMixin):
|
|||
return True
|
||||
if self.world.smallkey_shuffle[player] == smallkey_shuffle.option_universal:
|
||||
return self.can_buy_unlimited('Small Key (Universal)', player)
|
||||
return self.prog_items[item, player] >= count
|
||||
return self.prog_items[item, player] >= count
|
||||
|
|
|
@ -24,6 +24,11 @@ all_items["Evolution Trap"] = factorio_base_id - 2
|
|||
|
||||
|
||||
class Factorio(World):
|
||||
"""
|
||||
Factorio is a game about automation. You play as an engineer who has crash landed on the planet
|
||||
Nauvis, an inhospitable world filled with dangerous creatures called biters. Build a factory,
|
||||
research new technologies, and become more efficient in your quest to build a rocket and return home.
|
||||
"""
|
||||
game: str = "Factorio"
|
||||
static_nodes = {"automation", "logistics", "rocket-silo"}
|
||||
custom_recipes = {}
|
||||
|
|
|
@ -16,6 +16,12 @@ from ..AutoWorld import World
|
|||
client_version = 6
|
||||
|
||||
class MinecraftWorld(World):
|
||||
"""
|
||||
Minecraft is a game about creativity. In a world made entirely of cubes, you explore, discover, mine,
|
||||
craft, and try not to explode. Delve deep into the earth and discover abandoned mines, ancient
|
||||
structures, and materials to create a portal to another world. Defeat the Ender Dragon, and claim
|
||||
victory!
|
||||
"""
|
||||
game: str = "Minecraft"
|
||||
options = minecraft_options
|
||||
topology_present = True
|
||||
|
@ -47,7 +53,7 @@ class MinecraftWorld(World):
|
|||
itempool = []
|
||||
junk_pool = junk_weights.copy()
|
||||
# Add all required progression items
|
||||
for (name, num) in required_items.items():
|
||||
for (name, num) in required_items.items():
|
||||
itempool += [name] * num
|
||||
# Add structure compasses if desired
|
||||
if self.world.structure_compasses[self.player]:
|
||||
|
@ -85,9 +91,9 @@ class MinecraftWorld(World):
|
|||
def MCRegion(region_name: str, exits=[]):
|
||||
ret = Region(region_name, None, region_name, self.player, self.world)
|
||||
ret.locations = [MinecraftAdvancement(self.player, loc_name, loc_data.id, ret)
|
||||
for loc_name, loc_data in advancement_table.items()
|
||||
for loc_name, loc_data in advancement_table.items()
|
||||
if loc_data.region == region_name]
|
||||
for exit in exits:
|
||||
for exit in exits:
|
||||
ret.exits.append(Entrance(self.player, exit, ret))
|
||||
return ret
|
||||
|
||||
|
@ -100,7 +106,7 @@ class MinecraftWorld(World):
|
|||
with open(os.path.join(output_directory, filename), 'wb') as f:
|
||||
f.write(b64encode(bytes(json.dumps(data), 'utf-8')))
|
||||
|
||||
def fill_slot_data(self):
|
||||
def fill_slot_data(self):
|
||||
slot_data = self._get_mc_data()
|
||||
for option_name in minecraft_options:
|
||||
option = getattr(self.world, option_name)[self.player]
|
||||
|
@ -115,7 +121,7 @@ class MinecraftWorld(World):
|
|||
item.never_exclude = True
|
||||
return item
|
||||
|
||||
def mc_update_output(raw_data, server, port):
|
||||
def mc_update_output(raw_data, server, port):
|
||||
data = json.loads(b64decode(raw_data))
|
||||
data['server'] = server
|
||||
data['port'] = port
|
||||
|
|
|
@ -15,6 +15,11 @@ from ..AutoWorld import World
|
|||
|
||||
|
||||
class SubnauticaWorld(World):
|
||||
"""
|
||||
Subnautica is an undersea exploration game. Stranded on an alien world, you become infected by
|
||||
an unknown bacteria. The planet's automatic quarantine will shoot you down if you try to leave.
|
||||
You must find a cure for yourself, build an escape rocket, and leave the planet.
|
||||
"""
|
||||
game: str = "Subnautica"
|
||||
|
||||
item_name_to_id = items_lookup_name_to_id
|
||||
|
@ -53,7 +58,7 @@ class SubnauticaWorld(World):
|
|||
pass
|
||||
|
||||
|
||||
def fill_slot_data(self):
|
||||
def fill_slot_data(self):
|
||||
slot_data = {}
|
||||
return slot_data
|
||||
|
||||
|
|
Loading…
Reference in New Issue