mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-25 01:53:23 -07:00
Merge branch 'main' into archipidle
This commit is contained in:
18
Generate.py
18
Generate.py
@@ -21,7 +21,6 @@ from BaseClasses import seeddigits, get_seed, PlandoOptions
|
||||
from Main import main as ERmain
|
||||
from settings import get_settings
|
||||
from Utils import parse_yamls, version_tuple, __version__, tuplize_version
|
||||
from worlds.alttp import Options as LttPOptions
|
||||
from worlds.alttp.EntranceRandomizer import parse_arguments
|
||||
from worlds.alttp.Text import TextTable
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
@@ -35,8 +34,8 @@ def mystery_argparse():
|
||||
|
||||
parser = argparse.ArgumentParser(description="CMD Generation Interface, defaults come from host.yaml.")
|
||||
parser.add_argument('--weights_file_path', default=defaults.weights_file_path,
|
||||
help='Path to the weights file to use for rolling game settings, urls are also valid')
|
||||
parser.add_argument('--samesettings', help='Rolls settings per weights file rather than per player',
|
||||
help='Path to the weights file to use for rolling game options, urls are also valid')
|
||||
parser.add_argument('--sameoptions', help='Rolls options per weights file rather than per player',
|
||||
action='store_true')
|
||||
parser.add_argument('--player_files_path', default=defaults.player_files_path,
|
||||
help="Input directory for player files.")
|
||||
@@ -104,8 +103,8 @@ def main(args=None, callback=ERmain):
|
||||
del(meta_weights["meta_description"])
|
||||
except Exception as e:
|
||||
raise ValueError("No meta description found for meta.yaml. Unable to verify.") from e
|
||||
if args.samesettings:
|
||||
raise Exception("Cannot mix --samesettings with --meta")
|
||||
if args.sameoptions:
|
||||
raise Exception("Cannot mix --sameoptions with --meta")
|
||||
else:
|
||||
meta_weights = None
|
||||
player_id = 1
|
||||
@@ -157,7 +156,7 @@ def main(args=None, callback=ERmain):
|
||||
erargs.skip_output = args.skip_output
|
||||
|
||||
settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \
|
||||
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.samesettings else None)
|
||||
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None)
|
||||
for fname, yamls in weights_cache.items()}
|
||||
|
||||
if meta_weights:
|
||||
@@ -311,13 +310,6 @@ def handle_name(name: str, player: int, name_counter: Counter):
|
||||
return new_name
|
||||
|
||||
|
||||
def prefer_int(input_data: str) -> Union[str, int]:
|
||||
try:
|
||||
return int(input_data)
|
||||
except:
|
||||
return input_data
|
||||
|
||||
|
||||
def roll_percentage(percentage: Union[int, float]) -> bool:
|
||||
"""Roll a percentage chance.
|
||||
percentage is expected to be in range [0, 100]"""
|
||||
|
||||
@@ -6,6 +6,7 @@ import multiprocessing
|
||||
import threading
|
||||
import time
|
||||
import typing
|
||||
from uuid import UUID
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
from pony.orm import db_session, select, commit
|
||||
@@ -62,6 +63,16 @@ def autohost(config: dict):
|
||||
def keep_running():
|
||||
try:
|
||||
with Locker("autohost"):
|
||||
# delete unowned user-content
|
||||
with db_session:
|
||||
# >>> bool(uuid.UUID(int=0))
|
||||
# True
|
||||
rooms = Room.select(lambda room: room.owner == UUID(int=0)).delete(bulk=True)
|
||||
seeds = Seed.select(lambda seed: seed.owner == UUID(int=0) and not seed.rooms).delete(bulk=True)
|
||||
slots = Slot.select(lambda slot: not slot.seed).delete(bulk=True)
|
||||
# Command gets deleted by ponyorm Cascade Delete, as Room is Required
|
||||
if rooms or seeds or slots:
|
||||
logging.info(f"{rooms} Rooms, {seeds} Seeds and {slots} Slots have been deleted.")
|
||||
run_guardian()
|
||||
while 1:
|
||||
time.sleep(0.1)
|
||||
@@ -191,6 +202,6 @@ def run_guardian():
|
||||
guardian = threading.Thread(name="Guardian", target=guard)
|
||||
|
||||
|
||||
from .models import Room, Generation, STATE_QUEUED, STATE_STARTED, STATE_ERROR, db, Seed
|
||||
from .models import Room, Generation, STATE_QUEUED, STATE_STARTED, STATE_ERROR, db, Seed, Slot
|
||||
from .customserver import run_server_process, get_static_server_data
|
||||
from .generate import gen_game
|
||||
|
||||
@@ -49,12 +49,6 @@ def weighted_options():
|
||||
return render_template("weighted-options.html")
|
||||
|
||||
|
||||
# TODO for back compat. remove around 0.4.5
|
||||
@app.route("/games/<string:game>/player-settings")
|
||||
def player_settings(game: str):
|
||||
return redirect(url_for("player_options", game=game), 301)
|
||||
|
||||
|
||||
# Player options pages
|
||||
@app.route("/games/<string:game>/player-options")
|
||||
@cache.cached()
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<th class="center">Players</th>
|
||||
<th>Created (UTC)</th>
|
||||
<th>Last Activity (UTC)</th>
|
||||
<th>Mark for deletion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -35,6 +36,7 @@
|
||||
<td>{{ room.seed.slots|length }}</td>
|
||||
<td>{{ room.creation_time.strftime("%Y-%m-%d %H:%M") }}</td>
|
||||
<td>{{ room.last_activity.strftime("%Y-%m-%d %H:%M") }}</td>
|
||||
<td><a href="{{ url_for("disown_room", room=room.id) }}">Delete next maintenance.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -51,6 +53,7 @@
|
||||
<th>Seed</th>
|
||||
<th class="center">Players</th>
|
||||
<th>Created (UTC)</th>
|
||||
<th>Mark for deletion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -60,6 +63,7 @@
|
||||
<td>{% if seed.multidata %}{{ seed.slots|length }}{% else %}1{% endif %}
|
||||
</td>
|
||||
<td>{{ seed.creation_time.strftime("%Y-%m-%d %H:%M") }}</td>
|
||||
<td><a href="{{ url_for("disown_seed", seed=seed.id) }}">Delete next maintenance.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -7,7 +7,7 @@ import zipfile
|
||||
import zlib
|
||||
|
||||
from io import BytesIO
|
||||
from flask import request, flash, redirect, url_for, session, render_template
|
||||
from flask import request, flash, redirect, url_for, session, render_template, abort
|
||||
from markupsafe import Markup
|
||||
from pony.orm import commit, flush, select, rollback
|
||||
from pony.orm.core import TransactionIntegrityError
|
||||
@@ -219,3 +219,29 @@ def user_content():
|
||||
rooms = select(room for room in Room if room.owner == session["_id"])
|
||||
seeds = select(seed for seed in Seed if seed.owner == session["_id"])
|
||||
return render_template("userContent.html", rooms=rooms, seeds=seeds)
|
||||
|
||||
|
||||
@app.route("/disown_seed/<suuid:seed>", methods=["GET"])
|
||||
def disown_seed(seed):
|
||||
seed = Seed.get(id=seed)
|
||||
if not seed:
|
||||
return abort(404)
|
||||
if seed.owner != session["_id"]:
|
||||
return abort(403)
|
||||
|
||||
seed.owner = 0
|
||||
|
||||
return redirect(url_for("user_content"))
|
||||
|
||||
|
||||
@app.route("/disown_room/<suuid:room>", methods=["GET"])
|
||||
def disown_room(room):
|
||||
room = Room.get(id=room)
|
||||
if not room:
|
||||
return abort(404)
|
||||
if room.owner != session["_id"]:
|
||||
return abort(403)
|
||||
|
||||
room.owner = 0
|
||||
|
||||
return redirect(url_for("user_content"))
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
# Archipelago Settings API
|
||||
|
||||
The settings API describes how to use installation-wide config and let the user configure them, like paths, etc. using
|
||||
host.yaml. For the player settings / player yamls see [options api.md](options api.md).
|
||||
host.yaml. For the player options / player yamls see [options api.md](options api.md).
|
||||
|
||||
The settings API replaces `Utils.get_options()` and `Utils.get_default_options()`
|
||||
as well as the predefined `host.yaml` in the repository.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
Application settings / host.yaml interface using type hints.
|
||||
This is different from player settings.
|
||||
This is different from player options.
|
||||
"""
|
||||
|
||||
import os.path
|
||||
|
||||
@@ -43,7 +43,7 @@ an experience customized for their taste, and different players in the same mult
|
||||
|
||||
You can generate a yaml or download a template by visiting the [Adventure Options Page](/games/Adventure/player-options)
|
||||
|
||||
### What are recommended settings to tweak for beginners to the rando?
|
||||
### What are recommended options to tweak for beginners to the rando?
|
||||
Setting difficulty_switch_a and lowering the dragons' speeds makes the dragons easier to avoid. Adding Chalice to
|
||||
local_items guarantees you'll visit at least one of the interesting castles, as it can only be placed in a castle or
|
||||
the credits room.
|
||||
|
||||
@@ -42,7 +42,7 @@ une expérience personnalisée à leur goût, et différents joueurs dans le mê
|
||||
|
||||
### Où puis-je obtenir un fichier YAML ?
|
||||
|
||||
Vous pouvez générer un yaml ou télécharger un modèle en visitant la [page des paramètres d'aventure](/games/Adventure/player-settings)
|
||||
Vous pouvez générer un yaml ou télécharger un modèle en visitant la [page des paramètres d'aventure](/games/Adventure/player-options)
|
||||
|
||||
### Quels sont les paramètres recommandés pour s'initier à la rando ?
|
||||
Régler la difficulty_switch_a et réduire la vitesse des dragons rend les dragons plus faciles à éviter. Ajouter Calice à
|
||||
@@ -72,4 +72,4 @@ configuré pour le faire automatiquement.
|
||||
Pour connecter le client au multiserveur, mettez simplement `<adresse>:<port>` dans le champ de texte en haut et appuyez sur Entrée (si le
|
||||
le serveur utilise un mot de passe, saisissez dans le champ de texte inférieur `/connect <adresse> :<port> [mot de passe]`)
|
||||
|
||||
Appuyez sur Réinitialiser et commencez à jouer
|
||||
Appuyez sur Réinitialiser et commencez à jouer
|
||||
|
||||
@@ -4,7 +4,7 @@ import Utils
|
||||
import worlds.Files
|
||||
|
||||
LTTPJPN10HASH: str = "03a63945398191337e896e5771f77173"
|
||||
RANDOMIZERBASEHASH: str = "35d010bc148e0ea0ee68e81e330223f1"
|
||||
RANDOMIZERBASEHASH: str = "8704fb9b9fa4fad52d4d2f9a95fb5360"
|
||||
ROM_PLAYER_LIMIT: int = 255
|
||||
|
||||
import io
|
||||
|
||||
@@ -345,42 +345,43 @@ class ALTTPWorld(World):
|
||||
|
||||
def create_regions(self):
|
||||
player = self.player
|
||||
world = self.multiworld
|
||||
multiworld = self.multiworld
|
||||
|
||||
if world.mode[player] != 'inverted':
|
||||
create_regions(world, player)
|
||||
if multiworld.mode[player] != 'inverted':
|
||||
create_regions(multiworld, player)
|
||||
else:
|
||||
create_inverted_regions(world, player)
|
||||
create_shops(world, player)
|
||||
create_inverted_regions(multiworld, player)
|
||||
create_shops(multiworld, player)
|
||||
self.create_dungeons()
|
||||
|
||||
if world.glitches_required[player] not in ["no_glitches", "minor_glitches"] and world.entrance_shuffle[player] in \
|
||||
{"vanilla", "dungeons_simple", "dungeons_full", "simple", "restricted", "full"}:
|
||||
world.fix_fake_world[player] = False
|
||||
if (multiworld.glitches_required[player] not in ["no_glitches", "minor_glitches"] and
|
||||
multiworld.entrance_shuffle[player] in [
|
||||
"vanilla", "dungeons_simple", "dungeons_full", "simple", "restricted", "full"]):
|
||||
multiworld.fix_fake_world[player] = False
|
||||
|
||||
# seeded entrance shuffle
|
||||
old_random = world.random
|
||||
world.random = random.Random(self.er_seed)
|
||||
old_random = multiworld.random
|
||||
multiworld.random = random.Random(self.er_seed)
|
||||
|
||||
if world.mode[player] != 'inverted':
|
||||
link_entrances(world, player)
|
||||
mark_light_world_regions(world, player)
|
||||
if multiworld.mode[player] != 'inverted':
|
||||
link_entrances(multiworld, player)
|
||||
mark_light_world_regions(multiworld, player)
|
||||
for region_name, entrance_name in indirect_connections_not_inverted.items():
|
||||
world.register_indirect_condition(world.get_region(region_name, player),
|
||||
world.get_entrance(entrance_name, player))
|
||||
multiworld.register_indirect_condition(multiworld.get_region(region_name, player),
|
||||
multiworld.get_entrance(entrance_name, player))
|
||||
else:
|
||||
link_inverted_entrances(world, player)
|
||||
mark_dark_world_regions(world, player)
|
||||
link_inverted_entrances(multiworld, player)
|
||||
mark_dark_world_regions(multiworld, player)
|
||||
for region_name, entrance_name in indirect_connections_inverted.items():
|
||||
world.register_indirect_condition(world.get_region(region_name, player),
|
||||
world.get_entrance(entrance_name, player))
|
||||
multiworld.register_indirect_condition(multiworld.get_region(region_name, player),
|
||||
multiworld.get_entrance(entrance_name, player))
|
||||
|
||||
world.random = old_random
|
||||
plando_connect(world, player)
|
||||
multiworld.random = old_random
|
||||
plando_connect(multiworld, player)
|
||||
|
||||
for region_name, entrance_name in indirect_connections.items():
|
||||
world.register_indirect_condition(world.get_region(region_name, player),
|
||||
world.get_entrance(entrance_name, player))
|
||||
multiworld.register_indirect_condition(multiworld.get_region(region_name, player),
|
||||
multiworld.get_entrance(entrance_name, player))
|
||||
|
||||
def collect_item(self, state: CollectionState, item: Item, remove=False):
|
||||
item_name = item.name
|
||||
|
||||
@@ -47,12 +47,12 @@ wählen können!
|
||||
|
||||
### Wo bekomme ich so eine YAML-Datei her?
|
||||
|
||||
Die [Player Settings](/games/A Link to the Past/player-settings) Seite auf der Website ermöglicht das einfache Erstellen
|
||||
Die [Player Options](/games/A Link to the Past/player-options) Seite auf der Website ermöglicht das einfache Erstellen
|
||||
und Herunterladen deiner eigenen `yaml` Datei. Drei verschiedene Voreinstellungen können dort gespeichert werden.
|
||||
|
||||
### Deine YAML-Datei ist gewichtet!
|
||||
|
||||
Die **Player Settings** Seite hat eine Menge Optionen, die man per Schieber einstellen kann. Das ermöglicht es,
|
||||
Die **Player Options** Seite hat eine Menge Optionen, die man per Schieber einstellen kann. Das ermöglicht es,
|
||||
verschiedene Optionen mit unterschiedlichen Wahrscheinlichkeiten in einer Kategorie ausgewürfelt zu werden
|
||||
|
||||
Als Beispiel kann man sich die Option "Map Shuffle" als einen Eimer mit Zetteln zur Abstimmung Vorstellen. So kann man
|
||||
|
||||
@@ -59,7 +59,7 @@ de multiworld puede tener diferentes opciones.
|
||||
|
||||
### Donde puedo obtener un fichero YAML?
|
||||
|
||||
La página "[Generate Game](/games/A%20Link%20to%20the%20Past/player-settings)" en el sitio web te permite configurar tu
|
||||
La página "[Generate Game](/games/A%20Link%20to%20the%20Past/player-options)" en el sitio web te permite configurar tu
|
||||
configuración personal y descargar un fichero "YAML".
|
||||
|
||||
### Configuración YAML avanzada
|
||||
@@ -86,7 +86,7 @@ Si quieres validar que tu fichero YAML para asegurarte que funciona correctament
|
||||
|
||||
## Generar una partida para un jugador
|
||||
|
||||
1. Navega a [la pagina Generate game](/games/A%20Link%20to%20the%20Past/player-settings), configura tus opciones, haz
|
||||
1. Navega a [la pagina Generate game](/games/A%20Link%20to%20the%20Past/player-options), configura tus opciones, haz
|
||||
click en el boton "Generate game".
|
||||
2. Se te redigirá a una pagina "Seed Info", donde puedes descargar tu archivo de parche.
|
||||
3. Haz doble click en tu fichero de parche, y el emulador debería ejecutar tu juego automáticamente. Como el Cliente no
|
||||
|
||||
@@ -60,7 +60,7 @@ peuvent avoir différentes options.
|
||||
|
||||
### Où est-ce que j'obtiens un fichier YAML ?
|
||||
|
||||
La page [Génération de partie](/games/A%20Link%20to%20the%20Past/player-settings) vous permet de configurer vos
|
||||
La page [Génération de partie](/games/A%20Link%20to%20the%20Past/player-options) vous permet de configurer vos
|
||||
paramètres personnels et de les exporter vers un fichier YAML.
|
||||
|
||||
### Configuration avancée du fichier YAML
|
||||
@@ -87,7 +87,7 @@ Si vous voulez valider votre fichier YAML pour être sûr qu'il fonctionne, vous
|
||||
|
||||
## Générer une partie pour un joueur
|
||||
|
||||
1. Aller sur la page [Génération de partie](/games/A%20Link%20to%20the%20Past/player-settings), configurez vos options,
|
||||
1. Aller sur la page [Génération de partie](/games/A%20Link%20to%20the%20Past/player-options), configurez vos options,
|
||||
et cliquez sur le bouton "Generate Game".
|
||||
2. Il vous sera alors présenté une page d'informations sur la seed, où vous pourrez télécharger votre patch.
|
||||
3. Double-cliquez sur le patch et l'émulateur devrait se lancer automatiquement avec la seed. Etant donné que le client
|
||||
@@ -207,4 +207,4 @@ Le logiciel recommandé pour l'auto-tracking actuellement est
|
||||
3. Sélectionnez votre appareil SNES dans la liste déroulante.
|
||||
4. Si vous voulez tracquer les petites clés ainsi que les objets des donjons, cochez la case **Race Illegal Tracking**
|
||||
5. Cliquez sur le bouton **Start Autotracking**
|
||||
6. Fermez la fenêtre "AutoTracker" maintenant, elle n'est plus nécessaire
|
||||
6. Fermez la fenêtre "AutoTracker" maintenant, elle n'est plus nécessaire
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
[ArchipIDLE GitHub Releases Page](https://github.com/ArchipelagoMW/archipidle/releases)
|
||||
3. Enter the server address in the `Server Address` field and press enter
|
||||
4. Enter your slot name when prompted. This should be the same as the `name` you entered on the
|
||||
setting page above, or the `name` field in your yaml file.
|
||||
options page above, or the `name` field in your yaml file.
|
||||
5. Click the "Begin!" button.
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# Guide de configuration d'ArchipIdle
|
||||
|
||||
## Rejoindre une partie MultiWorld
|
||||
1. Générez un fichier `.yaml` à partir de la [page des paramètres du lecteur ArchipIDLE](/games/ArchipIDLE/player-settings)
|
||||
1. Générez un fichier `.yaml` à partir de la [page des paramètres du lecteur ArchipIDLE](/games/ArchipIDLE/player-options)
|
||||
2. Ouvrez le client ArchipIDLE dans votre navigateur Web en :
|
||||
- Accédez au [Client ArchipIDLE](http://idle.multiworld.link)
|
||||
- Téléchargez le client et exécutez-le localement à partir du
|
||||
[Page des versions d'ArchipIDLE GitHub](https://github.com/ArchipelagoMW/archipidle/releases)
|
||||
- Accédez au [Client ArchipIDLE](http://idle.multiworld.link)
|
||||
- Téléchargez le client et exécutez-le localement à partir du [Page des versions d'ArchipIDLE GitHub](https://github.com/ArchipelagoMW/archipidle/releases)
|
||||
3. Entrez l'adresse du serveur dans le champ `Server Address` et appuyez sur Entrée
|
||||
4. Entrez votre nom d'emplacement lorsque vous y êtes invité. Il doit être le même que le `name` que vous avez saisi sur le
|
||||
page de configuration ci-dessus, ou le champ `name` dans votre fichier yaml.
|
||||
|
||||
@@ -29,5 +29,5 @@ placez-le à la racine du jeu (ex: "SteamLibrary\steamapps\common\DARK SOULS III
|
||||
|
||||
## Où trouver le fichier de configuration ?
|
||||
|
||||
La [Page de configuration](/games/Dark%20Souls%20III/player-settings) sur le site vous permez de configurer vos
|
||||
La [Page de configuration](/games/Dark%20Souls%20III/player-options) sur le site vous permez de configurer vos
|
||||
paramètres et de les exporter sous la forme d'un fichier.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Où se trouve la page des paramètres ?
|
||||
|
||||
La [page des paramètres du joueur pour ce jeu](../player-settings) contient tous les paramètres dont vous avez besoin pour configurer et exporter le fichier.
|
||||
La [page des paramètres du joueur pour ce jeu](../player-options) contient tous les paramètres dont vous avez besoin pour configurer et exporter le fichier.
|
||||
|
||||
|
||||
## Quel est l'effet de la randomisation sur ce jeu ?
|
||||
@@ -46,4 +46,4 @@ Il y a aussi de nouveaux objets pièges, utilisés comme substituts, basés sur
|
||||
Chaque fois qu'un objet est reçu en ligne, une notification apparaît à l'écran pour en informer le joueur.
|
||||
Certains objets sont accompagnés d'une animation ou d'une scène qui se déroule immédiatement après leur réception.
|
||||
|
||||
Les objets reçus hors ligne ne sont pas accompagnés d'une animation ou d'une scène, et sont simplement activés lors de la connexion.
|
||||
Les objets reçus hors ligne ne sont pas accompagnés d'une animation ou d'une scène, et sont simplement activés lors de la connexion.
|
||||
|
||||
@@ -18,7 +18,7 @@ Voir le guide d'Archipelago sur la mise en place d'un YAML de base : [Basic Mult
|
||||
|
||||
### Où puis-je obtenir un fichier YAML ?
|
||||
|
||||
Vous pouvez personnaliser vos paramètres en visitant la [page des paramètres du joueur DLC Quest] (/games/DLCQuest/player-settings).
|
||||
Vous pouvez personnaliser vos paramètres en visitant la [page des paramètres du joueur DLC Quest](/games/DLCQuest/player-options).
|
||||
|
||||
## Rejoindre une partie multi-monde
|
||||
|
||||
@@ -52,4 +52,4 @@ Vous pouvez personnaliser vos paramètres en visitant la [page des paramètres d
|
||||
|
||||
Vous ne pouvez pas envoyer de commandes au serveur ou discuter avec les autres joueurs depuis DLC Quest, car le jeu ne dispose pas d'un moyen approprié pour saisir du texte.
|
||||
Vous pouvez suivre l'activité du serveur dans votre console BepInEx, car les messages de chat d'Archipelago y seront affichés.
|
||||
Vous devrez utiliser [Archipelago Text Client] (https://github.com/ArchipelagoMW/Archipelago/releases) si vous voulez envoyer des commandes.
|
||||
Vous devrez utiliser [Archipelago Text Client] (https://github.com/ArchipelagoMW/Archipelago/releases) si vous voulez envoyer des commandes.
|
||||
|
||||
@@ -2,27 +2,28 @@
|
||||
This guide covers more the more advanced options available in YAML files. This guide is intended for the user who plans
|
||||
to edit their YAML file manually. This guide should take about 10 minutes to read.
|
||||
|
||||
If you would like to generate a basic, fully playable YAML without editing a file, then visit the settings page for the
|
||||
If you would like to generate a basic, fully playable YAML without editing a file, then visit the options page for the
|
||||
game you intend to play. The weighted settings page can also handle most of the advanced settings discussed here.
|
||||
|
||||
The settings page can be found on the supported games page, just click the "Settings Page" link under the name of the
|
||||
game you would like.
|
||||
The options page can be found on the supported games page, just click the "Options Page" link under the name of the
|
||||
game you would like.
|
||||
|
||||
* Supported games page: [Archipelago Games List](/games)
|
||||
* Weighted settings page: [Archipelago Weighted Settings](/weighted-settings)
|
||||
|
||||
Clicking on the "Export Settings" button at the bottom-left will provide you with a pre-filled YAML with your options.
|
||||
The player settings page also has a link to download a full template file for that game which will have every option
|
||||
Clicking on the "Export Options" button at the bottom-left will provide you with a pre-filled YAML with your options.
|
||||
The player options page also has a link to download a full template file for that game which will have every option
|
||||
possible for the game including some that don't display correctly on the site.
|
||||
|
||||
## YAML Overview
|
||||
|
||||
The Archipelago system generates games using player configuration files as input. These are going to be YAML files and
|
||||
each world will have one of these containing their custom settings for the game that world will play.
|
||||
each world will have one of these containing their custom options for the game that world will play.
|
||||
|
||||
## YAML Formatting
|
||||
|
||||
YAML files are a format of human-readable config files. The basic syntax of a yaml file will have a `root` node and then
|
||||
different levels of `nested` nodes that the generator reads in order to determine your settings.
|
||||
different levels of `nested` nodes that the generator reads in order to determine your options.
|
||||
|
||||
To nest text, the correct syntax is to indent **two spaces over** from its root option. A YAML file can be edited with
|
||||
whatever text editor you choose to use though I personally recommend that you use Sublime Text. Sublime text
|
||||
@@ -53,13 +54,13 @@ so `option_one_setting_one` is guaranteed to occur.
|
||||
|
||||
For `nested_option_two`, `option_two_setting_one` will be rolled 14 times and `option_two_setting_two` will be rolled 43
|
||||
times against each other. This means `option_two_setting_two` will be more likely to occur, but it isn't guaranteed,
|
||||
adding more randomness and "mystery" to your settings. Every configurable setting supports weights.
|
||||
adding more randomness and "mystery" to your options. Every configurable setting supports weights.
|
||||
|
||||
## Root Options
|
||||
|
||||
Currently, there are only a few options that are root options. Everything else should be nested within one of these root
|
||||
options or in some cases nested within other nested options. The only options that should exist in root
|
||||
are `description`, `name`, `game`, `requires`, and the name of the games you want settings for.
|
||||
are `description`, `name`, `game`, `requires`, and the name of the games you want options for.
|
||||
|
||||
* `description` is ignored by the generator and is simply a good way for you to organize if you have multiple files
|
||||
using this to detail the intention of the file.
|
||||
@@ -79,15 +80,15 @@ are `description`, `name`, `game`, `requires`, and the name of the games you wan
|
||||
|
||||
* `requires` details different requirements from the generator for the YAML to work as you expect it to. Generally this
|
||||
is good for detailing the version of Archipelago this YAML was prepared for as, if it is rolled on an older version,
|
||||
settings may be missing and as such it will not work as expected. If any plando is used in the file then requiring it
|
||||
options may be missing and as such it will not work as expected. If any plando is used in the file then requiring it
|
||||
here to ensure it will be used is good practice.
|
||||
|
||||
## Game Options
|
||||
|
||||
One of your root settings will be the name of the game you would like to populate with settings. Since it is possible to
|
||||
One of your root options will be the name of the game you would like to populate with options. Since it is possible to
|
||||
give a weight to any option, it is possible to have one file that can generate a seed for you where you don't know which
|
||||
game you'll play. For these cases you'll want to fill the game options for every game that can be rolled by these
|
||||
settings. If a game can be rolled it **must** have a settings section even if it is empty.
|
||||
settings. If a game can be rolled it **must** have an options section even if it is empty.
|
||||
|
||||
### Universal Game Options
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ about 5 minutes to read.
|
||||
|
||||
## What are triggers?
|
||||
|
||||
Triggers allow you to customize your game settings by allowing you to define one or many options which only occur under
|
||||
Triggers allow you to customize your game options by allowing you to define one or many options which only occur under
|
||||
specific conditions. These are essentially "if, then" statements for options in your game. A good example of what you
|
||||
can do with triggers is the [custom mercenary mode YAML
|
||||
](https://github.com/alwaysintreble/Archipelago-yaml-dump/blob/main/Snippets/Mercenary%20Mode%20Snippet.yaml) that was
|
||||
@@ -148,4 +148,4 @@ In this example, if the `start_location` option rolls `landing_site`, only a sta
|
||||
If `aqueduct` is rolled, a starting hint for Gravity Suit will also be created alongside the hint for Morph Ball.
|
||||
|
||||
Note that for lists, items can only be added, not removed or replaced. For dicts, defining a value for a present key will
|
||||
replace that value within the dict.
|
||||
replace that value within the dict.
|
||||
|
||||
55
worlds/hk/GodhomeData.py
Normal file
55
worlds/hk/GodhomeData.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from functools import partial
|
||||
|
||||
|
||||
godhome_event_names = ["Godhome_Flower_Quest", "Defeated_Pantheon_5", "GG_Atrium_Roof", "Defeated_Pantheon_1", "Defeated_Pantheon_2", "Defeated_Pantheon_3", "Opened_Pantheon_4", "Defeated_Pantheon_4", "GG_Atrium", "Hit_Pantheon_5_Unlock_Orb", "GG_Workshop", "Can_Damage_Crystal_Guardian", 'Defeated_Any_Soul_Warrior', "Defeated_Colosseum_3", "COMBAT[Radiance]", "COMBAT[Pantheon_1]", "COMBAT[Pantheon_2]", "COMBAT[Pantheon_3]", "COMBAT[Pantheon_4]", "COMBAT[Pantheon_5]", "COMBAT[Colosseum_3]", 'Warp-Junk_Pit_to_Godhome', 'Bench-Godhome_Atrium', 'Bench-Hall_of_Gods', "GODTUNERUNLOCK", "GG_Waterways", "Warp-Godhome_to_Junk_Pit", "NAILCOMBAT", "BOSS", "AERIALMINIBOSS"]
|
||||
|
||||
|
||||
def set_godhome_rules(hk_world, hk_set_rule):
|
||||
player = hk_world.player
|
||||
fn = partial(hk_set_rule, hk_world)
|
||||
|
||||
required_events = {
|
||||
"Godhome_Flower_Quest": lambda state: state.count('Defeated_Pantheon_5', player) and state.count('Room_Mansion[left1]', player) and state.count('Fungus3_49[right1]', player),
|
||||
|
||||
"Defeated_Pantheon_5": lambda state: state.has('GG_Atrium_Roof', player) and state.has('WINGS', player) and (state.has('LEFTCLAW', player) or state.has('RIGHTCLAW', player)) and ((state.has('Defeated_Pantheon_1', player) and state.has('Defeated_Pantheon_2', player) and state.has('Defeated_Pantheon_3', player) and state.has('Defeated_Pantheon_4', player) and state.has('COMBAT[Radiance]', player))),
|
||||
"GG_Atrium_Roof": lambda state: state.has('GG_Atrium', player) and state.has('Hit_Pantheon_5_Unlock_Orb', player) and state.has('LEFTCLAW', player),
|
||||
|
||||
"Defeated_Pantheon_1": lambda state: state.has('GG_Atrium', player) and ((state.has('Defeated_Gruz_Mother', player) and state.has('Defeated_False_Knight', player) and (state.has('Fungus1_29[left1]', player) or state.has('Fungus1_29[right1]', player)) and state.has('Defeated_Hornet_1', player) and state.has('Defeated_Gorb', player) and state.has('Defeated_Dung_Defender', player) and state.has('Defeated_Any_Soul_Warrior', player) and state.has('Defeated_Brooding_Mawlek', player))),
|
||||
"Defeated_Pantheon_2": lambda state: state.has('GG_Atrium', player) and ((state.has('Defeated_Xero', player) and state.has('Defeated_Crystal_Guardian', player) and state.has('Defeated_Soul_Master', player) and state.has('Defeated_Colosseum_2', player) and state.has('Defeated_Mantis_Lords', player) and state.has('Defeated_Marmu', player) and state.has('Defeated_Nosk', player) and state.has('Defeated_Flukemarm', player) and state.has('Defeated_Broken_Vessel', player))),
|
||||
"Defeated_Pantheon_3": lambda state: state.has('GG_Atrium', player) and ((state.has('Defeated_Hive_Knight', player) and state.has('Defeated_Elder_Hu', player) and state.has('Defeated_Collector', player) and state.has('Defeated_Colosseum_2', player) and state.has('Defeated_Grimm', player) and state.has('Defeated_Galien', player) and state.has('Defeated_Uumuu', player) and state.has('Defeated_Hornet_2', player))),
|
||||
"Opened_Pantheon_4": lambda state: state.has('GG_Atrium', player) and (state.has('Defeated_Pantheon_1', player) and state.has('Defeated_Pantheon_2', player) and state.has('Defeated_Pantheon_3', player)),
|
||||
"Defeated_Pantheon_4": lambda state: state.has('GG_Atrium', player) and state.has('Opened_Pantheon_4', player) and ((state.has('Defeated_Enraged_Guardian', player) and state.has('Defeated_Broken_Vessel', player) and state.has('Defeated_No_Eyes', player) and state.has('Defeated_Traitor_Lord', player) and state.has('Defeated_Dung_Defender', player) and state.has('Defeated_False_Knight', player) and state.has('Defeated_Markoth', player) and state.has('Defeated_Watcher_Knights', player) and state.has('Defeated_Soul_Master', player))),
|
||||
"GG_Atrium": lambda state: state.has('Warp-Junk_Pit_to_Godhome', player) and (state.has('RIGHTCLAW', player) or state.has('WINGS', player) or state.has('LEFTCLAW', player) and state.has('RIGHTSUPERDASH', player)) or state.has('GG_Workshop', player) and (state.has('LEFTCLAW', player) or state.has('RIGHTCLAW', player) and state.has('WINGS', player)) or state.has('Bench-Godhome_Atrium', player),
|
||||
"Hit_Pantheon_5_Unlock_Orb": lambda state: state.has('GG_Atrium', player) and state.has('WINGS', player) and (state.has('LEFTCLAW', player) or state.has('RIGHTCLAW', player)) and (((state.has('Queen_Fragment', player) and state.has('King_Fragment', player) and state.has('Void_Heart', player)) and state.has('Defeated_Pantheon_1', player) and state.has('Defeated_Pantheon_2', player) and state.has('Defeated_Pantheon_3', player) and state.has('Defeated_Pantheon_4', player))),
|
||||
"GG_Workshop": lambda state: state.has('GG_Atrium', player) or state.has('Bench-Hall_of_Gods', player),
|
||||
"Can_Damage_Crystal_Guardian": lambda state: state.has('UPSLASH', player) or state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player) or state._hk_option(player, 'ProficientCombat') and (state.has('CYCLONE', player) or state.has('Great_Slash', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat')) and (state.has('CYCLONE', player) or state.has('Great_Slash', player)) and (state.has('DREAMNAIL', player) and (state.has('SPELLS', player) or state.has('FOCUS', player) and state.has('Spore_Shroom', player) or state.has('Glowing_Womb', player)) or state.has('Weaversong', player)),
|
||||
'Defeated_Any_Soul_Warrior': lambda state: state.has('Defeated_Sanctum_Warrior', player) or state.has('Defeated_Elegant_Warrior', player) or state.has('Room_Colosseum_01[left1]', player) and state.has('Defeated_Colosseum_3', player),
|
||||
"Defeated_Colosseum_3": lambda state: state.has('Room_Colosseum_01[left1]', player) and state.has('Can_Replenish_Geo', player) and ((state.has('LEFTCLAW', player) or state.has('RIGHTCLAW', player)) or ((state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat')) and state.has('WINGS', player))) and state.has('COMBAT[Colosseum_3]', player),
|
||||
|
||||
# MACROS
|
||||
"COMBAT[Radiance]": lambda state: (state.has('LEFTDASH', player) and state.has('RIGHTDASH', player)) and ((((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('LEFTDASH', player)) and ((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('RIGHTDASH', player))) or state.has('QUAKE', player)) and (state.count('FIREBALL', player) > 1 and state.has('UPSLASH', player) or state.count('SCREAM', player) > 1 and state.has('UPSLASH', player) or state._hk_option(player, 'RemoveSpellUpgrades') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and state.has('UPSLASH', player) or state._hk_option(player, 'ProficientCombat') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and (state.has('UPSLASH', player) or (state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('Great_Slash', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
"COMBAT[Pantheon_1]": lambda state: state.has('AERIALMINIBOSS', player) and state.count('SPELLS', player) > 1 and (state.has('FOCUS', player) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
"COMBAT[Pantheon_2]": lambda state: state.has('AERIALMINIBOSS', player) and state.count('SPELLS', player) > 1 and (state.has('FOCUS', player) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))) and state.has('Can_Damage_Crystal_Guardian', player),
|
||||
"COMBAT[Pantheon_3]": lambda state: state.has('AERIALMINIBOSS', player) and state.count('SPELLS', player) > 1 and (state.has('FOCUS', player) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
"COMBAT[Pantheon_4]": lambda state: state.has('AERIALMINIBOSS', player) and (state.has('FOCUS', player) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))) and state.has('Can_Damage_Crystal_Guardian', player) and (state.has('LEFTDASH', player) and state.has('RIGHTDASH', player)) and ((((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('LEFTDASH', player)) and ((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('RIGHTDASH', player))) or state.has('QUAKE', player)) and (state.count('FIREBALL', player) > 1 and state.has('UPSLASH', player) or state.count('SCREAM', player) > 1 and state.has('UPSLASH', player) or state._hk_option(player, 'RemoveSpellUpgrades') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and state.has('UPSLASH', player) or state._hk_option(player, 'ProficientCombat') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and (state.has('UPSLASH', player) or (state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('Great_Slash', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
"COMBAT[Pantheon_5]": lambda state: state.has('AERIALMINIBOSS', player) and state.has('FOCUS', player) and state.has('Can_Damage_Crystal_Guardian', player) and (state.has('LEFTDASH', player) and state.has('RIGHTDASH', player)) and ((((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('LEFTDASH', player)) and ((state.count('LEFTDASH', player) > 1 or state.count('RIGHTDASH', player) > 1) and state.has('RIGHTDASH', player))) or state.has('QUAKE', player)) and (state.count('FIREBALL', player) > 1 and state.has('UPSLASH', player) or state.count('SCREAM', player) > 1 and state.has('UPSLASH', player) or state._hk_option(player, 'RemoveSpellUpgrades') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and state.has('UPSLASH', player) or state._hk_option(player, 'ProficientCombat') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and (state.has('UPSLASH', player) or (state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('Great_Slash', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
"COMBAT[Colosseum_3]": lambda state: state.has('BOSS', player) and (state.has('FOCUS', player) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat'))),
|
||||
|
||||
# MISC
|
||||
'Warp-Junk_Pit_to_Godhome': lambda state: state.has('GG_Waterways', player) and state.has('GODTUNERUNLOCK', player) and state.has('DREAMNAIL', player),
|
||||
'Bench-Godhome_Atrium': lambda state: state.has('GG_Atrium', player) and (state.has('RIGHTCLAW', player) and (state.has('RIGHTDASH', player) or state.has('LEFTCLAW', player) and state.has('RIGHTSUPERDASH', player) or state.has('WINGS', player)) or state.has('LEFTCLAW', player) and state.has('WINGS', player)),
|
||||
'Bench-Hall_of_Gods': lambda state: state.has('GG_Workshop', player) and ((state.has('LEFTCLAW', player) or state.has('RIGHTCLAW', player))),
|
||||
|
||||
"GODTUNERUNLOCK": lambda state: state.count('SIMPLE', player) > 3,
|
||||
"GG_Waterways": lambda state: state.has('GG_Waterways[door1]', player) or state.has('GG_Waterways[right1]', player) and (state.has('LEFTSUPERDASH', player) or state.has('SWIM', player)) or state.has('Warp-Godhome_to_Junk_Pit', player),
|
||||
"Warp-Godhome_to_Junk_Pit": lambda state: state.has('Warp-Junk_Pit_to_Godhome', player) or state.has('GG_Atrium', player),
|
||||
|
||||
# COMBAT MACROS
|
||||
"NAILCOMBAT": lambda state: (state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('UPSLASH', player) or state._hk_option(player, 'ProficientCombat') and (state.has('CYCLONE', player) or state.has('Great_Slash', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat')),
|
||||
"BOSS": lambda state: state.count('SPELLS', player) > 1 and ((state.has('LEFTDASH', player) or state.has('RIGHTDASH', player)) and ((state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('UPSLASH', player)) or state._hk_option(player, 'ProficientCombat') and state.has('NAILCOMBAT', player)),
|
||||
"AERIALMINIBOSS": lambda state: (state.has('FIREBALL', player) or state.has('SCREAM', player)) and (state.has('LEFTDASH', player) or state.has('RIGHTDASH', player)) and ((state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('UPSLASH', player)) or state._hk_option(player, 'ProficientCombat') and (state.has('FIREBALL', player) or state.has('SCREAM', player)) and ((state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('UPSLASH', player)) or (state._hk_option(player, 'DifficultSkips') and state._hk_option(player, 'ProficientCombat')) and ((state.has('LEFTSLASH', player) or state.has('RIGHTSLASH', player)) or state.has('UPSLASH', player) or state.has('CYCLONE', player) or state.has('Great_Slash', player)),
|
||||
|
||||
}
|
||||
|
||||
for item, rule in required_events.items():
|
||||
fn(item, rule)
|
||||
@@ -1,5 +1,6 @@
|
||||
from typing import Dict, Set, NamedTuple
|
||||
from .ExtractedData import items, logic_items, item_effects
|
||||
from .GodhomeData import godhome_event_names
|
||||
|
||||
item_table = {}
|
||||
|
||||
@@ -14,6 +15,9 @@ for i, (item_name, item_type) in enumerate(items.items(), start=0x1000000):
|
||||
item_table[item_name] = HKItemData(advancement=item_name in logic_items or item_name in item_effects,
|
||||
id=i, type=item_type)
|
||||
|
||||
for item_name in godhome_event_names:
|
||||
item_table[item_name] = HKItemData(advancement=True, id=None, type=None)
|
||||
|
||||
lookup_id_to_name: Dict[int, str] = {data.id: item_name for item_name, data in item_table.items()}
|
||||
lookup_type_to_names: Dict[str, Set[str]] = {}
|
||||
for item, item_data in item_table.items():
|
||||
|
||||
@@ -397,8 +397,8 @@ class Goal(Choice):
|
||||
option_hollowknight = 1
|
||||
option_siblings = 2
|
||||
option_radiance = 3
|
||||
# Client support exists for this, but logic is a nightmare
|
||||
# option_godhome = 4
|
||||
option_godhome = 4
|
||||
option_godhome_flower = 5
|
||||
default = 0
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ..generic.Rules import set_rule, add_rule
|
||||
from ..AutoWorld import World
|
||||
from .GeneratedRules import set_generated_rules
|
||||
from .GodhomeData import set_godhome_rules
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
@@ -39,6 +40,7 @@ def hk_set_rule(hk_world: World, location: str, rule):
|
||||
def set_rules(hk_world: World):
|
||||
player = hk_world.player
|
||||
set_generated_rules(hk_world, hk_set_rule)
|
||||
set_godhome_rules(hk_world, hk_set_rule)
|
||||
|
||||
# Shop costs
|
||||
for location in hk_world.multiworld.get_locations(player):
|
||||
|
||||
@@ -307,6 +307,12 @@ class HKWorld(World):
|
||||
randomized = True
|
||||
_add("Elevator_Pass", "Elevator_Pass", randomized)
|
||||
|
||||
# check for any goal that godhome events are relevant to
|
||||
if self.multiworld.Goal[self.player] in [Goal.option_godhome, Goal.option_godhome_flower]:
|
||||
from .GodhomeData import godhome_event_names
|
||||
for item_name in godhome_event_names:
|
||||
_add(item_name, item_name, False)
|
||||
|
||||
for shop, locations in self.created_multi_locations.items():
|
||||
for _ in range(len(locations), getattr(self.multiworld, shop_to_option[shop])[self.player].value):
|
||||
loc = self.create_location(shop)
|
||||
@@ -431,6 +437,10 @@ class HKWorld(World):
|
||||
world.completion_condition[player] = lambda state: state._hk_siblings_ending(player)
|
||||
elif goal == Goal.option_radiance:
|
||||
world.completion_condition[player] = lambda state: state._hk_can_beat_radiance(player)
|
||||
elif goal == Goal.option_godhome:
|
||||
world.completion_condition[player] = lambda state: state.count("Defeated_Pantheon_5", player)
|
||||
elif goal == Goal.option_godhome_flower:
|
||||
world.completion_condition[player] = lambda state: state.count("Godhome_Flower_Quest", player)
|
||||
else:
|
||||
# Any goal
|
||||
world.completion_condition[player] = lambda state: state._hk_can_beat_thk(player) or state._hk_can_beat_radiance(player)
|
||||
|
||||
@@ -593,6 +593,20 @@ class HealingFloorChance(Range):
|
||||
default = 16
|
||||
|
||||
|
||||
class InactiveExpGain(Choice):
|
||||
"""The rate at which characters not currently in the active party gain EXP.
|
||||
|
||||
Supported values: disabled, half, full
|
||||
Default value: disabled (same as in an unmodified game)
|
||||
"""
|
||||
|
||||
display_name = "Inactive character EXP gain"
|
||||
option_disabled = 0
|
||||
option_half = 50
|
||||
option_full = 100
|
||||
default = option_disabled
|
||||
|
||||
|
||||
class InitialFloor(Range):
|
||||
"""The initial floor, where you begin your journey.
|
||||
|
||||
@@ -805,7 +819,7 @@ class ShufflePartyMembers(Toggle):
|
||||
false — all 6 optional party members are present in the cafe and can be recruited right away
|
||||
true — only Maxim is available from the start; 6 new "items" are added to your pool and shuffled into the
|
||||
multiworld; when one of these items is found, the corresponding party member is unlocked for you to use.
|
||||
While cave diving, you can add newly unlocked ones to your party by using the character items from the inventory
|
||||
While cave diving, you can add or remove unlocked party members by using the character items from the inventory
|
||||
Default value: false (same as in an unmodified game)
|
||||
"""
|
||||
|
||||
@@ -838,6 +852,7 @@ class L2ACOptions(PerGameCommonOptions):
|
||||
goal: Goal
|
||||
gold_modifier: GoldModifier
|
||||
healing_floor_chance: HealingFloorChance
|
||||
inactive_exp_gain: InactiveExpGain
|
||||
initial_floor: InitialFloor
|
||||
iris_floor_chance: IrisFloorChance
|
||||
iris_treasures_required: IrisTreasuresRequired
|
||||
|
||||
@@ -232,6 +232,7 @@ class L2ACWorld(World):
|
||||
rom_bytearray[0x280018:0x280018 + 1] = self.o.shuffle_party_members.unlock.to_bytes(1, "little")
|
||||
rom_bytearray[0x280019:0x280019 + 1] = self.o.shuffle_capsule_monsters.unlock.to_bytes(1, "little")
|
||||
rom_bytearray[0x28001A:0x28001A + 1] = self.o.shop_interval.value.to_bytes(1, "little")
|
||||
rom_bytearray[0x28001B:0x28001B + 1] = self.o.inactive_exp_gain.value.to_bytes(1, "little")
|
||||
rom_bytearray[0x280030:0x280030 + 1] = self.o.goal.value.to_bytes(1, "little")
|
||||
rom_bytearray[0x28003D:0x28003D + 1] = self.o.death_link.value.to_bytes(1, "little")
|
||||
rom_bytearray[0x281200:0x281200 + 470] = self.get_capsule_cravings_table()
|
||||
|
||||
@@ -309,6 +309,12 @@ org $8EFD2E ; unused region at the end of bank $8E
|
||||
DB $1E,$0B,$01,$2B,$05,$1A,$05,$00 ; add dekar
|
||||
DB $1E,$0B,$01,$2B,$04,$1A,$06,$00 ; add tia
|
||||
DB $1E,$0B,$01,$2B,$06,$1A,$07,$00 ; add lexis
|
||||
DB $1F,$0B,$01,$2C,$01,$1B,$02,$00 ; remove selan
|
||||
DB $1F,$0B,$01,$2C,$02,$1B,$03,$00 ; remove guy
|
||||
DB $1F,$0B,$01,$2C,$03,$1B,$04,$00 ; remove arty
|
||||
DB $1F,$0B,$01,$2C,$05,$1B,$05,$00 ; remove dekar
|
||||
DB $1F,$0B,$01,$2C,$04,$1B,$06,$00 ; remove tia
|
||||
DB $1F,$0B,$01,$2C,$06,$1B,$07,$00 ; remove lexis
|
||||
pullpc
|
||||
|
||||
SpecialItemUse:
|
||||
@@ -328,11 +334,15 @@ SpecialItemUse:
|
||||
SEP #$20
|
||||
LDA $8ED8C7,X ; load predefined bitmask with a single bit set
|
||||
BIT $077E ; check against EV flags $02 to $07 (party member flags)
|
||||
BNE + ; abort if character already present
|
||||
LDA $07A9 ; load EV register $11 (party counter)
|
||||
BEQ ++
|
||||
LDA.b #$30 ; character already present; modify pointer to point to L2SASM leave script
|
||||
ADC $09B7
|
||||
STA $09B7
|
||||
BRA +++
|
||||
++: LDA $07A9 ; character not present; load EV register $0B (party counter)
|
||||
CMP.b #$03
|
||||
BPL + ; abort if party full
|
||||
LDA.b #$8E
|
||||
+++ LDA.b #$8E
|
||||
STA $09B9
|
||||
PHK
|
||||
PEA ++
|
||||
@@ -340,7 +350,6 @@ SpecialItemUse:
|
||||
JML $83BB76 ; initialize parser variables
|
||||
++: NOP
|
||||
JSL $809CB8 ; call L2SASM parser
|
||||
JSL $81F034 ; consume the item
|
||||
TSX
|
||||
INX #13
|
||||
TXS
|
||||
@@ -490,6 +499,73 @@ pullpc
|
||||
|
||||
|
||||
|
||||
; allow inactive characters to gain exp
|
||||
pushpc
|
||||
org $81DADD
|
||||
; DB=$81, x=0, m=1
|
||||
NOP ; overwrites BNE $81DAE2 : JMP $DBED
|
||||
JML HandleActiveExp
|
||||
AwardExp:
|
||||
; isolate exp distribution into a subroutine, to be reused for both active party members and inactive characters
|
||||
org $81DAE9
|
||||
NOP #2 ; overwrites JMP $DBBD
|
||||
RTL
|
||||
org $81DB42
|
||||
NOP #2 ; overwrites JMP $DBBD
|
||||
RTL
|
||||
org $81DD11
|
||||
; DB=$81, x=0, m=1
|
||||
JSL HandleInactiveExp ; overwrites LDA $0A8A : CLC
|
||||
pullpc
|
||||
|
||||
HandleActiveExp:
|
||||
BNE + ; (overwritten instruction; modified) check if statblock not empty
|
||||
JML $81DBED ; (overwritten instruction; modified) abort
|
||||
+: JSL AwardExp ; award exp (X=statblock pointer, Y=position in battle order, $00=position in menu order)
|
||||
JML $81DBBD ; (overwritten instruction; modified) continue to next level text
|
||||
|
||||
HandleInactiveExp:
|
||||
LDA $F0201B ; load inactive exp gain rate
|
||||
BEQ + ; zero gain; skip everything
|
||||
CMP.b #$64
|
||||
BCS ++ ; full gain
|
||||
LSR $1607
|
||||
ROR $1606 ; half gain
|
||||
ROR $1605
|
||||
++: LDY.w #$0000 ; start looping through all characters
|
||||
-: TDC
|
||||
TYA
|
||||
LDX.w #$0003 ; start looping through active party
|
||||
--: CMP $0A7B,X
|
||||
BEQ ++ ; skip if character in active party
|
||||
DEX
|
||||
BPL -- ; continue looping through active party
|
||||
STA $153D ; inactive character detected; overwrite character index of 1st slot in party battle order
|
||||
ASL
|
||||
TAX
|
||||
REP #$20
|
||||
LDA $859EBA,X ; convert character index to statblock pointer
|
||||
SEP #$20
|
||||
TAX
|
||||
PHY ; stash character loop index
|
||||
LDY $0A80
|
||||
PHY ; stash 1st (in menu order) party member statblock pointer
|
||||
STX $0A80 ; overwrite 1st (in menu order) party member statblock pointer
|
||||
LDY.w #$0000 ; set to use 1st position (in battle order)
|
||||
STY $00 ; set to use 1st position (in menu order)
|
||||
JSL AwardExp ; award exp (X=statblock pointer, Y=position in battle order, $00=position in menu order)
|
||||
PLY ; restore 1st (in menu order) party member statblock pointer
|
||||
STY $0A80
|
||||
PLY ; restore character loop index
|
||||
++: INY
|
||||
CPY.w #$0007
|
||||
BCC - ; continue looping through all characters
|
||||
+: LDA $0A8A ; (overwritten instruction) load current gold
|
||||
CLC ; (overwritten instruction)
|
||||
RTL
|
||||
|
||||
|
||||
|
||||
; receive death link
|
||||
pushpc
|
||||
org $83BC91
|
||||
@@ -1226,6 +1302,7 @@ pullpc
|
||||
; $F02018 1 party members available
|
||||
; $F02019 1 capsule monsters available
|
||||
; $F0201A 1 shop interval
|
||||
; $F0201B 1 inactive exp gain rate
|
||||
; $F02030 1 selected goal
|
||||
; $F02031 1 goal completion: boss
|
||||
; $F02032 1 goal completion: iris_treasure_hunt
|
||||
|
||||
Binary file not shown.
@@ -53,8 +53,9 @@ Your Party Leader will hold up the item they received when not in a fight or in
|
||||
- Randomize enemy movement patterns, enemy sprites, and which enemy types can appear at which floor numbers
|
||||
- Option to make shops appear in the cave so that you have a way to spend your hard-earned gold
|
||||
- Option to shuffle your party members and/or capsule monsters into the multiworld, meaning that someone will have to
|
||||
find them in order to unlock them for you to use. While cave diving, you can add newly unlocked members to your party
|
||||
by using the character items from your inventory
|
||||
find them in order to unlock them for you to use. While cave diving, you can add or remove unlocked party members by
|
||||
using the character items from your inventory. There's also an option to allow inactive characters to gain some EXP,
|
||||
so that new party members added during a run don't have to start off at a low level
|
||||
|
||||
###### Quality of life:
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ guide : [Guide de configuration de base de Multiworld](/tutorial/Archipelago/se
|
||||
|
||||
### Où puis-je obtenir un fichier YAML ?
|
||||
|
||||
Vous pouvez personnaliser vos paramètres Minecraft en allant sur la [page des paramètres de joueur](/games/Minecraft/player-settings)
|
||||
Vous pouvez personnaliser vos paramètres Minecraft en allant sur la [page des paramètres de joueur](/games/Minecraft/player-options)
|
||||
|
||||
## Rejoindre une partie MultiWorld
|
||||
|
||||
@@ -71,4 +71,4 @@ les liens suivants sont les versions des logiciels que nous utilisons.
|
||||
- [Page des versions du mod Minecraft Archipelago Randomizer] (https://github.com/KonoTyran/Minecraft_AP_Randomizer/releases)
|
||||
- **NE PAS INSTALLER CECI SUR VOTRE CLIENT**
|
||||
- [Amazon Corretto](https://docs.aws.amazon.com/corretto/)
|
||||
- choisissez la version correspondante et sélectionnez "Téléchargements" sur la gauche
|
||||
- choisissez la version correspondante et sélectionnez "Téléchargements" sur la gauche
|
||||
|
||||
@@ -103,8 +103,6 @@ shuffle_structures:
|
||||
off: 0
|
||||
```
|
||||
|
||||
För mer detaljer om vad varje inställning gör, kolla standardinställningen `PlayerSettings.yaml` som kommer med
|
||||
Archipelago-installationen.
|
||||
|
||||
## Gå med i ett Multivärld-spel
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Enlaces rápidos
|
||||
- [Página Principal](../../../../games/Muse%20Dash/info/en)
|
||||
- [Página de Configuraciones](../../../../games/Muse%20Dash/player-settings)
|
||||
- [Página de Configuraciones](../../../../games/Muse%20Dash/player-options)
|
||||
|
||||
## Software Requerido
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
Si todo fue instalado correctamente, un botón aparecerá en la parte inferior derecha del juego una vez abierto, que te permitirá conectarte al servidor de Archipelago.
|
||||
|
||||
## Generar un juego MultiWorld
|
||||
1. Entra a la página de [configuraciones de jugador](/games/Muse%20Dash/player-settings) y configura las opciones del juego a tu gusto.
|
||||
1. Entra a la página de [configuraciones de jugador](/games/Muse%20Dash/player-options) y configura las opciones del juego a tu gusto.
|
||||
2. Genera tu archivo YAML y úsalo para generar un juego nuevo en el radomizer
|
||||
- (Instrucciones sobre como generar un juego en Archipelago disponibles en la [guía web de Archipelago en Inglés](/tutorial/Archipelago/setup/en))
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ guide : [Guide de configuration de base de Multiworld](/tutorial/Archipelago/set
|
||||
|
||||
### Où puis-je obtenir un fichier de configuration (.yaml) ?
|
||||
|
||||
La page Paramètres du lecteur sur le site Web vous permet de configurer vos paramètres personnels et d'exporter un fichier de configuration depuis eux. Page des paramètres du joueur : [Page des paramètres du joueur d'Ocarina of Time](/games/Ocarina%20of%20Time/player-settings)
|
||||
La page Paramètres du lecteur sur le site Web vous permet de configurer vos paramètres personnels et d'exporter un fichier de configuration depuis eux. Page des paramètres du joueur : [Page des paramètres du joueur d'Ocarina of Time](/games/Ocarina%20of%20Time/player-options)
|
||||
|
||||
### Vérification de votre fichier de configuration
|
||||
|
||||
@@ -67,4 +67,4 @@ Une fois le client et l'émulateur démarrés, vous devez les connecter. Accéde
|
||||
|
||||
Pour connecter le client au multiserveur, mettez simplement `<adresse>:<port>` dans le champ de texte en haut et appuyez sur Entrée (si le serveur utilise un mot de passe, tapez dans le champ de texte inférieur `/connect <adresse>:<port> [mot de passe]`)
|
||||
|
||||
Vous êtes maintenant prêt à commencer votre aventure dans Hyrule.
|
||||
Vous êtes maintenant prêt à commencer votre aventure dans Hyrule.
|
||||
|
||||
@@ -51,7 +51,7 @@ opciones.
|
||||
|
||||
### ¿Dónde puedo obtener un archivo YAML?
|
||||
|
||||
Puedes generar un archivo YAML or descargar su plantilla en la [página de configuración de jugador de Pokémon Red and Blue](/games/Pokemon%20Red%20and%20Blue/player-settings)
|
||||
Puedes generar un archivo YAML or descargar su plantilla en la [página de configuración de jugador de Pokémon Red and Blue](/games/Pokemon%20Red%20and%20Blue/player-options)
|
||||
|
||||
Es importante tener en cuenta que la opción `game_version` determina el ROM que será parcheado.
|
||||
Tanto el jugador como la persona que genera (si está generando localmente) necesitarán el archivo del ROM
|
||||
|
||||
@@ -44,8 +44,8 @@ class RiskOfRainWorld(World):
|
||||
}
|
||||
location_name_to_id = item_pickups
|
||||
|
||||
data_version = 8
|
||||
required_client_version = (0, 4, 4)
|
||||
data_version = 9
|
||||
required_client_version = (0, 4, 5)
|
||||
web = RiskOfWeb()
|
||||
total_revivals: int
|
||||
|
||||
@@ -91,6 +91,17 @@ class RiskOfRainWorld(World):
|
||||
# only mess with the environments if they are set as items
|
||||
if self.options.goal == "explore":
|
||||
|
||||
# check to see if the user doesn't want to use stages, and to figure out what type of stages are being used.
|
||||
if not self.options.require_stages:
|
||||
if not self.options.progressive_stages:
|
||||
self.multiworld.push_precollected(self.multiworld.create_item("Stage 1", self.player))
|
||||
self.multiworld.push_precollected(self.multiworld.create_item("Stage 2", self.player))
|
||||
self.multiworld.push_precollected(self.multiworld.create_item("Stage 3", self.player))
|
||||
self.multiworld.push_precollected(self.multiworld.create_item("Stage 4", self.player))
|
||||
else:
|
||||
for _ in range(4):
|
||||
self.multiworld.push_precollected(self.multiworld.create_item("Progressive Stage", self.player))
|
||||
|
||||
# figure out all available ordered stages for each tier
|
||||
environment_available_orderedstages_table = environment_vanilla_orderedstages_table
|
||||
if self.options.dlc_sotv:
|
||||
@@ -121,8 +132,12 @@ class RiskOfRainWorld(World):
|
||||
total_locations = self.options.total_locations.value
|
||||
else:
|
||||
# explore mode
|
||||
# Add Stage items for logic gates
|
||||
itempool += ["Stage 1", "Stage 2", "Stage 3", "Stage 4"]
|
||||
|
||||
# Add Stage items to the pool
|
||||
if self.options.require_stages:
|
||||
itempool += ["Stage 1", "Stage 2", "Stage 3", "Stage 4"] if not self.options.progressive_stages else \
|
||||
["Progressive Stage"] * 4
|
||||
|
||||
total_locations = len(
|
||||
get_locations(
|
||||
chests=self.options.chests_per_stage.value,
|
||||
@@ -206,8 +221,8 @@ class RiskOfRainWorld(World):
|
||||
options_dict = self.options.as_dict("item_pickup_step", "shrine_use_step", "goal", "victory", "total_locations",
|
||||
"chests_per_stage", "shrines_per_stage", "scavengers_per_stage",
|
||||
"scanner_per_stage", "altars_per_stage", "total_revivals",
|
||||
"start_with_revive", "final_stage_death", "death_link",
|
||||
casing="camel")
|
||||
"start_with_revive", "final_stage_death", "death_link", "require_stages",
|
||||
"progressive_stages", casing="camel")
|
||||
return {
|
||||
**options_dict,
|
||||
"seed": "".join(self.random.choice(string.digits) for _ in range(16)),
|
||||
|
||||
@@ -57,7 +57,6 @@ options apply, so each Risk of Rain 2 player slot in the multiworld needs to be
|
||||
for example, have two players trade off hosting and making progress on each other's player slot, but a single co-op
|
||||
instance can't make progress towards multiple player slots in the multiworld.
|
||||
|
||||
Explore mode is untested in multiplayer and will likely not work until a later release.
|
||||
|
||||
## What Risk of Rain items can appear in other players' worlds?
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ stage_table: Dict[str, RiskOfRainItemData] = {
|
||||
"Stage 2": RiskOfRainItemData("Stage", 2 + stage_offset, ItemClassification.progression),
|
||||
"Stage 3": RiskOfRainItemData("Stage", 3 + stage_offset, ItemClassification.progression),
|
||||
"Stage 4": RiskOfRainItemData("Stage", 4 + stage_offset, ItemClassification.progression),
|
||||
|
||||
"Progressive Stage": RiskOfRainItemData("Stage", 5 + stage_offset, ItemClassification.progression),
|
||||
}
|
||||
|
||||
item_table = {**upgrade_table, **other_table, **filler_table, **trap_table, **stage_table}
|
||||
|
||||
@@ -151,6 +151,17 @@ class DLC_SOTV(Toggle):
|
||||
display_name = "Enable DLC - SOTV"
|
||||
|
||||
|
||||
class RequireStages(DefaultOnToggle):
|
||||
"""Add Stage items to the pool to block access to the next set of environments."""
|
||||
display_name = "Require Stages"
|
||||
|
||||
|
||||
class ProgressiveStages(DefaultOnToggle):
|
||||
"""This will convert Stage items to be a progressive item. For example instead of "Stage 2" it would be
|
||||
"Progressive Stage" """
|
||||
display_name = "Progressive Stages"
|
||||
|
||||
|
||||
class GreenScrap(Range):
|
||||
"""Weight of Green Scraps in the item pool.
|
||||
|
||||
@@ -378,6 +389,8 @@ class ROR2Options(PerGameCommonOptions):
|
||||
start_with_revive: StartWithRevive
|
||||
final_stage_death: FinalStageDeath
|
||||
dlc_sotv: DLC_SOTV
|
||||
require_stages: RequireStages
|
||||
progressive_stages: ProgressiveStages
|
||||
death_link: DeathLink
|
||||
item_pickup_step: ItemPickupStep
|
||||
shrine_use_step: ShrineUseStep
|
||||
|
||||
@@ -15,6 +15,13 @@ def has_entrance_access_rule(multiworld: MultiWorld, stage: str, region: str, pl
|
||||
entrance.access_rule = rule
|
||||
|
||||
|
||||
def has_stage_access_rule(multiworld: MultiWorld, stage: str, amount: int, region: str, player: int) -> None:
|
||||
rule = lambda state: state.has(region, player) and \
|
||||
(state.has(stage, player) or state.count("Progressive Stage", player) >= amount)
|
||||
for entrance in multiworld.get_region(region, player).entrances:
|
||||
entrance.access_rule = rule
|
||||
|
||||
|
||||
def has_all_items(multiworld: MultiWorld, items: Set[str], region: str, player: int) -> None:
|
||||
rule = lambda state: state.has_all(items, player) and state.has(region, player)
|
||||
for entrance in multiworld.get_region(region, player).entrances:
|
||||
@@ -43,15 +50,6 @@ def check_location(state, environment: str, player: int, item_number: int, item_
|
||||
return state.can_reach(f"{environment}: {item_name} {item_number - 1}", "Location", player)
|
||||
|
||||
|
||||
# unlock event to next set of stages
|
||||
def get_stage_event(multiworld: MultiWorld, player: int, stage_number: int) -> None:
|
||||
if stage_number == 4:
|
||||
return
|
||||
rule = lambda state: state.has(f"Stage {stage_number + 1}", player)
|
||||
for entrance in multiworld.get_region(f"OrderedStage_{stage_number + 1}", player).entrances:
|
||||
entrance.access_rule = rule
|
||||
|
||||
|
||||
def set_rules(ror2_world: "RiskOfRainWorld") -> None:
|
||||
player = ror2_world.player
|
||||
multiworld = ror2_world.multiworld
|
||||
@@ -124,8 +122,7 @@ def set_rules(ror2_world: "RiskOfRainWorld") -> None:
|
||||
for newt in range(1, newts + 1):
|
||||
has_location_access_rule(multiworld, environment_name, player, newt, "Newt Altar")
|
||||
if i > 0:
|
||||
has_entrance_access_rule(multiworld, f"Stage {i}", environment_name, player)
|
||||
get_stage_event(multiworld, player, i)
|
||||
has_stage_access_rule(multiworld, f"Stage {i}", i, environment_name, player)
|
||||
|
||||
if ror2_options.dlc_sotv:
|
||||
for i in range(len(environment_sotv_orderedstages_table)):
|
||||
@@ -143,10 +140,10 @@ def set_rules(ror2_world: "RiskOfRainWorld") -> None:
|
||||
for newt in range(1, newts + 1):
|
||||
has_location_access_rule(multiworld, environment_name, player, newt, "Newt Altar")
|
||||
if i > 0:
|
||||
has_entrance_access_rule(multiworld, f"Stage {i}", environment_name, player)
|
||||
has_stage_access_rule(multiworld, f"Stage {i}", i, environment_name, player)
|
||||
has_entrance_access_rule(multiworld, "Hidden Realm: A Moment, Fractured", "Hidden Realm: A Moment, Whole",
|
||||
player)
|
||||
has_entrance_access_rule(multiworld, "Stage 1", "Hidden Realm: Bazaar Between Time", player)
|
||||
has_stage_access_rule(multiworld, "Stage 1", 1, "Hidden Realm: Bazaar Between Time", player)
|
||||
has_entrance_access_rule(multiworld, "Hidden Realm: Bazaar Between Time", "Void Fields", player)
|
||||
has_entrance_access_rule(multiworld, "Stage 5", "Commencement", player)
|
||||
has_entrance_access_rule(multiworld, "Stage 5", "Hidden Realm: A Moment, Fractured", player)
|
||||
|
||||
@@ -3,7 +3,9 @@ from . import RoR2TestBase
|
||||
|
||||
class MithrixGoalTest(RoR2TestBase):
|
||||
options = {
|
||||
"victory": "mithrix"
|
||||
"victory": "mithrix",
|
||||
"require_stages": "true",
|
||||
"progressive_stages": "false"
|
||||
}
|
||||
|
||||
def test_mithrix(self) -> None:
|
||||
|
||||
@@ -25,7 +25,7 @@ class SwordLocation(Choice):
|
||||
Randomized - The sword can be placed anywhere.
|
||||
Early - The sword will be placed in a location accessible from the start of
|
||||
the game.
|
||||
Unce assured - The sword will always be placed on Link's Uncle."""
|
||||
Uncle - The sword will always be placed on Link's Uncle."""
|
||||
display_name = "Sword Location"
|
||||
option_Randomized = 0
|
||||
option_Early = 1
|
||||
@@ -48,7 +48,7 @@ class MorphLocation(Choice):
|
||||
|
||||
class Goal(Choice):
|
||||
"""This option decides what goal is required to finish the randomizer.
|
||||
Defeat Ganon and Mother Brain - Find the required crystals and boss tokens kill both bosses.
|
||||
Defeat Ganon and Mother Brain - Find the required crystals and boss tokens to kill both bosses.
|
||||
Fast Ganon and Defeat Mother Brain - The hole to ganon is open without having to defeat Agahnim in
|
||||
Ganon's Tower and Ganon can be defeat as soon you have the required
|
||||
crystals to make Ganon vulnerable. For keysanity, this mode also removes
|
||||
|
||||
@@ -42,7 +42,7 @@ Weitere Informationen zum Randomizer findest du hier: [ReadMe](https://github.co
|
||||
|
||||
## Woher bekomme ich eine Konfigurationsdatei?
|
||||
|
||||
Die [Player Settings](https://archipelago.gg/games/Timespinner/player-settings) Seite auf der Website erlaubt dir,
|
||||
Die [Player Options](https://archipelago.gg/games/Timespinner/player-options) Seite auf der Website erlaubt dir,
|
||||
persönliche Einstellungen zu definieren und diese in eine Konfigurationsdatei zu exportieren
|
||||
|
||||
* Die Timespinner Randomizer Option "StinkyMaw" ist in Archipelago Seeds aktuell immer an
|
||||
|
||||
@@ -43,4 +43,4 @@ The Witness has a fully functional map tracker that supports auto-tracking.
|
||||
3. Click on the "AP" symbol at the top.
|
||||
4. Enter the AP address, slot name and password.
|
||||
|
||||
The rest should take care of itself! Items and checks will be marked automatically, and it even knows your settings - It will hide checks & adjust logic accordingly.
|
||||
The rest should take care of itself! Items and checks will be marked automatically, and it even knows your options - It will hide checks & adjust logic accordingly.
|
||||
|
||||
@@ -32,8 +32,7 @@ class YoshisIslandWeb(WebWorld):
|
||||
|
||||
setup_en = Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Yoshi's Island randomizer"
|
||||
"and connecting to an Archipelago server.",
|
||||
"A guide to setting up the Yoshi's Island randomizer and connecting to an Archipelago server.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Yoshi's Island
|
||||
|
||||
## Where is the settings page?
|
||||
## Where is the options page?
|
||||
|
||||
The [player options page for this game](../player-options) contains all the options you need to configure and export a config file.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en)
|
||||
|
||||
### Where do I get a config file?
|
||||
|
||||
The Player Options page on the website allows you to configure your personal settings and export a config file from
|
||||
The Player Options page on the website allows you to configure your personal options and export a config file from
|
||||
them.
|
||||
|
||||
### Verifying your config file
|
||||
|
||||
Reference in New Issue
Block a user